Index: releng/10.1/crypto/openssl/crypto/asn1/a_type.c =================================================================== --- releng/10.1/crypto/openssl/crypto/asn1/a_type.c (revision 280267) +++ releng/10.1/crypto/openssl/crypto/asn1/a_type.c (revision 280268) @@ -1,159 +1,162 @@ /* crypto/asn1/a_type.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include "cryptlib.h" #include #include int ASN1_TYPE_get(ASN1_TYPE *a) { if ((a->value.ptr != NULL) || (a->type == V_ASN1_NULL)) return(a->type); else return(0); } void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value) { if (a->value.ptr != NULL) { ASN1_TYPE **tmp_a = &a; ASN1_primitive_free((ASN1_VALUE **)tmp_a, NULL); } a->type=type; if (type == V_ASN1_BOOLEAN) a->value.boolean = value ? 0xff : 0; else a->value.ptr=value; } int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value) { if (!value || (type == V_ASN1_BOOLEAN)) { void *p = (void *)value; ASN1_TYPE_set(a, type, p); } else if (type == V_ASN1_OBJECT) { ASN1_OBJECT *odup; odup = OBJ_dup(value); if (!odup) return 0; ASN1_TYPE_set(a, type, odup); } else { ASN1_STRING *sdup; sdup = ASN1_STRING_dup(value); if (!sdup) return 0; ASN1_TYPE_set(a, type, sdup); } return 1; } IMPLEMENT_STACK_OF(ASN1_TYPE) IMPLEMENT_ASN1_SET_OF(ASN1_TYPE) /* Returns 0 if they are equal, != 0 otherwise. */ int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b) { int result = -1; if (!a || !b || a->type != b->type) return -1; switch (a->type) { case V_ASN1_OBJECT: result = OBJ_cmp(a->value.object, b->value.object); break; + case V_ASN1_BOOLEAN: + result = a->value.boolean - b->value.boolean; + break; case V_ASN1_NULL: result = 0; /* They do not have content. */ break; case V_ASN1_INTEGER: case V_ASN1_NEG_INTEGER: case V_ASN1_ENUMERATED: case V_ASN1_NEG_ENUMERATED: case V_ASN1_BIT_STRING: case V_ASN1_OCTET_STRING: case V_ASN1_SEQUENCE: case V_ASN1_SET: case V_ASN1_NUMERICSTRING: case V_ASN1_PRINTABLESTRING: case V_ASN1_T61STRING: case V_ASN1_VIDEOTEXSTRING: case V_ASN1_IA5STRING: case V_ASN1_UTCTIME: case V_ASN1_GENERALIZEDTIME: case V_ASN1_GRAPHICSTRING: case V_ASN1_VISIBLESTRING: case V_ASN1_GENERALSTRING: case V_ASN1_UNIVERSALSTRING: case V_ASN1_BMPSTRING: case V_ASN1_UTF8STRING: case V_ASN1_OTHER: default: result = ASN1_STRING_cmp((ASN1_STRING *) a->value.ptr, (ASN1_STRING *) b->value.ptr); break; } return result; } Index: releng/10.1/crypto/openssl/crypto/asn1/tasn_dec.c =================================================================== --- releng/10.1/crypto/openssl/crypto/asn1/tasn_dec.c (revision 280267) +++ releng/10.1/crypto/openssl/crypto/asn1/tasn_dec.c (revision 280268) @@ -1,1355 +1,1379 @@ /* tasn_dec.c */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2000. */ /* ==================================================================== * Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * licensing@OpenSSL.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ #include #include #include #include #include #include #include static int asn1_check_eoc(const unsigned char **in, long len); static int asn1_find_end(const unsigned char **in, long len, char inf); static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, char inf, int tag, int aclass, int depth); static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen); static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst, const unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx); static int asn1_template_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx); static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx); static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx); /* Table to convert tags to bit values, used for MSTRING type */ static const unsigned long tag2bit[32] = { 0, 0, 0, B_ASN1_BIT_STRING, /* tags 0 - 3 */ B_ASN1_OCTET_STRING, 0, 0, B_ASN1_UNKNOWN,/* tags 4- 7 */ B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN,/* tags 8-11 */ B_ASN1_UTF8STRING,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,/* tags 12-15 */ B_ASN1_SEQUENCE,0,B_ASN1_NUMERICSTRING,B_ASN1_PRINTABLESTRING, /* tags 16-19 */ B_ASN1_T61STRING,B_ASN1_VIDEOTEXSTRING,B_ASN1_IA5STRING, /* tags 20-22 */ B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME, /* tags 23-24 */ B_ASN1_GRAPHICSTRING,B_ASN1_ISO64STRING,B_ASN1_GENERALSTRING, /* tags 25-27 */ B_ASN1_UNIVERSALSTRING,B_ASN1_UNKNOWN,B_ASN1_BMPSTRING,B_ASN1_UNKNOWN, /* tags 28-31 */ }; unsigned long ASN1_tag2bit(int tag) { if ((tag < 0) || (tag > 30)) return 0; return tag2bit[tag]; } /* Macro to initialize and invalidate the cache */ #define asn1_tlc_clear(c) if (c) (c)->valid = 0 /* Version to avoid compiler warning about 'c' always non-NULL */ #define asn1_tlc_clear_nc(c) (c)->valid = 0 /* Decode an ASN1 item, this currently behaves just * like a standard 'd2i' function. 'in' points to * a buffer to read the data from, in future we will * have more advanced versions that can input data * a piece at a time and this will simply be a special * case. */ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it) - { +{ ASN1_TLC c; ASN1_VALUE *ptmpval = NULL; - if (!pval) - pval = &ptmpval; asn1_tlc_clear_nc(&c); - if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0) - return *pval; - return NULL; + if (pval && *pval && it->itype == ASN1_ITYPE_PRIMITIVE) + ptmpval = *pval; + if (ASN1_item_ex_d2i(&ptmpval, in, len, it, -1, 0, 0, &c) > 0) { + if (pval && it->itype != ASN1_ITYPE_PRIMITIVE) { + if (*pval) + ASN1_item_free(*pval, it); + *pval = ptmpval; + } + return ptmpval; } + return NULL; +} int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt) { ASN1_TLC c; asn1_tlc_clear_nc(&c); return asn1_template_ex_d2i(pval, in, len, tt, 0, &c); } /* Decode an item, taking care of IMPLICIT tagging, if any. * If 'opt' set and tag mismatch return -1 to handle OPTIONAL */ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx) { const ASN1_TEMPLATE *tt, *errtt = NULL; const ASN1_COMPAT_FUNCS *cf; const ASN1_EXTERN_FUNCS *ef; const ASN1_AUX *aux = it->funcs; ASN1_aux_cb *asn1_cb; const unsigned char *p = NULL, *q; unsigned char *wp=NULL; /* BIG FAT WARNING! BREAKS CONST WHERE USED */ unsigned char imphack = 0, oclass; char seq_eoc, seq_nolen, cst, isopt; long tmplen; int i; int otag; int ret = 0; ASN1_VALUE **pchptr, *ptmpval; if (!pval) return 0; if (aux && aux->asn1_cb) asn1_cb = aux->asn1_cb; else asn1_cb = 0; switch(it->itype) { case ASN1_ITYPE_PRIMITIVE: if (it->templates) { /* tagging or OPTIONAL is currently illegal on an item * template because the flags can't get passed down. * In practice this isn't a problem: we include the * relevant flags from the item template in the * template itself. */ if ((tag != -1) || opt) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE); goto err; } return asn1_template_ex_d2i(pval, in, len, it->templates, opt, ctx); } return asn1_d2i_ex_primitive(pval, in, len, it, tag, aclass, opt, ctx); break; case ASN1_ITYPE_MSTRING: p = *in; /* Just read in tag and class */ ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, &p, len, -1, 0, 1, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } /* Must be UNIVERSAL class */ if (oclass != V_ASN1_UNIVERSAL) { /* If OPTIONAL, assume this is OK */ if (opt) return -1; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_NOT_UNIVERSAL); goto err; } /* Check tag matches bit map */ if (!(ASN1_tag2bit(otag) & it->utype)) { /* If OPTIONAL, assume this is OK */ if (opt) return -1; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_WRONG_TAG); goto err; } return asn1_d2i_ex_primitive(pval, in, len, it, otag, 0, 0, ctx); case ASN1_ITYPE_EXTERN: /* Use new style d2i */ ef = it->funcs; return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx); case ASN1_ITYPE_COMPAT: /* we must resort to old style evil hackery */ cf = it->funcs; /* If OPTIONAL see if it is there */ if (opt) { int exptag; p = *in; if (tag == -1) exptag = it->utype; else exptag = tag; /* Don't care about anything other than presence * of expected tag */ ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL, &p, len, exptag, aclass, 1, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } if (ret == -1) return -1; } /* This is the old style evil hack IMPLICIT handling: * since the underlying code is expecting a tag and * class other than the one present we change the * buffer temporarily then change it back afterwards. * This doesn't and never did work for tags > 30. * * Yes this is *horrible* but it is only needed for * old style d2i which will hopefully not be around * for much longer. * FIXME: should copy the buffer then modify it so * the input buffer can be const: we should *always* * copy because the old style d2i might modify the * buffer. */ if (tag != -1) { wp = *(unsigned char **)in; imphack = *wp; if (p == NULL) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } *wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED) | it->utype); } ptmpval = cf->asn1_d2i(pval, in, len); if (tag != -1) *wp = imphack; if (ptmpval) return 1; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; case ASN1_ITYPE_CHOICE: if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) goto auxerr; - /* Allocate structure */ - if (!*pval && !ASN1_item_ex_new(pval, it)) - { + if (*pval) { + /* Free up and zero CHOICE value if initialised */ + i = asn1_get_choice_selector(pval, it); + if ((i >= 0) && (i < it->tcount)) { + tt = it->templates + i; + pchptr = asn1_get_field_ptr(pval, tt); + ASN1_template_free(pchptr, tt); + asn1_set_choice_selector(pval, -1, it); + } + } else if (!ASN1_item_ex_new(pval, it)) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; - } + } /* CHOICE type, try each possibility in turn */ p = *in; for (i = 0, tt=it->templates; i < it->tcount; i++, tt++) { pchptr = asn1_get_field_ptr(pval, tt); /* We mark field as OPTIONAL so its absence * can be recognised. */ ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx); /* If field not present, try the next one */ if (ret == -1) continue; /* If positive return, read OK, break loop */ if (ret > 0) break; /* Otherwise must be an ASN1 parsing error */ errtt = tt; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } /* Did we fall off the end without reading anything? */ if (i == it->tcount) { /* If OPTIONAL, this is OK */ if (opt) { /* Free and zero it */ ASN1_item_ex_free(pval, it); return -1; } ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_NO_MATCHING_CHOICE_TYPE); goto err; } asn1_set_choice_selector(pval, i, it); *in = p; if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) goto auxerr; return 1; case ASN1_ITYPE_NDEF_SEQUENCE: case ASN1_ITYPE_SEQUENCE: p = *in; tmplen = len; /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ if (tag == -1) { tag = V_ASN1_SEQUENCE; aclass = V_ASN1_UNIVERSAL; } /* Get SEQUENCE length and update len, p */ ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst, &p, len, tag, aclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if (ret == -1) return -1; if (aux && (aux->flags & ASN1_AFLG_BROKEN)) { len = tmplen - (p - *in); seq_nolen = 1; } /* If indefinite we don't do a length check */ else seq_nolen = seq_eoc; if (!cst) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_NOT_CONSTRUCTED); goto err; } if (!*pval && !ASN1_item_ex_new(pval, it)) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) goto auxerr; + + /* Free up and zero any ADB found */ + for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { + if (tt->flags & ASN1_TFLG_ADB_MASK) { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + pseqval = asn1_get_field_ptr(pval, seqtt); + ASN1_template_free(pseqval, seqtt); + } + } /* Get each field entry */ for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { const ASN1_TEMPLATE *seqtt; ASN1_VALUE **pseqval; seqtt = asn1_do_adb(pval, tt, 1); if (!seqtt) goto err; pseqval = asn1_get_field_ptr(pval, seqtt); /* Have we ran out of data? */ if (!len) break; q = p; if (asn1_check_eoc(&p, len)) { if (!seq_eoc) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_UNEXPECTED_EOC); goto err; } len -= p - q; seq_eoc = 0; q = p; break; } /* This determines the OPTIONAL flag value. The field * cannot be omitted if it is the last of a SEQUENCE * and there is still data to be read. This isn't * strictly necessary but it increases efficiency in * some cases. */ if (i == (it->tcount - 1)) isopt = 0; else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL); /* attempt to read in field, allowing each to be * OPTIONAL */ ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx); if (!ret) { errtt = seqtt; goto err; } else if (ret == -1) { /* OPTIONAL component absent. * Free and zero the field. */ ASN1_template_free(pseqval, seqtt); continue; } /* Update length */ len -= p - q; } /* Check for EOC if expecting one */ if (seq_eoc && !asn1_check_eoc(&p, len)) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MISSING_EOC); goto err; } /* Check all data read */ if (!seq_nolen && len) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_LENGTH_MISMATCH); goto err; } /* If we get here we've got no more data in the SEQUENCE, * however we may not have read all fields so check all * remaining are OPTIONAL and clear any that are. */ for (; i < it->tcount; tt++, i++) { const ASN1_TEMPLATE *seqtt; seqtt = asn1_do_adb(pval, tt, 1); if (!seqtt) goto err; if (seqtt->flags & ASN1_TFLG_OPTIONAL) { ASN1_VALUE **pseqval; pseqval = asn1_get_field_ptr(pval, seqtt); ASN1_template_free(pseqval, seqtt); } else { errtt = seqtt; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_FIELD_MISSING); goto err; } } /* Save encoding */ if (!asn1_enc_save(pval, *in, p - *in, it)) goto auxerr; *in = p; if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) goto auxerr; return 1; default: return 0; } auxerr: ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_AUX_ERROR); err: ASN1_item_ex_free(pval, it); if (errtt) ERR_add_error_data(4, "Field=", errtt->field_name, ", Type=", it->sname); else ERR_add_error_data(2, "Type=", it->sname); return 0; } /* Templates are handled with two separate functions. * One handles any EXPLICIT tag and the other handles the rest. */ static int asn1_template_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx) { int flags, aclass; int ret; long len; const unsigned char *p, *q; char exp_eoc; if (!val) return 0; flags = tt->flags; aclass = flags & ASN1_TFLG_TAG_CLASS; p = *in; /* Check if EXPLICIT tag expected */ if (flags & ASN1_TFLG_EXPTAG) { char cst; /* Need to work out amount of data available to the inner * content and where it starts: so read in EXPLICIT header to * get the info. */ ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst, &p, inlen, tt->tag, aclass, opt, ctx); q = p; if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR); return 0; } else if (ret == -1) return -1; if (!cst) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED); return 0; } /* We've found the field so it can't be OPTIONAL now */ ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR); return 0; } /* We read the field in OK so update length */ len -= p - q; if (exp_eoc) { /* If NDEF we must have an EOC here */ if (!asn1_check_eoc(&p, len)) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_MISSING_EOC); goto err; } } else { /* Otherwise we must hit the EXPLICIT tag end or its * an error */ if (len) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_EXPLICIT_LENGTH_MISMATCH); goto err; } } } else return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx); *in = p; return 1; err: ASN1_template_free(val, tt); return 0; } static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx) { int flags, aclass; int ret; const unsigned char *p, *q; if (!val) return 0; flags = tt->flags; aclass = flags & ASN1_TFLG_TAG_CLASS; p = *in; q = p; if (flags & ASN1_TFLG_SK_MASK) { /* SET OF, SEQUENCE OF */ int sktag, skaclass; char sk_eoc; /* First work out expected inner tag value */ if (flags & ASN1_TFLG_IMPTAG) { sktag = tt->tag; skaclass = aclass; } else { skaclass = V_ASN1_UNIVERSAL; if (flags & ASN1_TFLG_SET_OF) sktag = V_ASN1_SET; else sktag = V_ASN1_SEQUENCE; } /* Get the tag */ ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL, &p, len, sktag, skaclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); return 0; } else if (ret == -1) return -1; if (!*val) *val = (ASN1_VALUE *)sk_new_null(); else { /* We've got a valid STACK: free up any items present */ STACK_OF(ASN1_VALUE) *sktmp = (STACK_OF(ASN1_VALUE) *)*val; ASN1_VALUE *vtmp; while(sk_ASN1_VALUE_num(sktmp) > 0) { vtmp = sk_ASN1_VALUE_pop(sktmp); ASN1_item_ex_free(&vtmp, ASN1_ITEM_ptr(tt->item)); } } if (!*val) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_MALLOC_FAILURE); goto err; } /* Read as many items as we can */ while(len > 0) { ASN1_VALUE *skfield; q = p; /* See if EOC found */ if (asn1_check_eoc(&p, len)) { if (!sk_eoc) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1_R_UNEXPECTED_EOC); goto err; } len -= p - q; sk_eoc = 0; break; } skfield = NULL; if (!ASN1_item_ex_d2i(&skfield, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } len -= p - q; if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, skfield)) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_MALLOC_FAILURE); goto err; } } if (sk_eoc) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1_R_MISSING_EOC); goto err; } } else if (flags & ASN1_TFLG_IMPTAG) { /* IMPLICIT tagging */ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if (ret == -1) return -1; } else { /* Nothing special */ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if (ret == -1) return -1; } *in = p; return 1; err: ASN1_template_free(val, tt); return 0; } static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx) { int ret = 0, utype; long plen; char cst, inf, free_cont = 0; const unsigned char *p; BUF_MEM buf; const unsigned char *cont = NULL; long len; if (!pval) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_NULL); return 0; /* Should never happen */ } if (it->itype == ASN1_ITYPE_MSTRING) { utype = tag; tag = -1; } else utype = it->utype; if (utype == V_ASN1_ANY) { /* If type is ANY need to figure out type from tag */ unsigned char oclass; if (tag >= 0) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_TAGGED_ANY); return 0; } if (opt) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_OPTIONAL_ANY); return 0; } p = *in; ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL, &p, inlen, -1, 0, 0, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR); return 0; } if (oclass != V_ASN1_UNIVERSAL) utype = V_ASN1_OTHER; } if (tag == -1) { tag = utype; aclass = V_ASN1_UNIVERSAL; } p = *in; /* Check header */ ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst, &p, inlen, tag, aclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR); return 0; } else if (ret == -1) return -1; ret = 0; /* SEQUENCE, SET and "OTHER" are left in encoded form */ if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) { /* Clear context cache for type OTHER because the auto clear * when we have a exact match wont work */ if (utype == V_ASN1_OTHER) { asn1_tlc_clear(ctx); } /* SEQUENCE and SET must be constructed */ else if (!cst) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_TYPE_NOT_CONSTRUCTED); return 0; } cont = *in; /* If indefinite length constructed find the real end */ if (inf) { if (!asn1_find_end(&p, plen, inf)) goto err; len = p - cont; } else { len = p - cont + plen; p += plen; buf.data = NULL; } } else if (cst) { if (utype == V_ASN1_NULL || utype == V_ASN1_BOOLEAN || utype == V_ASN1_OBJECT || utype == V_ASN1_INTEGER || utype == V_ASN1_ENUMERATED) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_TYPE_NOT_PRIMITIVE); return 0; } buf.length = 0; buf.max = 0; buf.data = NULL; /* Should really check the internal tags are correct but * some things may get this wrong. The relevant specs * say that constructed string types should be OCTET STRINGs * internally irrespective of the type. So instead just check * for UNIVERSAL class and ignore the tag. */ if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) { free_cont = 1; goto err; } len = buf.length; /* Append a final null to string */ if (!BUF_MEM_grow_clean(&buf, len + 1)) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE); return 0; } buf.data[len] = 0; cont = (const unsigned char *)buf.data; free_cont = 1; } else { cont = p; len = plen; p += plen; } /* We now have content length and type: translate into a structure */ if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it)) goto err; *in = p; ret = 1; err: if (free_cont && buf.data) OPENSSL_free(buf.data); return ret; } /* Translate ASN1 content octets into a structure */ int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it) { ASN1_VALUE **opval = NULL; ASN1_STRING *stmp; ASN1_TYPE *typ = NULL; int ret = 0; const ASN1_PRIMITIVE_FUNCS *pf; ASN1_INTEGER **tint; pf = it->funcs; if (pf && pf->prim_c2i) return pf->prim_c2i(pval, cont, len, utype, free_cont, it); /* If ANY type clear type and set pointer to internal value */ if (it->utype == V_ASN1_ANY) { if (!*pval) { typ = ASN1_TYPE_new(); if (typ == NULL) goto err; *pval = (ASN1_VALUE *)typ; } else typ = (ASN1_TYPE *)*pval; if (utype != typ->type) ASN1_TYPE_set(typ, utype, NULL); opval = pval; pval = &typ->value.asn1_value; } switch(utype) { case V_ASN1_OBJECT: if (!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len)) goto err; break; case V_ASN1_NULL: if (len) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_NULL_IS_WRONG_LENGTH); goto err; } *pval = (ASN1_VALUE *)1; break; case V_ASN1_BOOLEAN: if (len != 1) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_BOOLEAN_IS_WRONG_LENGTH); goto err; } else { ASN1_BOOLEAN *tbool; tbool = (ASN1_BOOLEAN *)pval; *tbool = *cont; } break; case V_ASN1_BIT_STRING: if (!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len)) goto err; break; case V_ASN1_INTEGER: case V_ASN1_NEG_INTEGER: case V_ASN1_ENUMERATED: case V_ASN1_NEG_ENUMERATED: tint = (ASN1_INTEGER **)pval; if (!c2i_ASN1_INTEGER(tint, &cont, len)) goto err; /* Fixup type to match the expected form */ (*tint)->type = utype | ((*tint)->type & V_ASN1_NEG); break; case V_ASN1_OCTET_STRING: case V_ASN1_NUMERICSTRING: case V_ASN1_PRINTABLESTRING: case V_ASN1_T61STRING: case V_ASN1_VIDEOTEXSTRING: case V_ASN1_IA5STRING: case V_ASN1_UTCTIME: case V_ASN1_GENERALIZEDTIME: case V_ASN1_GRAPHICSTRING: case V_ASN1_VISIBLESTRING: case V_ASN1_GENERALSTRING: case V_ASN1_UNIVERSALSTRING: case V_ASN1_BMPSTRING: case V_ASN1_UTF8STRING: case V_ASN1_OTHER: case V_ASN1_SET: case V_ASN1_SEQUENCE: default: if (utype == V_ASN1_BMPSTRING && (len & 1)) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_BMPSTRING_IS_WRONG_LENGTH); goto err; } if (utype == V_ASN1_UNIVERSALSTRING && (len & 3)) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH); goto err; } /* All based on ASN1_STRING and handled the same */ if (!*pval) { stmp = ASN1_STRING_type_new(utype); if (!stmp) { ASN1err(ASN1_F_ASN1_EX_C2I, ERR_R_MALLOC_FAILURE); goto err; } *pval = (ASN1_VALUE *)stmp; } else { stmp = (ASN1_STRING *)*pval; stmp->type = utype; } /* If we've already allocated a buffer use it */ if (*free_cont) { if (stmp->data) OPENSSL_free(stmp->data); stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */ stmp->length = len; *free_cont = 0; } else { if (!ASN1_STRING_set(stmp, cont, len)) { ASN1err(ASN1_F_ASN1_EX_C2I, ERR_R_MALLOC_FAILURE); ASN1_STRING_free(stmp); *pval = NULL; goto err; } } break; } /* If ASN1_ANY and NULL type fix up value */ if (typ && (utype == V_ASN1_NULL)) typ->value.ptr = NULL; ret = 1; err: if (!ret) { ASN1_TYPE_free(typ); if (opval) *opval = NULL; } return ret; } /* This function finds the end of an ASN1 structure when passed its maximum * length, whether it is indefinite length and a pointer to the content. * This is more efficient than calling asn1_collect because it does not * recurse on each indefinite length header. */ static int asn1_find_end(const unsigned char **in, long len, char inf) { int expected_eoc; long plen; const unsigned char *p = *in, *q; /* If not indefinite length constructed just add length */ if (inf == 0) { *in += len; return 1; } expected_eoc = 1; /* Indefinite length constructed form. Find the end when enough EOCs * are found. If more indefinite length constructed headers * are encountered increment the expected eoc count otherwise just * skip to the end of the data. */ while (len > 0) { if(asn1_check_eoc(&p, len)) { expected_eoc--; if (expected_eoc == 0) break; len -= 2; continue; } q = p; /* Just read in a header: only care about the length */ if(!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len, -1, 0, 0, NULL)) { ASN1err(ASN1_F_ASN1_FIND_END, ERR_R_NESTED_ASN1_ERROR); return 0; } if (inf) expected_eoc++; else p += plen; len -= p - q; } if (expected_eoc) { ASN1err(ASN1_F_ASN1_FIND_END, ASN1_R_MISSING_EOC); return 0; } *in = p; return 1; } /* This function collects the asn1 data from a constructred string * type into a buffer. The values of 'in' and 'len' should refer * to the contents of the constructed type and 'inf' should be set * if it is indefinite length. */ #ifndef ASN1_MAX_STRING_NEST /* This determines how many levels of recursion are permitted in ASN1 * string types. If it is not limited stack overflows can occur. If set * to zero no recursion is allowed at all. Although zero should be adequate * examples exist that require a value of 1. So 5 should be more than enough. */ #define ASN1_MAX_STRING_NEST 5 #endif static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, char inf, int tag, int aclass, int depth) { const unsigned char *p, *q; long plen; char cst, ininf; p = *in; inf &= 1; /* If no buffer and not indefinite length constructed just pass over * the encoded data */ if (!buf && !inf) { *in += len; return 1; } while(len > 0) { q = p; /* Check for EOC */ if (asn1_check_eoc(&p, len)) { /* EOC is illegal outside indefinite length * constructed form */ if (!inf) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_UNEXPECTED_EOC); return 0; } inf = 0; break; } if (!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p, len, tag, aclass, 0, NULL)) { ASN1err(ASN1_F_ASN1_COLLECT, ERR_R_NESTED_ASN1_ERROR); return 0; } /* If indefinite length constructed update max length */ if (cst) { if (depth >= ASN1_MAX_STRING_NEST) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_NESTED_ASN1_STRING); return 0; } if (!asn1_collect(buf, &p, plen, ininf, tag, aclass, depth + 1)) return 0; } else if (plen && !collect_data(buf, &p, plen)) return 0; len -= p - q; } if (inf) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_MISSING_EOC); return 0; } *in = p; return 1; } static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen) { int len; if (buf) { len = buf->length; if (!BUF_MEM_grow_clean(buf, len + plen)) { ASN1err(ASN1_F_COLLECT_DATA, ERR_R_MALLOC_FAILURE); return 0; } memcpy(buf->data + len, *p, plen); } *p += plen; return 1; } /* Check for ASN1 EOC and swallow it if found */ static int asn1_check_eoc(const unsigned char **in, long len) { const unsigned char *p; if (len < 2) return 0; p = *in; if (!p[0] && !p[1]) { *in += 2; return 1; } return 0; } /* Check an ASN1 tag and length: a bit like ASN1_get_object * but it sets the length for indefinite length constructed * form, we don't know the exact length but we can set an * upper bound to the amount of data available minus the * header length just read. */ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst, const unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx) { int i; int ptag, pclass; long plen; const unsigned char *p, *q; p = *in; q = p; if (ctx && ctx->valid) { i = ctx->ret; plen = ctx->plen; pclass = ctx->pclass; ptag = ctx->ptag; p += ctx->hdrlen; } else { i = ASN1_get_object(&p, &plen, &ptag, &pclass, len); if (ctx) { ctx->ret = i; ctx->plen = plen; ctx->pclass = pclass; ctx->ptag = ptag; ctx->hdrlen = p - q; ctx->valid = 1; /* If definite length, and no error, length + * header can't exceed total amount of data available. */ if (!(i & 0x81) && ((plen + ctx->hdrlen) > len)) { ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_TOO_LONG); asn1_tlc_clear(ctx); return 0; } } } if (i & 0x80) { ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_BAD_OBJECT_HEADER); asn1_tlc_clear(ctx); return 0; } if (exptag >= 0) { if ((exptag != ptag) || (expclass != pclass)) { /* If type is OPTIONAL, not an error: * indicate missing type. */ if (opt) return -1; asn1_tlc_clear(ctx); ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG); return 0; } /* We have a tag and class match: * assume we are going to do something with it */ asn1_tlc_clear(ctx); } if (i & 1) plen = len - (p - q); if (inf) *inf = i & 1; if (cst) *cst = i & V_ASN1_CONSTRUCTED; if (olen) *olen = plen; if (oclass) *oclass = pclass; if (otag) *otag = ptag; *in = p; return 1; } Index: releng/10.1/crypto/openssl/crypto/pkcs7/pk7_doit.c =================================================================== --- releng/10.1/crypto/openssl/crypto/pkcs7/pk7_doit.c (revision 280267) +++ releng/10.1/crypto/openssl/crypto/pkcs7/pk7_doit.c (revision 280268) @@ -1,1305 +1,1362 @@ /* crypto/pkcs7/pk7_doit.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include "cryptlib.h" #include #include #include #include #include static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, void *value); static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid); static int PKCS7_type_is_other(PKCS7* p7) { int isOther=1; int nid=OBJ_obj2nid(p7->type); switch( nid ) { case NID_pkcs7_data: case NID_pkcs7_signed: case NID_pkcs7_enveloped: case NID_pkcs7_signedAndEnveloped: case NID_pkcs7_digest: case NID_pkcs7_encrypted: isOther=0; break; default: isOther=1; } return isOther; } static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7) { if ( PKCS7_type_is_data(p7)) return p7->d.data; if ( PKCS7_type_is_other(p7) && p7->d.other && (p7->d.other->type == V_ASN1_OCTET_STRING)) return p7->d.other->value.octet_string; return NULL; } static int PKCS7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) { BIO *btmp; const EVP_MD *md; if ((btmp=BIO_new(BIO_f_md())) == NULL) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB); goto err; } md=EVP_get_digestbyobj(alg->algorithm); if (md == NULL) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,PKCS7_R_UNKNOWN_DIGEST_TYPE); goto err; } BIO_set_md(btmp,md); if (*pbio == NULL) *pbio=btmp; else if (!BIO_push(*pbio,btmp)) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB); goto err; } btmp=NULL; return 1; err: if (btmp) BIO_free(btmp); return 0; } static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *key, int keylen) { EVP_PKEY_CTX *pctx = NULL; EVP_PKEY *pkey = NULL; unsigned char *ek = NULL; int ret = 0; size_t eklen; pkey = X509_get_pubkey(ri->cert); if (!pkey) return 0; pctx = EVP_PKEY_CTX_new(pkey, NULL); if (!pctx) return 0; if (EVP_PKEY_encrypt_init(pctx) <= 0) goto err; if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT, EVP_PKEY_CTRL_PKCS7_ENCRYPT, 0, ri) <= 0) { PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, PKCS7_R_CTRL_ERROR); goto err; } if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0) goto err; ek = OPENSSL_malloc(eklen); if (ek == NULL) { PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, ERR_R_MALLOC_FAILURE); goto err; } if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0) goto err; ASN1_STRING_set0(ri->enc_key, ek, eklen); ek = NULL; ret = 1; err: if (pkey) EVP_PKEY_free(pkey); if (pctx) EVP_PKEY_CTX_free(pctx); if (ek) OPENSSL_free(ek); return ret; } static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen, PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey) { EVP_PKEY_CTX *pctx = NULL; unsigned char *ek = NULL; size_t eklen; int ret = -1; pctx = EVP_PKEY_CTX_new(pkey, NULL); if (!pctx) return -1; if (EVP_PKEY_decrypt_init(pctx) <= 0) goto err; if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT, EVP_PKEY_CTRL_PKCS7_DECRYPT, 0, ri) <= 0) { PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, PKCS7_R_CTRL_ERROR); goto err; } if (EVP_PKEY_decrypt(pctx, NULL, &eklen, ri->enc_key->data, ri->enc_key->length) <= 0) goto err; ek = OPENSSL_malloc(eklen); if (ek == NULL) { PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_MALLOC_FAILURE); goto err; } if (EVP_PKEY_decrypt(pctx, ek, &eklen, ri->enc_key->data, ri->enc_key->length) <= 0) { ret = 0; PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB); goto err; } ret = 1; if (*pek) { OPENSSL_cleanse(*pek, *peklen); OPENSSL_free(*pek); } *pek = ek; *peklen = eklen; err: if (pctx) EVP_PKEY_CTX_free(pctx); if (!ret && ek) OPENSSL_free(ek); return ret; } BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { int i; BIO *out=NULL,*btmp=NULL; X509_ALGOR *xa = NULL; const EVP_CIPHER *evp_cipher=NULL; STACK_OF(X509_ALGOR) *md_sk=NULL; STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; X509_ALGOR *xalg=NULL; PKCS7_RECIP_INFO *ri=NULL; ASN1_OCTET_STRING *os=NULL; + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_INVALID_NULL_POINTER); + return NULL; + } + /* + * The content field in the PKCS7 ContentInfo is optional, but that really + * only applies to inner content (precisely, detached signatures). + * + * When reading content, missing outer content is therefore treated as an + * error. + * + * When creating content, PKCS7_content_new() must be called before + * calling this method, so a NULL p7->d is always an error. + */ + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_NO_CONTENT); + return NULL; + } + i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signed: md_sk=p7->d.sign->md_algs; os = PKCS7_get_octet_string(p7->d.sign->contents); break; case NID_pkcs7_signedAndEnveloped: rsk=p7->d.signed_and_enveloped->recipientinfo; md_sk=p7->d.signed_and_enveloped->md_algs; xalg=p7->d.signed_and_enveloped->enc_data->algorithm; evp_cipher=p7->d.signed_and_enveloped->enc_data->cipher; if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED); goto err; } break; case NID_pkcs7_enveloped: rsk=p7->d.enveloped->recipientinfo; xalg=p7->d.enveloped->enc_data->algorithm; evp_cipher=p7->d.enveloped->enc_data->cipher; if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED); goto err; } break; case NID_pkcs7_digest: xa = p7->d.digest->md; os = PKCS7_get_octet_string(p7->d.digest->contents); break; case NID_pkcs7_data: break; default: PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } for (i=0; ialgorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher)); if (ivlen > 0) if (RAND_pseudo_bytes(iv,ivlen) <= 0) goto err; if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1)<=0) goto err; if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0) goto err; if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0) goto err; if (ivlen > 0) { if (xalg->parameter == NULL) { xalg->parameter = ASN1_TYPE_new(); if (xalg->parameter == NULL) goto err; } if(EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0) goto err; } /* Lets do the pub key stuff :-) */ for (i=0; ilength > 0) bio = BIO_new_mem_buf(os->data, os->length); if(bio == NULL) { bio=BIO_new(BIO_s_mem()); if (bio == NULL) goto err; BIO_set_mem_eof_return(bio,0); } } if (out) BIO_push(out,bio); else out = bio; bio=NULL; if (0) { err: if (out != NULL) BIO_free_all(out); if (btmp != NULL) BIO_free_all(btmp); out=NULL; } return(out); } static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert) { int ret; ret = X509_NAME_cmp(ri->issuer_and_serial->issuer, pcert->cert_info->issuer); if (ret) return ret; return M_ASN1_INTEGER_cmp(pcert->cert_info->serialNumber, ri->issuer_and_serial->serial); } /* int */ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) { int i,j; BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL; X509_ALGOR *xa; ASN1_OCTET_STRING *data_body=NULL; const EVP_MD *evp_md; const EVP_CIPHER *evp_cipher=NULL; EVP_CIPHER_CTX *evp_ctx=NULL; X509_ALGOR *enc_alg=NULL; STACK_OF(X509_ALGOR) *md_sk=NULL; STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; PKCS7_RECIP_INFO *ri=NULL; unsigned char *ek = NULL, *tkey = NULL; int eklen = 0, tkeylen = 0; + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER); + return NULL; + } + + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); + return NULL; + } + i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signed: data_body=PKCS7_get_octet_string(p7->d.sign->contents); if (!PKCS7_is_detached(p7) && data_body == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_INVALID_SIGNED_DATA_TYPE); goto err; } md_sk=p7->d.sign->md_algs; break; case NID_pkcs7_signedAndEnveloped: rsk=p7->d.signed_and_enveloped->recipientinfo; md_sk=p7->d.signed_and_enveloped->md_algs; data_body=p7->d.signed_and_enveloped->enc_data->enc_data; enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm; evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } break; case NID_pkcs7_enveloped: rsk=p7->d.enveloped->recipientinfo; enc_alg=p7->d.enveloped->enc_data->algorithm; data_body=p7->d.enveloped->enc_data->enc_data; evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } break; default: PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } /* We will be checking the signature */ if (md_sk != NULL) { for (i=0; ialgorithm); evp_md=EVP_get_digestbynid(j); if (evp_md == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE); goto err; } BIO_set_md(btmp,evp_md); if (out == NULL) out=btmp; else BIO_push(out,btmp); btmp=NULL; } } if (evp_cipher != NULL) { #if 0 unsigned char key[EVP_MAX_KEY_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char *p; int keylen,ivlen; int max; X509_OBJECT ret; #endif if ((etmp=BIO_new(BIO_f_cipher())) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); goto err; } /* It was encrypted, we need to decrypt the secret key * with the private key */ /* Find the recipientInfo which matches the passed certificate * (if any) */ if (pcert) { for (i=0; iparameter) < 0) goto err; /* Generate random key as MMA defence */ tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx); tkey = OPENSSL_malloc(tkeylen); if (!tkey) goto err; if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0) goto err; if (ek == NULL) { ek = tkey; eklen = tkeylen; tkey = NULL; } if (eklen != EVP_CIPHER_CTX_key_length(evp_ctx)) { /* Some S/MIME clients don't use the same key * and effective key length. The key length is * determined by the size of the decrypted RSA key. */ if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen)) { /* Use random key as MMA defence */ OPENSSL_cleanse(ek, eklen); OPENSSL_free(ek); ek = tkey; eklen = tkeylen; tkey = NULL; } } /* Clear errors so we don't leak information useful in MMA */ ERR_clear_error(); if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,ek,NULL,0) <= 0) goto err; if (ek) { OPENSSL_cleanse(ek,eklen); OPENSSL_free(ek); ek = NULL; } if (tkey) { OPENSSL_cleanse(tkey,tkeylen); OPENSSL_free(tkey); tkey = NULL; } if (out == NULL) out=etmp; else BIO_push(out,etmp); etmp=NULL; } #if 1 if (PKCS7_is_detached(p7) || (in_bio != NULL)) { bio=in_bio; } else { #if 0 bio=BIO_new(BIO_s_mem()); /* We need to set this so that when we have read all * the data, the encrypt BIO, if present, will read * EOF and encode the last few bytes */ BIO_set_mem_eof_return(bio,0); if (data_body->length > 0) BIO_write(bio,(char *)data_body->data,data_body->length); #else if (data_body->length > 0) bio = BIO_new_mem_buf(data_body->data,data_body->length); else { bio=BIO_new(BIO_s_mem()); BIO_set_mem_eof_return(bio,0); } if (bio == NULL) goto err; #endif } BIO_push(out,bio); bio=NULL; #endif if (0) { err: if (ek) { OPENSSL_cleanse(ek,eklen); OPENSSL_free(ek); } if (tkey) { OPENSSL_cleanse(tkey,tkeylen); OPENSSL_free(tkey); } if (out != NULL) BIO_free_all(out); if (btmp != NULL) BIO_free_all(btmp); if (etmp != NULL) BIO_free_all(etmp); if (bio != NULL) BIO_free_all(bio); out=NULL; } return(out); } static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { for (;;) { bio=BIO_find_type(bio,BIO_TYPE_MD); if (bio == NULL) { PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); return NULL; } BIO_get_md_ctx(bio,pmd); if (*pmd == NULL) { PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,ERR_R_INTERNAL_ERROR); return NULL; } if (EVP_MD_CTX_type(*pmd) == nid) return bio; bio=BIO_next(bio); } return NULL; } static int do_pkcs7_signed_attrib(PKCS7_SIGNER_INFO *si, EVP_MD_CTX *mctx) { unsigned char md_data[EVP_MAX_MD_SIZE]; unsigned int md_len; /* Add signing time if not already present */ if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime)) { if (!PKCS7_add0_attrib_signing_time(si, NULL)) { PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE); return 0; } } /* Add digest */ if (!EVP_DigestFinal_ex(mctx, md_data,&md_len)) { PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_EVP_LIB); return 0; } if (!PKCS7_add1_attrib_digest(si, md_data, md_len)) { PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE); return 0; } /* Now sign the attributes */ if (!PKCS7_SIGNER_INFO_sign(si)) return 0; return 1; } int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { int ret=0; int i,j; BIO *btmp; PKCS7_SIGNER_INFO *si; EVP_MD_CTX *mdc,ctx_tmp; STACK_OF(X509_ATTRIBUTE) *sk; STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL; ASN1_OCTET_STRING *os=NULL; + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_INVALID_NULL_POINTER); + return 0; + } + + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_NO_CONTENT); + return 0; + } + EVP_MD_CTX_init(&ctx_tmp); i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_data: os = p7->d.data; break; case NID_pkcs7_signedAndEnveloped: /* XXXXXXXXXXXXXXXX */ si_sk=p7->d.signed_and_enveloped->signer_info; os = p7->d.signed_and_enveloped->enc_data->enc_data; if (!os) { os=M_ASN1_OCTET_STRING_new(); if (!os) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE); goto err; } p7->d.signed_and_enveloped->enc_data->enc_data=os; } break; case NID_pkcs7_enveloped: /* XXXXXXXXXXXXXXXX */ os = p7->d.enveloped->enc_data->enc_data; if (!os) { os=M_ASN1_OCTET_STRING_new(); if (!os) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE); goto err; } p7->d.enveloped->enc_data->enc_data=os; } break; case NID_pkcs7_signed: si_sk=p7->d.sign->signer_info; os=PKCS7_get_octet_string(p7->d.sign->contents); /* If detached data then the content is excluded */ if(PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) { M_ASN1_OCTET_STRING_free(os); + os = NULL; p7->d.sign->contents->d.data = NULL; } break; case NID_pkcs7_digest: os=PKCS7_get_octet_string(p7->d.digest->contents); /* If detached data then the content is excluded */ if(PKCS7_type_is_data(p7->d.digest->contents) && p7->detached) { M_ASN1_OCTET_STRING_free(os); + os = NULL; p7->d.digest->contents->d.data = NULL; } break; default: PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } if (si_sk != NULL) { for (i=0; ipkey == NULL) continue; j = OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; btmp = PKCS7_find_digest(&mdc, btmp, j); if (btmp == NULL) goto err; /* We now have the EVP_MD_CTX, lets do the * signing. */ if (!EVP_MD_CTX_copy_ex(&ctx_tmp,mdc)) goto err; sk=si->auth_attr; /* If there are attributes, we add the digest * attribute and only sign the attributes */ if (sk_X509_ATTRIBUTE_num(sk) > 0) { if (!do_pkcs7_signed_attrib(si, &ctx_tmp)) goto err; } else { unsigned char *abuf = NULL; unsigned int abuflen; abuflen = EVP_PKEY_size(si->pkey); abuf = OPENSSL_malloc(abuflen); if (!abuf) goto err; if (!EVP_SignFinal(&ctx_tmp, abuf, &abuflen, si->pkey)) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_EVP_LIB); goto err; } ASN1_STRING_set0(si->enc_digest, abuf, abuflen); } } } - else if (i == NID_pkcs7_digest) - { + else if (i == NID_pkcs7_digest) { unsigned char md_data[EVP_MAX_MD_SIZE]; unsigned int md_len; if (!PKCS7_find_digest(&mdc, bio, OBJ_obj2nid(p7->d.digest->md->algorithm))) goto err; if (!EVP_DigestFinal_ex(mdc,md_data,&md_len)) goto err; M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len); } - if (!PKCS7_is_detached(p7) && !(os->flags & ASN1_STRING_FLAG_NDEF)) - { - char *cont; - long contlen; - btmp=BIO_find_type(bio,BIO_TYPE_MEM); - if (btmp == NULL) - { - PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNABLE_TO_FIND_MEM_BIO); - goto err; + if (!PKCS7_is_detached(p7)) { + /* + * NOTE(emilia): I think we only reach os == NULL here because detached + * digested data support is broken. + */ + if (os == NULL) + goto err; + if (!(os->flags & ASN1_STRING_FLAG_NDEF)) { + char *cont; + long contlen; + btmp = BIO_find_type(bio, BIO_TYPE_MEM); + if (btmp == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNABLE_TO_FIND_MEM_BIO); + goto err; } - contlen = BIO_get_mem_data(btmp, &cont); - /* Mark the BIO read only then we can use its copy of the data - * instead of making an extra copy. - */ - BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY); - BIO_set_mem_eof_return(btmp, 0); - ASN1_STRING_set0(os, (unsigned char *)cont, contlen); + contlen = BIO_get_mem_data(btmp, &cont); + /* + * Mark the BIO read only then we can use its copy of the data + * instead of making an extra copy. + */ + BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY); + BIO_set_mem_eof_return(btmp, 0); + ASN1_STRING_set0(os, (unsigned char *)cont, contlen); } + } ret=1; err: EVP_MD_CTX_cleanup(&ctx_tmp); return(ret); } int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si) { EVP_MD_CTX mctx; EVP_PKEY_CTX *pctx; unsigned char *abuf = NULL; int alen; size_t siglen; const EVP_MD *md = NULL; md = EVP_get_digestbyobj(si->digest_alg->algorithm); if (md == NULL) return 0; EVP_MD_CTX_init(&mctx); if (EVP_DigestSignInit(&mctx, &pctx, md,NULL, si->pkey) <= 0) goto err; if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, EVP_PKEY_CTRL_PKCS7_SIGN, 0, si) <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR); goto err; } alen = ASN1_item_i2d((ASN1_VALUE *)si->auth_attr,&abuf, ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); if(!abuf) goto err; if (EVP_DigestSignUpdate(&mctx,abuf,alen) <= 0) goto err; OPENSSL_free(abuf); abuf = NULL; if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0) goto err; abuf = OPENSSL_malloc(siglen); if(!abuf) goto err; if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0) goto err; if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR); goto err; } EVP_MD_CTX_cleanup(&mctx); ASN1_STRING_set0(si->enc_digest, abuf, siglen); return 1; err: if (abuf) OPENSSL_free(abuf); EVP_MD_CTX_cleanup(&mctx); return 0; } int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si) { PKCS7_ISSUER_AND_SERIAL *ias; int ret=0,i; STACK_OF(X509) *cert; X509 *x509; + + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_INVALID_NULL_POINTER); + return 0; + } + + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_NO_CONTENT); + return 0; + } if (PKCS7_type_is_signed(p7)) { cert=p7->d.sign->cert; } else if (PKCS7_type_is_signedAndEnveloped(p7)) { cert=p7->d.signed_and_enveloped->cert; } else { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_WRONG_PKCS7_TYPE); goto err; } /* XXXXXXXXXXXXXXXXXXXXXXX */ ias=si->issuer_and_serial; x509=X509_find_by_issuer_and_serial(cert,ias->issuer,ias->serial); /* were we able to find the cert in passed to us */ if (x509 == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_UNABLE_TO_FIND_CERTIFICATE); goto err; } /* Lets verify */ if(!X509_STORE_CTX_init(ctx,cert_store,x509,cert)) { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); goto err; } X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN); i=X509_verify_cert(ctx); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); X509_STORE_CTX_cleanup(ctx); goto err; } X509_STORE_CTX_cleanup(ctx); return PKCS7_signatureVerify(bio, p7, si, x509); err: return ret; } int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, X509 *x509) { ASN1_OCTET_STRING *os; EVP_MD_CTX mdc_tmp,*mdc; int ret=0,i; int md_type; STACK_OF(X509_ATTRIBUTE) *sk; BIO *btmp; EVP_PKEY *pkey; EVP_MD_CTX_init(&mdc_tmp); if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); goto err; } md_type=OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; for (;;) { if ((btmp == NULL) || ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } BIO_get_md_ctx(btmp,&mdc); if (mdc == NULL) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_INTERNAL_ERROR); goto err; } if (EVP_MD_CTX_type(mdc) == md_type) break; /* Workaround for some broken clients that put the signature * OID instead of the digest OID in digest_alg->algorithm */ if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type) break; btmp=BIO_next(btmp); } /* mdc is the digest ctx that we want, unless there are attributes, * in which case the digest is the signed attributes */ if (!EVP_MD_CTX_copy_ex(&mdc_tmp,mdc)) goto err; sk=si->auth_attr; if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL; unsigned int md_len; int alen; ASN1_OCTET_STRING *message_digest; if (!EVP_DigestFinal_ex(&mdc_tmp,md_dat,&md_len)) goto err; message_digest=PKCS7_digest_from_attributes(sk); if (!message_digest) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } if ((message_digest->length != (int)md_len) || (memcmp(message_digest->data,md_dat,md_len))) { #if 0 { int ii; for (ii=0; iilength; ii++) printf("%02X",message_digest->data[ii]); printf(" sent\n"); for (ii=0; iienc_digest; pkey = X509_get_pubkey(x509); if (!pkey) { ret = -1; goto err; } i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey); EVP_PKEY_free(pkey); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE); ret= -1; goto err; } else ret=1; err: EVP_MD_CTX_cleanup(&mdc_tmp); return(ret); } PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx) { STACK_OF(PKCS7_RECIP_INFO) *rsk; PKCS7_RECIP_INFO *ri; int i; i=OBJ_obj2nid(p7->type); if (i != NID_pkcs7_signedAndEnveloped) return NULL; if (p7->d.signed_and_enveloped == NULL) return NULL; rsk=p7->d.signed_and_enveloped->recipientinfo; if (rsk == NULL) return NULL; ri=sk_PKCS7_RECIP_INFO_value(rsk,0); if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) return(NULL); ri=sk_PKCS7_RECIP_INFO_value(rsk,idx); return(ri->issuer_and_serial); } ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid) { return(get_attribute(si->auth_attr,nid)); } ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid) { return(get_attribute(si->unauth_attr,nid)); } static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid) { int i; X509_ATTRIBUTE *xa; ASN1_OBJECT *o; o=OBJ_nid2obj(nid); if (!o || !sk) return(NULL); for (i=0; iobject,o) == 0) { if (!xa->single && sk_ASN1_TYPE_num(xa->value.set)) return(sk_ASN1_TYPE_value(xa->value.set,0)); else return(NULL); } } return(NULL); } ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk) { ASN1_TYPE *astype; if(!(astype = get_attribute(sk, NID_pkcs9_messageDigest))) return NULL; return astype->value.octet_string; } int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk) { int i; if (p7si->auth_attr != NULL) sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr,X509_ATTRIBUTE_free); p7si->auth_attr=sk_X509_ATTRIBUTE_dup(sk); if (p7si->auth_attr == NULL) return 0; for (i=0; iauth_attr,i, X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) == NULL) return(0); } return(1); } int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk) { int i; if (p7si->unauth_attr != NULL) sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr, X509_ATTRIBUTE_free); p7si->unauth_attr=sk_X509_ATTRIBUTE_dup(sk); if (p7si->unauth_attr == NULL) return 0; for (i=0; iunauth_attr,i, X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) == NULL) return(0); } return(1); } int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, void *value) { return(add_attribute(&(p7si->auth_attr),nid,atrtype,value)); } int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, void *value) { return(add_attribute(&(p7si->unauth_attr),nid,atrtype,value)); } static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, void *value) { X509_ATTRIBUTE *attr=NULL; if (*sk == NULL) { *sk = sk_X509_ATTRIBUTE_new_null(); if (*sk == NULL) return 0; new_attrib: if (!(attr=X509_ATTRIBUTE_create(nid,atrtype,value))) return 0; if (!sk_X509_ATTRIBUTE_push(*sk,attr)) { X509_ATTRIBUTE_free(attr); return 0; } } else { int i; for (i=0; iobject) == nid) { X509_ATTRIBUTE_free(attr); attr=X509_ATTRIBUTE_create(nid,atrtype,value); if (attr == NULL) return 0; if (!sk_X509_ATTRIBUTE_set(*sk,i,attr)) { X509_ATTRIBUTE_free(attr); return 0; } goto end; } } goto new_attrib; } end: return(1); } Index: releng/10.1/crypto/openssl/crypto/pkcs7/pk7_lib.c =================================================================== --- releng/10.1/crypto/openssl/crypto/pkcs7/pk7_lib.c (revision 280267) +++ releng/10.1/crypto/openssl/crypto/pkcs7/pk7_lib.c (revision 280268) @@ -1,665 +1,668 @@ /* crypto/pkcs7/pk7_lib.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include "cryptlib.h" #include #include #include "asn1_locl.h" long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg) { int nid; long ret; nid=OBJ_obj2nid(p7->type); switch (cmd) { + /* NOTE(emilia): does not support detached digested data. */ case PKCS7_OP_SET_DETACHED_SIGNATURE: if (nid == NID_pkcs7_signed) { ret=p7->detached=(int)larg; if (ret && PKCS7_type_is_data(p7->d.sign->contents)) { ASN1_OCTET_STRING *os; os=p7->d.sign->contents->d.data; ASN1_OCTET_STRING_free(os); p7->d.sign->contents->d.data = NULL; } } else { PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); ret=0; } break; case PKCS7_OP_GET_DETACHED_SIGNATURE: if (nid == NID_pkcs7_signed) { if(!p7->d.sign || !p7->d.sign->contents->d.ptr) ret = 1; else ret = 0; p7->detached = ret; } else { PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); ret=0; } break; default: PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_UNKNOWN_OPERATION); ret=0; } return(ret); } int PKCS7_content_new(PKCS7 *p7, int type) { PKCS7 *ret=NULL; if ((ret=PKCS7_new()) == NULL) goto err; if (!PKCS7_set_type(ret,type)) goto err; if (!PKCS7_set_content(p7,ret)) goto err; return(1); err: if (ret != NULL) PKCS7_free(ret); return(0); } int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data) { int i; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: if (p7->d.sign->contents != NULL) PKCS7_free(p7->d.sign->contents); p7->d.sign->contents=p7_data; break; case NID_pkcs7_digest: if (p7->d.digest->contents != NULL) PKCS7_free(p7->d.digest->contents); p7->d.digest->contents=p7_data; break; case NID_pkcs7_data: case NID_pkcs7_enveloped: case NID_pkcs7_signedAndEnveloped: case NID_pkcs7_encrypted: default: PKCS7err(PKCS7_F_PKCS7_SET_CONTENT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } return(1); err: return(0); } int PKCS7_set_type(PKCS7 *p7, int type) { ASN1_OBJECT *obj; /*PKCS7_content_free(p7);*/ obj=OBJ_nid2obj(type); /* will not fail */ switch (type) { case NID_pkcs7_signed: p7->type=obj; if ((p7->d.sign=PKCS7_SIGNED_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.sign->version,1)) { PKCS7_SIGNED_free(p7->d.sign); p7->d.sign=NULL; goto err; } break; case NID_pkcs7_data: p7->type=obj; if ((p7->d.data=M_ASN1_OCTET_STRING_new()) == NULL) goto err; break; case NID_pkcs7_signedAndEnveloped: p7->type=obj; if ((p7->d.signed_and_enveloped=PKCS7_SIGN_ENVELOPE_new()) == NULL) goto err; ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1); if (!ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1)) goto err; p7->d.signed_and_enveloped->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data); break; case NID_pkcs7_enveloped: p7->type=obj; if ((p7->d.enveloped=PKCS7_ENVELOPE_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.enveloped->version,0)) goto err; p7->d.enveloped->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data); break; case NID_pkcs7_encrypted: p7->type=obj; if ((p7->d.encrypted=PKCS7_ENCRYPT_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.encrypted->version,0)) goto err; p7->d.encrypted->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data); break; case NID_pkcs7_digest: p7->type=obj; if ((p7->d.digest=PKCS7_DIGEST_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.digest->version,0)) goto err; break; default: PKCS7err(PKCS7_F_PKCS7_SET_TYPE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } return(1); err: return(0); } int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other) { p7->type = OBJ_nid2obj(type); p7->d.other = other; return 1; } int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *psi) { int i,j,nid; X509_ALGOR *alg; STACK_OF(PKCS7_SIGNER_INFO) *signer_sk; STACK_OF(X509_ALGOR) *md_sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: signer_sk= p7->d.sign->signer_info; md_sk= p7->d.sign->md_algs; break; case NID_pkcs7_signedAndEnveloped: signer_sk= p7->d.signed_and_enveloped->signer_info; md_sk= p7->d.signed_and_enveloped->md_algs; break; default: PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } nid=OBJ_obj2nid(psi->digest_alg->algorithm); /* If the digest is not currently listed, add it */ j=0; for (i=0; ialgorithm) == nid) { j=1; break; } } if (!j) /* we need to add another algorithm */ { if(!(alg=X509_ALGOR_new()) || !(alg->parameter = ASN1_TYPE_new())) { X509_ALGOR_free(alg); PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,ERR_R_MALLOC_FAILURE); return(0); } alg->algorithm=OBJ_nid2obj(nid); alg->parameter->type = V_ASN1_NULL; if (!sk_X509_ALGOR_push(md_sk,alg)) { X509_ALGOR_free(alg); return 0; } } if (!sk_PKCS7_SIGNER_INFO_push(signer_sk,psi)) return 0; return(1); } int PKCS7_add_certificate(PKCS7 *p7, X509 *x509) { int i; STACK_OF(X509) **sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: sk= &(p7->d.sign->cert); break; case NID_pkcs7_signedAndEnveloped: sk= &(p7->d.signed_and_enveloped->cert); break; default: PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } if (*sk == NULL) *sk=sk_X509_new_null(); if (*sk == NULL) { PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE, ERR_R_MALLOC_FAILURE); return 0; } CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); if (!sk_X509_push(*sk,x509)) { X509_free(x509); return 0; } return(1); } int PKCS7_add_crl(PKCS7 *p7, X509_CRL *crl) { int i; STACK_OF(X509_CRL) **sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: sk= &(p7->d.sign->crl); break; case NID_pkcs7_signedAndEnveloped: sk= &(p7->d.signed_and_enveloped->crl); break; default: PKCS7err(PKCS7_F_PKCS7_ADD_CRL,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } if (*sk == NULL) *sk=sk_X509_CRL_new_null(); if (*sk == NULL) { PKCS7err(PKCS7_F_PKCS7_ADD_CRL,ERR_R_MALLOC_FAILURE); return 0; } CRYPTO_add(&crl->references,1,CRYPTO_LOCK_X509_CRL); if (!sk_X509_CRL_push(*sk,crl)) { X509_CRL_free(crl); return 0; } return(1); } int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, const EVP_MD *dgst) { int ret; /* We now need to add another PKCS7_SIGNER_INFO entry */ if (!ASN1_INTEGER_set(p7i->version,1)) goto err; if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, X509_get_issuer_name(x509))) goto err; /* because ASN1_INTEGER_set is used to set a 'long' we will do * things the ugly way. */ M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); if (!(p7i->issuer_and_serial->serial= M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) goto err; /* lets keep the pkey around for a while */ CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY); p7i->pkey=pkey; /* Set the algorithms */ X509_ALGOR_set0(p7i->digest_alg, OBJ_nid2obj(EVP_MD_type(dgst)), V_ASN1_NULL, NULL); if (pkey->ameth && pkey->ameth->pkey_ctrl) { ret = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_PKCS7_SIGN, 0, p7i); if (ret > 0) return 1; if (ret != -2) { PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SET, PKCS7_R_SIGNING_CTRL_FAILURE); return 0; } } PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SET, PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); err: return 0; } PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey, const EVP_MD *dgst) { PKCS7_SIGNER_INFO *si = NULL; if (dgst == NULL) { int def_nid; if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) <= 0) goto err; dgst = EVP_get_digestbynid(def_nid); if (dgst == NULL) { PKCS7err(PKCS7_F_PKCS7_ADD_SIGNATURE, PKCS7_R_NO_DEFAULT_DIGEST); goto err; } } if ((si=PKCS7_SIGNER_INFO_new()) == NULL) goto err; if (!PKCS7_SIGNER_INFO_set(si,x509,pkey,dgst)) goto err; if (!PKCS7_add_signer(p7,si)) goto err; return(si); err: if (si) PKCS7_SIGNER_INFO_free(si); return(NULL); } int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) { if (PKCS7_type_is_digest(p7)) { if(!(p7->d.digest->md->parameter = ASN1_TYPE_new())) { PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,ERR_R_MALLOC_FAILURE); return 0; } p7->d.digest->md->parameter->type = V_ASN1_NULL; p7->d.digest->md->algorithm = OBJ_nid2obj(EVP_MD_nid(md)); return 1; } PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,PKCS7_R_WRONG_CONTENT_TYPE); return 1; } STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7) { + if (p7 == NULL || p7->d.ptr == NULL) + return NULL; if (PKCS7_type_is_signed(p7)) { return(p7->d.sign->signer_info); } else if (PKCS7_type_is_signedAndEnveloped(p7)) { return(p7->d.signed_and_enveloped->signer_info); } else return(NULL); } void PKCS7_SIGNER_INFO_get0_algs(PKCS7_SIGNER_INFO *si, EVP_PKEY **pk, X509_ALGOR **pdig, X509_ALGOR **psig) { if (pk) *pk = si->pkey; if (pdig) *pdig = si->digest_alg; if (psig) *psig = si->digest_enc_alg; } void PKCS7_RECIP_INFO_get0_alg(PKCS7_RECIP_INFO *ri, X509_ALGOR **penc) { if (penc) *penc = ri->key_enc_algor; } PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509) { PKCS7_RECIP_INFO *ri; if ((ri=PKCS7_RECIP_INFO_new()) == NULL) goto err; if (!PKCS7_RECIP_INFO_set(ri,x509)) goto err; if (!PKCS7_add_recipient_info(p7,ri)) goto err; return ri; err: if (ri) PKCS7_RECIP_INFO_free(ri); return NULL; } int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri) { int i; STACK_OF(PKCS7_RECIP_INFO) *sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signedAndEnveloped: sk= p7->d.signed_and_enveloped->recipientinfo; break; case NID_pkcs7_enveloped: sk= p7->d.enveloped->recipientinfo; break; default: PKCS7err(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } if (!sk_PKCS7_RECIP_INFO_push(sk,ri)) return 0; return(1); } int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509) { int ret; EVP_PKEY *pkey = NULL; if (!ASN1_INTEGER_set(p7i->version,0)) return 0; if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, X509_get_issuer_name(x509))) return 0; M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); if (!(p7i->issuer_and_serial->serial= M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) return 0; pkey = X509_get_pubkey(x509); if (!pkey || !pkey->ameth || !pkey->ameth->pkey_ctrl) { PKCS7err(PKCS7_F_PKCS7_RECIP_INFO_SET, PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); goto err; } ret = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_PKCS7_ENCRYPT, 0, p7i); if (ret == -2) { PKCS7err(PKCS7_F_PKCS7_RECIP_INFO_SET, PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); goto err; } if (ret <= 0) { PKCS7err(PKCS7_F_PKCS7_RECIP_INFO_SET, PKCS7_R_ENCRYPTION_CTRL_FAILURE); goto err; } EVP_PKEY_free(pkey); CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); p7i->cert=x509; return 1; err: if (pkey) EVP_PKEY_free(pkey); return 0; } X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si) { if (PKCS7_type_is_signed(p7)) return(X509_find_by_issuer_and_serial(p7->d.sign->cert, si->issuer_and_serial->issuer, si->issuer_and_serial->serial)); else return(NULL); } int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher) { int i; PKCS7_ENC_CONTENT *ec; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signedAndEnveloped: ec=p7->d.signed_and_enveloped->enc_data; break; case NID_pkcs7_enveloped: ec=p7->d.enveloped->enc_data; break; default: PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } /* Check cipher OID exists and has data in it*/ i = EVP_CIPHER_type(cipher); if(i == NID_undef) { PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); return(0); } ec->cipher = cipher; return 1; } int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7) { ASN1_OCTET_STRING *os = NULL; switch (OBJ_obj2nid(p7->type)) { case NID_pkcs7_data: os = p7->d.data; break; case NID_pkcs7_signedAndEnveloped: os = p7->d.signed_and_enveloped->enc_data->enc_data; if (os == NULL) { os=M_ASN1_OCTET_STRING_new(); p7->d.signed_and_enveloped->enc_data->enc_data=os; } break; case NID_pkcs7_enveloped: os = p7->d.enveloped->enc_data->enc_data; if (os == NULL) { os=M_ASN1_OCTET_STRING_new(); p7->d.enveloped->enc_data->enc_data=os; } break; case NID_pkcs7_signed: os=p7->d.sign->contents->d.data; break; default: os = NULL; break; } if (os == NULL) return 0; os->flags |= ASN1_STRING_FLAG_NDEF; *boundary = &os->data; return 1; } Index: releng/10.1/crypto/openssl/doc/crypto/d2i_X509.pod =================================================================== --- releng/10.1/crypto/openssl/doc/crypto/d2i_X509.pod (revision 280267) +++ releng/10.1/crypto/openssl/doc/crypto/d2i_X509.pod (revision 280268) @@ -1,231 +1,239 @@ =pod =head1 NAME d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio, i2d_X509_fp - X509 encode and decode functions =head1 SYNOPSIS #include X509 *d2i_X509(X509 **px, const unsigned char **in, int len); int i2d_X509(X509 *x, unsigned char **out); X509 *d2i_X509_bio(BIO *bp, X509 **x); X509 *d2i_X509_fp(FILE *fp, X509 **x); int i2d_X509_bio(BIO *bp, X509 *x); int i2d_X509_fp(FILE *fp, X509 *x); =head1 DESCRIPTION The X509 encode and decode routines encode and parse an B structure, which represents an X509 certificate. d2i_X509() attempts to decode B bytes at B<*in>. If successful a pointer to the B structure is returned. If an error occurred then B is returned. If B is not B then the returned structure is written to B<*px>. If B<*px> is not B then it is assumed that B<*px> contains a valid B structure and an attempt is made to reuse it. If the call is successful B<*in> is incremented to the byte following the parsed data. i2d_X509() encodes the structure pointed to by B into DER format. If B is not B is writes the DER encoded data to the buffer at B<*out>, and increments it to point after the data just written. If the return value is negative an error occurred, otherwise it returns the length of the encoded data. For OpenSSL 0.9.7 and later if B<*out> is B memory will be allocated for a buffer and the encoded data written to it. In this case B<*out> is not incremented and it points to the start of the data just written. d2i_X509_bio() is similar to d2i_X509() except it attempts to parse data from BIO B. d2i_X509_fp() is similar to d2i_X509() except it attempts to parse data from FILE pointer B. i2d_X509_bio() is similar to i2d_X509() except it writes the encoding of the structure B to BIO B and it returns 1 for success and 0 for failure. i2d_X509_fp() is similar to i2d_X509() except it writes the encoding of the structure B to BIO B and it returns 1 for success and 0 for failure. =head1 NOTES The letters B and B in for example B stand for "internal" (that is an internal C structure) and "DER". So that B converts from internal to DER. The functions can also understand B forms. The actual X509 structure passed to i2d_X509() must be a valid populated B structure it can B simply be fed with an empty structure such as that returned by X509_new(). The encoded data is in binary form and may contain embedded zeroes. Therefore any FILE pointers or BIOs should be opened in binary mode. Functions such as B will B return the correct length of the encoded structure. The ways that B<*in> and B<*out> are incremented after the operation can trap the unwary. See the B section for some common errors. The reason for the auto increment behaviour is to reflect a typical usage of ASN1 functions: after one structure is encoded or decoded another will processed after it. =head1 EXAMPLES Allocate and encode the DER encoding of an X509 structure: int len; unsigned char *buf, *p; len = i2d_X509(x, NULL); buf = OPENSSL_malloc(len); if (buf == NULL) /* error */ p = buf; i2d_X509(x, &p); If you are using OpenSSL 0.9.7 or later then this can be simplified to: int len; unsigned char *buf; buf = NULL; len = i2d_X509(x, &buf); if (len < 0) /* error */ Attempt to decode a buffer: X509 *x; unsigned char *buf, *p; int len; /* Something to setup buf and len */ p = buf; x = d2i_X509(NULL, &p, len); if (x == NULL) /* Some error */ Alternative technique: X509 *x; unsigned char *buf, *p; int len; /* Something to setup buf and len */ p = buf; x = NULL; if(!d2i_X509(&x, &p, len)) /* Some error */ =head1 WARNINGS The use of temporary variable is mandatory. A common mistake is to attempt to use a buffer directly as follows: int len; unsigned char *buf; len = i2d_X509(x, NULL); buf = OPENSSL_malloc(len); if (buf == NULL) /* error */ i2d_X509(x, &buf); /* Other stuff ... */ OPENSSL_free(buf); This code will result in B apparently containing garbage because it was incremented after the call to point after the data just written. Also B will no longer contain the pointer allocated by B and the subsequent call to B may well crash. The auto allocation feature (setting buf to NULL) only works on OpenSSL 0.9.7 and later. Attempts to use it on earlier versions will typically cause a segmentation violation. Another trap to avoid is misuse of the B argument to B: X509 *x; if (!d2i_X509(&x, &p, len)) /* Some error */ This will probably crash somewhere in B. The reason for this is that the variable B is uninitialized and an attempt will be made to interpret its (invalid) value as an B structure, typically causing a segmentation violation. If B is set to NULL first then this will not happen. =head1 BUGS In some versions of OpenSSL the "reuse" behaviour of d2i_X509() when B<*px> is valid is broken and some parts of the reused structure may persist if they are not present in the new one. As a result the use of this "reuse" behaviour is strongly discouraged. +Current versions of OpenSSL will not modify B<*px> if an error occurs. +If parsing succeeds then B<*px> is freed (if it is not NULL) and then +set to the value of the newly decoded structure. As a result B<*px> +B be allocated on the stack or an attempt will be made to +free an invalid pointer. + i2d_X509() will not return an error in many versions of OpenSSL, if mandatory fields are not initialized due to a programming error then the encoded structure may contain invalid data or omit the fields entirely and will not be parsed by d2i_X509(). This may be fixed in future so code should not assume that i2d_X509() will always succeed. =head1 RETURN VALUES d2i_X509(), d2i_X509_bio() and d2i_X509_fp() return a valid B structure or B if an error occurs. The error code that can be obtained by -L. +L. If the "reuse" capability has been used +with a valid X509 structure being passed in via B then the object is not +modified in the event of error. i2d_X509() returns the number of bytes successfully encoded or a negative value if an error occurs. The error code can be obtained by L. i2d_X509_bio() and i2d_X509_fp() return 1 for success and 0 if an error occurs The error code can be obtained by L. =head1 SEE ALSO L =head1 HISTORY d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio and i2d_X509_fp are available in all versions of SSLeay and OpenSSL. =cut Index: releng/10.1/crypto/openssl/ssl/s2_lib.c =================================================================== --- releng/10.1/crypto/openssl/ssl/s2_lib.c (revision 280267) +++ releng/10.1/crypto/openssl/ssl/s2_lib.c (revision 280268) @@ -1,558 +1,558 @@ /* ssl/s2_lib.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* ==================================================================== * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ #include "ssl_locl.h" #ifndef OPENSSL_NO_SSL2 #include #include #include #include const char ssl2_version_str[]="SSLv2" OPENSSL_VERSION_PTEXT; #define SSL2_NUM_CIPHERS (sizeof(ssl2_ciphers)/sizeof(SSL_CIPHER)) /* list of available SSLv2 ciphers (sorted by id) */ OPENSSL_GLOBAL const SSL_CIPHER ssl2_ciphers[]={ #if 0 /* NULL_WITH_MD5 v3 */ { 1, SSL2_TXT_NULL_WITH_MD5, SSL2_CK_NULL_WITH_MD5, SSL_kRSA, SSL_aRSA, SSL_eNULL, SSL_MD5, SSL_SSLV2, SSL_EXPORT|SSL_EXP40|SSL_STRONG_NONE, 0, 0, 0, }, #endif /* RC4_128_WITH_MD5 */ { 1, SSL2_TXT_RC4_128_WITH_MD5, SSL2_CK_RC4_128_WITH_MD5, SSL_kRSA, SSL_aRSA, SSL_RC4, SSL_MD5, SSL_SSLV2, SSL_NOT_EXP|SSL_MEDIUM, 0, 128, 128, }, /* RC4_128_EXPORT40_WITH_MD5 */ { 1, SSL2_TXT_RC4_128_EXPORT40_WITH_MD5, SSL2_CK_RC4_128_EXPORT40_WITH_MD5, SSL_kRSA, SSL_aRSA, SSL_RC4, SSL_MD5, SSL_SSLV2, SSL_EXPORT|SSL_EXP40, SSL2_CF_5_BYTE_ENC, 40, 128, }, /* RC2_128_CBC_WITH_MD5 */ { 1, SSL2_TXT_RC2_128_CBC_WITH_MD5, SSL2_CK_RC2_128_CBC_WITH_MD5, SSL_kRSA, SSL_aRSA, SSL_RC2, SSL_MD5, SSL_SSLV2, SSL_NOT_EXP|SSL_MEDIUM, 0, 128, 128, }, /* RC2_128_CBC_EXPORT40_WITH_MD5 */ { 1, SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5, SSL2_CK_RC2_128_CBC_EXPORT40_WITH_MD5, SSL_kRSA, SSL_aRSA, SSL_RC2, SSL_MD5, SSL_SSLV2, SSL_EXPORT|SSL_EXP40, SSL2_CF_5_BYTE_ENC, 40, 128, }, #ifndef OPENSSL_NO_IDEA /* IDEA_128_CBC_WITH_MD5 */ { 1, SSL2_TXT_IDEA_128_CBC_WITH_MD5, SSL2_CK_IDEA_128_CBC_WITH_MD5, SSL_kRSA, SSL_aRSA, SSL_IDEA, SSL_MD5, SSL_SSLV2, SSL_NOT_EXP|SSL_MEDIUM, 0, 128, 128, }, #endif /* DES_64_CBC_WITH_MD5 */ { 1, SSL2_TXT_DES_64_CBC_WITH_MD5, SSL2_CK_DES_64_CBC_WITH_MD5, SSL_kRSA, SSL_aRSA, SSL_DES, SSL_MD5, SSL_SSLV2, SSL_NOT_EXP|SSL_LOW, 0, 56, 56, }, /* DES_192_EDE3_CBC_WITH_MD5 */ { 1, SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5, SSL2_CK_DES_192_EDE3_CBC_WITH_MD5, SSL_kRSA, SSL_aRSA, SSL_3DES, SSL_MD5, SSL_SSLV2, SSL_NOT_EXP|SSL_HIGH, 0, 112, 168, }, #if 0 /* RC4_64_WITH_MD5 */ { 1, SSL2_TXT_RC4_64_WITH_MD5, SSL2_CK_RC4_64_WITH_MD5, SSL_kRSA, SSL_aRSA, SSL_RC4, SSL_MD5, SSL_SSLV2, SSL_NOT_EXP|SSL_LOW, SSL2_CF_8_BYTE_ENC, 64, 64, }, #endif #if 0 /* NULL SSLeay (testing) */ { 0, SSL2_TXT_NULL, SSL2_CK_NULL, 0, 0, 0, 0, SSL_SSLV2, SSL_STRONG_NONE, 0, 0, 0, }, #endif /* end of list :-) */ }; long ssl2_default_timeout(void) { return(300); } int ssl2_num_ciphers(void) { return(SSL2_NUM_CIPHERS); } const SSL_CIPHER *ssl2_get_cipher(unsigned int u) { if (u < SSL2_NUM_CIPHERS) return(&(ssl2_ciphers[SSL2_NUM_CIPHERS-1-u])); else return(NULL); } int ssl2_pending(const SSL *s) { return SSL_in_init(s) ? 0 : s->s2->ract_data_length; } int ssl2_new(SSL *s) { SSL2_STATE *s2; if ((s2=OPENSSL_malloc(sizeof *s2)) == NULL) goto err; memset(s2,0,sizeof *s2); #if SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER + 3 > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2 # error "assertion failed" #endif if ((s2->rbuf=OPENSSL_malloc( SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2)) == NULL) goto err; /* wbuf needs one byte more because when using two-byte headers, * we leave the first byte unused in do_ssl_write (s2_pkt.c) */ if ((s2->wbuf=OPENSSL_malloc( SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+3)) == NULL) goto err; s->s2=s2; ssl2_clear(s); return(1); err: if (s2 != NULL) { if (s2->wbuf != NULL) OPENSSL_free(s2->wbuf); if (s2->rbuf != NULL) OPENSSL_free(s2->rbuf); OPENSSL_free(s2); } return(0); } void ssl2_free(SSL *s) { SSL2_STATE *s2; if(s == NULL) return; s2=s->s2; if (s2->rbuf != NULL) OPENSSL_free(s2->rbuf); if (s2->wbuf != NULL) OPENSSL_free(s2->wbuf); OPENSSL_cleanse(s2,sizeof *s2); OPENSSL_free(s2); s->s2=NULL; } void ssl2_clear(SSL *s) { SSL2_STATE *s2; unsigned char *rbuf,*wbuf; s2=s->s2; rbuf=s2->rbuf; wbuf=s2->wbuf; memset(s2,0,sizeof *s2); s2->rbuf=rbuf; s2->wbuf=wbuf; s2->clear_text=1; s->packet=s2->rbuf; s->version=SSL2_VERSION; s->packet_length=0; } long ssl2_ctrl(SSL *s, int cmd, long larg, void *parg) { int ret=0; switch(cmd) { case SSL_CTRL_GET_SESSION_REUSED: ret=s->hit; break; case SSL_CTRL_CHECK_PROTO_VERSION: return ssl3_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, larg, parg); default: break; } return(ret); } long ssl2_callback_ctrl(SSL *s, int cmd, void (*fp)(void)) { return(0); } long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { return(0); } long ssl2_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) { return(0); } /* This function needs to check if the ciphers required are actually * available */ const SSL_CIPHER *ssl2_get_cipher_by_char(const unsigned char *p) { SSL_CIPHER c; const SSL_CIPHER *cp; unsigned long id; id=0x02000000L|((unsigned long)p[0]<<16L)| ((unsigned long)p[1]<<8L)|(unsigned long)p[2]; c.id=id; cp = OBJ_bsearch_ssl_cipher_id(&c, ssl2_ciphers, SSL2_NUM_CIPHERS); if ((cp == NULL) || (cp->valid == 0)) return NULL; else return cp; } int ssl2_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p) { long l; if (p != NULL) { l=c->id; if ((l & 0xff000000) != 0x02000000 && l != SSL3_CK_FALLBACK_SCSV) return(0); p[0]=((unsigned char)(l>>16L))&0xFF; p[1]=((unsigned char)(l>> 8L))&0xFF; p[2]=((unsigned char)(l ))&0xFF; } return(3); } int ssl2_generate_key_material(SSL *s) { unsigned int i; EVP_MD_CTX ctx; unsigned char *km; unsigned char c='0'; const EVP_MD *md5; int md_size; md5 = EVP_md5(); #ifdef CHARSET_EBCDIC c = os_toascii['0']; /* Must be an ASCII '0', not EBCDIC '0', see SSLv2 docu */ #endif EVP_MD_CTX_init(&ctx); km=s->s2->key_material; if (s->session->master_key_length < 0 || s->session->master_key_length > (int)sizeof(s->session->master_key)) { SSLerr(SSL_F_SSL2_GENERATE_KEY_MATERIAL, ERR_R_INTERNAL_ERROR); return 0; } md_size = EVP_MD_size(md5); if (md_size < 0) return 0; for (i=0; is2->key_material_length; i += md_size) { if (((km - s->s2->key_material) + md_size) > (int)sizeof(s->s2->key_material)) { /* EVP_DigestFinal_ex() below would write beyond buffer */ SSLerr(SSL_F_SSL2_GENERATE_KEY_MATERIAL, ERR_R_INTERNAL_ERROR); return 0; } EVP_DigestInit_ex(&ctx, md5, NULL); OPENSSL_assert(s->session->master_key_length >= 0 && s->session->master_key_length - < (int)sizeof(s->session->master_key)); + <= (int)sizeof(s->session->master_key)); EVP_DigestUpdate(&ctx,s->session->master_key,s->session->master_key_length); EVP_DigestUpdate(&ctx,&c,1); c++; EVP_DigestUpdate(&ctx,s->s2->challenge,s->s2->challenge_length); EVP_DigestUpdate(&ctx,s->s2->conn_id,s->s2->conn_id_length); EVP_DigestFinal_ex(&ctx,km,NULL); km += md_size; } EVP_MD_CTX_cleanup(&ctx); return 1; } void ssl2_return_error(SSL *s, int err) { if (!s->error) { s->error=3; s->error_code=err; ssl2_write_error(s); } } void ssl2_write_error(SSL *s) { unsigned char buf[3]; int i,error; buf[0]=SSL2_MT_ERROR; buf[1]=(s->error_code>>8)&0xff; buf[2]=(s->error_code)&0xff; /* state=s->rwstate;*/ error=s->error; /* number of bytes left to write */ s->error=0; OPENSSL_assert(error >= 0 && error <= (int)sizeof(buf)); i=ssl2_write(s,&(buf[3-error]),error); /* if (i == error) s->rwstate=state; */ if (i < 0) s->error=error; else { s->error=error-i; if (s->error == 0) if (s->msg_callback) s->msg_callback(1, s->version, 0, buf, 3, s, s->msg_callback_arg); /* ERROR */ } } int ssl2_shutdown(SSL *s) { s->shutdown=(SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); return(1); } #else /* !OPENSSL_NO_SSL2 */ # if PEDANTIC static void *dummy=&dummy; # endif #endif Index: releng/10.1/crypto/openssl/ssl/s2_srvr.c =================================================================== --- releng/10.1/crypto/openssl/ssl/s2_srvr.c (revision 280267) +++ releng/10.1/crypto/openssl/ssl/s2_srvr.c (revision 280268) @@ -1,1156 +1,1192 @@ /* ssl/s2_srvr.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* ==================================================================== * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ #include "ssl_locl.h" #ifndef OPENSSL_NO_SSL2 #include #include #include #include #include static const SSL_METHOD *ssl2_get_server_method(int ver); static int get_client_master_key(SSL *s); static int get_client_hello(SSL *s); static int server_hello(SSL *s); static int get_client_finished(SSL *s); static int server_verify(SSL *s); static int server_finish(SSL *s); static int request_certificate(SSL *s); static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from, unsigned char *to,int padding); #define BREAK break static const SSL_METHOD *ssl2_get_server_method(int ver) { if (ver == SSL2_VERSION) return(SSLv2_server_method()); else return(NULL); } IMPLEMENT_ssl2_meth_func(SSLv2_server_method, ssl2_accept, ssl_undefined_function, ssl2_get_server_method) int ssl2_accept(SSL *s) { unsigned long l=(unsigned long)time(NULL); BUF_MEM *buf=NULL; int ret= -1; long num1; void (*cb)(const SSL *ssl,int type,int val)=NULL; int new_state,state; RAND_add(&l,sizeof(l),0); ERR_clear_error(); clear_sys_error(); if (s->info_callback != NULL) cb=s->info_callback; else if (s->ctx->info_callback != NULL) cb=s->ctx->info_callback; /* init things to blank */ s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); if (s->cert == NULL) { SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_NO_CERTIFICATE_SET); return(-1); } clear_sys_error(); for (;;) { state=s->state; switch (s->state) { case SSL_ST_BEFORE: case SSL_ST_ACCEPT: case SSL_ST_BEFORE|SSL_ST_ACCEPT: case SSL_ST_OK|SSL_ST_ACCEPT: s->server=1; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1); s->version=SSL2_VERSION; s->type=SSL_ST_ACCEPT; if(s->init_buf == NULL) { if ((buf=BUF_MEM_new()) == NULL) { ret= -1; goto end; } if (!BUF_MEM_grow(buf,(int) SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)) { BUF_MEM_free(buf); ret= -1; goto end; } s->init_buf=buf; } s->init_num=0; s->ctx->stats.sess_accept++; s->handshake_func=ssl2_accept; s->state=SSL2_ST_GET_CLIENT_HELLO_A; BREAK; case SSL2_ST_GET_CLIENT_HELLO_A: case SSL2_ST_GET_CLIENT_HELLO_B: case SSL2_ST_GET_CLIENT_HELLO_C: s->shutdown=0; ret=get_client_hello(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SEND_SERVER_HELLO_A; BREAK; case SSL2_ST_SEND_SERVER_HELLO_A: case SSL2_ST_SEND_SERVER_HELLO_B: ret=server_hello(s); if (ret <= 0) goto end; s->init_num=0; if (!s->hit) { s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_A; BREAK; } else { s->state=SSL2_ST_SERVER_START_ENCRYPTION; BREAK; } case SSL2_ST_GET_CLIENT_MASTER_KEY_A: case SSL2_ST_GET_CLIENT_MASTER_KEY_B: ret=get_client_master_key(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SERVER_START_ENCRYPTION; BREAK; case SSL2_ST_SERVER_START_ENCRYPTION: /* Ok we how have sent all the stuff needed to * start encrypting, the next packet back will * be encrypted. */ if (!ssl2_enc_init(s,0)) { ret= -1; goto end; } s->s2->clear_text=0; s->state=SSL2_ST_SEND_SERVER_VERIFY_A; BREAK; case SSL2_ST_SEND_SERVER_VERIFY_A: case SSL2_ST_SEND_SERVER_VERIFY_B: ret=server_verify(s); if (ret <= 0) goto end; s->init_num=0; if (s->hit) { /* If we are in here, we have been * buffering the output, so we need to * flush it and remove buffering from * future traffic */ s->state=SSL2_ST_SEND_SERVER_VERIFY_C; BREAK; } else { s->state=SSL2_ST_GET_CLIENT_FINISHED_A; break; } case SSL2_ST_SEND_SERVER_VERIFY_C: /* get the number of bytes to write */ num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL); if (num1 > 0) { s->rwstate=SSL_WRITING; num1=BIO_flush(s->wbio); if (num1 <= 0) { ret= -1; goto end; } s->rwstate=SSL_NOTHING; } /* flushed and now remove buffering */ s->wbio=BIO_pop(s->wbio); s->state=SSL2_ST_GET_CLIENT_FINISHED_A; BREAK; case SSL2_ST_GET_CLIENT_FINISHED_A: case SSL2_ST_GET_CLIENT_FINISHED_B: ret=get_client_finished(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_A; BREAK; case SSL2_ST_SEND_REQUEST_CERTIFICATE_A: case SSL2_ST_SEND_REQUEST_CERTIFICATE_B: case SSL2_ST_SEND_REQUEST_CERTIFICATE_C: case SSL2_ST_SEND_REQUEST_CERTIFICATE_D: /* don't do a 'request certificate' if we * don't want to, or we already have one, and * we only want to do it once. */ if (!(s->verify_mode & SSL_VERIFY_PEER) || ((s->session->peer != NULL) && (s->verify_mode & SSL_VERIFY_CLIENT_ONCE))) { s->state=SSL2_ST_SEND_SERVER_FINISHED_A; break; } else { ret=request_certificate(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SEND_SERVER_FINISHED_A; } BREAK; case SSL2_ST_SEND_SERVER_FINISHED_A: case SSL2_ST_SEND_SERVER_FINISHED_B: ret=server_finish(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL_ST_OK; break; case SSL_ST_OK: BUF_MEM_free(s->init_buf); ssl_free_wbio_buffer(s); s->init_buf=NULL; s->init_num=0; /* ERR_clear_error();*/ ssl_update_cache(s,SSL_SESS_CACHE_SERVER); s->ctx->stats.sess_accept_good++; /* s->server=1; */ ret=1; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1); goto end; /* BREAK; */ default: SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_UNKNOWN_STATE); ret= -1; goto end; /* BREAK; */ } if ((cb != NULL) && (s->state != state)) { new_state=s->state; s->state=state; cb(s,SSL_CB_ACCEPT_LOOP,1); s->state=new_state; } } end: s->in_handshake--; if (cb != NULL) cb(s,SSL_CB_ACCEPT_EXIT,ret); return(ret); } static int get_client_master_key(SSL *s) { int is_export,i,n,keya,ek; unsigned long len; unsigned char *p; const SSL_CIPHER *cp; const EVP_CIPHER *c; const EVP_MD *md; p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_GET_CLIENT_MASTER_KEY_A) { i=ssl2_read(s,(char *)&(p[s->init_num]),10-s->init_num); if (i < (10-s->init_num)) return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i)); s->init_num = 10; if (*(p++) != SSL2_MT_CLIENT_MASTER_KEY) { if (p[-1] != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_READ_WRONG_PACKET_TYPE); } else SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_PEER_ERROR); return(-1); } cp=ssl2_get_cipher_by_char(p); if (cp == NULL) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_NO_CIPHER_MATCH); return(-1); } s->session->cipher= cp; p+=3; n2s(p,i); s->s2->tmp.clear=i; n2s(p,i); s->s2->tmp.enc=i; n2s(p,i); if(i > SSL_MAX_KEY_ARG_LENGTH) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_KEY_ARG_TOO_LONG); return -1; } s->session->key_arg_length=i; s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_B; } /* SSL2_ST_GET_CLIENT_MASTER_KEY_B */ p=(unsigned char *)s->init_buf->data; if (s->init_buf->length < SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); return -1; } keya=s->session->key_arg_length; len = 10 + (unsigned long)s->s2->tmp.clear + (unsigned long)s->s2->tmp.enc + (unsigned long)keya; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_MESSAGE_TOO_LONG); return -1; } n = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),n); if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i)); if (s->msg_callback) s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-MASTER-KEY */ p += 10; memcpy(s->session->key_arg,&(p[s->s2->tmp.clear+s->s2->tmp.enc]), (unsigned int)keya); if (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_NO_PRIVATEKEY); return(-1); } - i=ssl_rsa_private_decrypt(s->cert,s->s2->tmp.enc, - &(p[s->s2->tmp.clear]),&(p[s->s2->tmp.clear]), - (s->s2->ssl2_rollback)?RSA_SSLV23_PADDING:RSA_PKCS1_PADDING); is_export=SSL_C_IS_EXPORT(s->session->cipher); if (!ssl_cipher_get_evp(s->session,&c,&md,NULL,NULL,NULL)) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS); return(0); } if (s->session->cipher->algorithm2 & SSL2_CF_8_BYTE_ENC) { is_export=1; ek=8; } else ek=5; + /* + * The format of the CLIENT-MASTER-KEY message is + * 1 byte message type + * 3 bytes cipher + * 2-byte clear key length (stored in s->s2->tmp.clear) + * 2-byte encrypted key length (stored in s->s2->tmp.enc) + * 2-byte key args length (IV etc) + * clear key + * encrypted key + * key args + * + * If the cipher is an export cipher, then the encrypted key bytes + * are a fixed portion of the total key (5 or 8 bytes). The size of + * this portion is in |ek|. If the cipher is not an export cipher, + * then the entire key material is encrypted (i.e., clear key length + * must be zero). + */ + if ((!is_export && s->s2->tmp.clear != 0) || + (is_export && s->s2->tmp.clear + ek != EVP_CIPHER_key_length(c))) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_LENGTH); + return -1; + } + /* + * The encrypted blob must decrypt to the encrypted portion of the key. + * Decryption can't be expanding, so if we don't have enough encrypted + * bytes to fit the key in the buffer, stop now. + */ + if ((is_export && s->s2->tmp.enc < ek) || + (!is_export && s->s2->tmp.enc < EVP_CIPHER_key_length(c))) { + ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_LENGTH_TOO_SHORT); + return -1; + } + + i = ssl_rsa_private_decrypt(s->cert, s->s2->tmp.enc, + &(p[s->s2->tmp.clear]), + &(p[s->s2->tmp.clear]), + (s->s2->ssl2_rollback) ? RSA_SSLV23_PADDING : + RSA_PKCS1_PADDING); + /* bad decrypt */ #if 1 /* If a bad decrypt, continue with protocol but with a * random master secret (Bleichenbacher attack) */ - if ((i < 0) || - ((!is_export && (i != EVP_CIPHER_key_length(c))) - || (is_export && ((i != ek) || (s->s2->tmp.clear+(unsigned int)i != - (unsigned int)EVP_CIPHER_key_length(c)))))) - { + if ((i < 0) || ((!is_export && i != EVP_CIPHER_key_length(c)) + || (is_export && i != ek))) { ERR_clear_error(); if (is_export) i=ek; else i=EVP_CIPHER_key_length(c); - if (RAND_pseudo_bytes(p,i) <= 0) + if (RAND_pseudo_bytes(&p[s->s2->tmp.clear], i) <= 0) return 0; - } + } #else if (i < 0) { error=1; SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_RSA_DECRYPT); } /* incorrect number of key bytes for non export cipher */ else if ((!is_export && (i != EVP_CIPHER_key_length(c))) || (is_export && ((i != ek) || (s->s2->tmp.clear+i != EVP_CIPHER_key_length(c))))) { error=1; SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_WRONG_NUMBER_OF_KEY_BITS); } if (error) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } #endif - if (is_export) i+=s->s2->tmp.clear; + if (is_export) + i = EVP_CIPHER_key_length(c); if (i > SSL_MAX_MASTER_KEY_LENGTH) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); return -1; } s->session->master_key_length=i; memcpy(s->session->master_key,p,(unsigned int)i); return(1); } static int get_client_hello(SSL *s) { int i,n; unsigned long len; unsigned char *p; STACK_OF(SSL_CIPHER) *cs; /* a stack of SSL_CIPHERS */ STACK_OF(SSL_CIPHER) *cl; /* the ones we want to use */ STACK_OF(SSL_CIPHER) *prio, *allow; int z; /* This is a bit of a hack to check for the correct packet * type the first time round. */ if (s->state == SSL2_ST_GET_CLIENT_HELLO_A) { s->first_packet=1; s->state=SSL2_ST_GET_CLIENT_HELLO_B; } p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_GET_CLIENT_HELLO_B) { i=ssl2_read(s,(char *)&(p[s->init_num]),9-s->init_num); if (i < (9-s->init_num)) return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i)); s->init_num = 9; if (*(p++) != SSL2_MT_CLIENT_HELLO) { if (p[-1] != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_READ_WRONG_PACKET_TYPE); } else SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_PEER_ERROR); return(-1); } n2s(p,i); if (i < s->version) s->version=i; n2s(p,i); s->s2->tmp.cipher_spec_length=i; n2s(p,i); s->s2->tmp.session_id_length=i; n2s(p,i); s->s2->challenge_length=i; if ( (i < SSL2_MIN_CHALLENGE_LENGTH) || (i > SSL2_MAX_CHALLENGE_LENGTH)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_INVALID_CHALLENGE_LENGTH); return(-1); } s->state=SSL2_ST_GET_CLIENT_HELLO_C; } /* SSL2_ST_GET_CLIENT_HELLO_C */ p=(unsigned char *)s->init_buf->data; len = 9 + (unsigned long)s->s2->tmp.cipher_spec_length + (unsigned long)s->s2->challenge_length + (unsigned long)s->s2->tmp.session_id_length; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_MESSAGE_TOO_LONG); return -1; } n = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),n); if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i)); if (s->msg_callback) s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-HELLO */ p += 9; /* get session-id before cipher stuff so we can get out session * structure if it is cached */ /* session-id */ if ((s->s2->tmp.session_id_length != 0) && (s->s2->tmp.session_id_length != SSL2_SSL_SESSION_ID_LENGTH)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_BAD_SSL_SESSION_ID_LENGTH); return(-1); } if (s->s2->tmp.session_id_length == 0) { if (!ssl_get_new_session(s,1)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } } else { i=ssl_get_prev_session(s,&(p[s->s2->tmp.cipher_spec_length]), s->s2->tmp.session_id_length, NULL); if (i == 1) { /* previous session */ s->hit=1; } else if (i == -1) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } else { if (s->cert == NULL) { ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_NO_CERTIFICATE_SET); return(-1); } if (!ssl_get_new_session(s,1)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } } } if (!s->hit) { cs=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.cipher_spec_length, &s->session->ciphers); if (cs == NULL) goto mem_err; cl=SSL_get_ciphers(s); if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { prio=sk_SSL_CIPHER_dup(cl); if (prio == NULL) goto mem_err; allow = cs; } else { prio = cs; allow = cl; } for (z=0; zoptions & SSL_OP_CIPHER_SERVER_PREFERENCE) { sk_SSL_CIPHER_free(s->session->ciphers); s->session->ciphers = prio; } /* s->session->ciphers should now have a list of * ciphers that are on both the client and server. * This list is ordered by the order the client sent * the ciphers or in the order of the server's preference * if SSL_OP_CIPHER_SERVER_PREFERENCE was set. */ } p+=s->s2->tmp.cipher_spec_length; /* done cipher selection */ /* session id extracted already */ p+=s->s2->tmp.session_id_length; /* challenge */ if (s->s2->challenge_length > sizeof s->s2->challenge) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); return -1; } memcpy(s->s2->challenge,p,(unsigned int)s->s2->challenge_length); return(1); mem_err: SSLerr(SSL_F_GET_CLIENT_HELLO,ERR_R_MALLOC_FAILURE); return(0); } static int server_hello(SSL *s) { unsigned char *p,*d; int n,hit; p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_SEND_SERVER_HELLO_A) { d=p+11; *(p++)=SSL2_MT_SERVER_HELLO; /* type */ hit=s->hit; *(p++)=(unsigned char)hit; #if 1 if (!hit) { if (s->session->sess_cert != NULL) /* This can't really happen because get_client_hello * has called ssl_get_new_session, which does not set * sess_cert. */ ssl_sess_cert_free(s->session->sess_cert); s->session->sess_cert = ssl_sess_cert_new(); if (s->session->sess_cert == NULL) { SSLerr(SSL_F_SERVER_HELLO, ERR_R_MALLOC_FAILURE); return(-1); } } /* If 'hit' is set, then s->sess_cert may be non-NULL or NULL, * depending on whether it survived in the internal cache * or was retrieved from an external cache. * If it is NULL, we cannot put any useful data in it anyway, * so we don't touch it. */ #else /* That's what used to be done when cert_st and sess_cert_st were * the same. */ if (!hit) { /* else add cert to session */ CRYPTO_add(&s->cert->references,1,CRYPTO_LOCK_SSL_CERT); if (s->session->sess_cert != NULL) ssl_cert_free(s->session->sess_cert); s->session->sess_cert=s->cert; } else /* We have a session id-cache hit, if the * session-id has no certificate listed against * the 'cert' structure, grab the 'old' one * listed against the SSL connection */ { if (s->session->sess_cert == NULL) { CRYPTO_add(&s->cert->references,1, CRYPTO_LOCK_SSL_CERT); s->session->sess_cert=s->cert; } } #endif if (s->cert == NULL) { ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE); SSLerr(SSL_F_SERVER_HELLO,SSL_R_NO_CERTIFICATE_SPECIFIED); return(-1); } if (hit) { *(p++)=0; /* no certificate type */ s2n(s->version,p); /* version */ s2n(0,p); /* cert len */ s2n(0,p); /* ciphers len */ } else { /* EAY EAY */ /* put certificate type */ *(p++)=SSL2_CT_X509_CERTIFICATE; s2n(s->version,p); /* version */ n=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL); s2n(n,p); /* certificate length */ i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&d); n=0; /* lets send out the ciphers we like in the * prefered order */ n=ssl_cipher_list_to_bytes(s,s->session->ciphers,d,0); d+=n; s2n(n,p); /* add cipher length */ } /* make and send conn_id */ s2n(SSL2_CONNECTION_ID_LENGTH,p); /* add conn_id length */ s->s2->conn_id_length=SSL2_CONNECTION_ID_LENGTH; if (RAND_pseudo_bytes(s->s2->conn_id,(int)s->s2->conn_id_length) <= 0) return -1; memcpy(d,s->s2->conn_id,SSL2_CONNECTION_ID_LENGTH); d+=SSL2_CONNECTION_ID_LENGTH; s->state=SSL2_ST_SEND_SERVER_HELLO_B; s->init_num=d-(unsigned char *)s->init_buf->data; s->init_off=0; } /* SSL2_ST_SEND_SERVER_HELLO_B */ /* If we are using TCP/IP, the performance is bad if we do 2 * writes without a read between them. This occurs when * Session-id reuse is used, so I will put in a buffering module */ if (s->hit) { if (!ssl_init_wbio_buffer(s,1)) return(-1); } return(ssl2_do_write(s)); } static int get_client_finished(SSL *s) { unsigned char *p; int i, n; unsigned long len; p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_GET_CLIENT_FINISHED_A) { i=ssl2_read(s,(char *)&(p[s->init_num]),1-s->init_num); if (i < 1-s->init_num) return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i)); s->init_num += i; if (*p != SSL2_MT_CLIENT_FINISHED) { if (*p != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_READ_WRONG_PACKET_TYPE); } else { SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_PEER_ERROR); /* try to read the error message */ i=ssl2_read(s,(char *)&(p[s->init_num]),3-s->init_num); return ssl2_part_read(s,SSL_F_GET_SERVER_VERIFY,i); } return(-1); } s->state=SSL2_ST_GET_CLIENT_FINISHED_B; } /* SSL2_ST_GET_CLIENT_FINISHED_B */ if (s->s2->conn_id_length > sizeof s->s2->conn_id) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_FINISHED, ERR_R_INTERNAL_ERROR); return -1; } len = 1 + (unsigned long)s->s2->conn_id_length; n = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),n); if (i < n) { return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i)); } if (s->msg_callback) s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-FINISHED */ p += 1; if (memcmp(p,s->s2->conn_id,s->s2->conn_id_length) != 0) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_CONNECTION_ID_IS_DIFFERENT); return(-1); } return(1); } static int server_verify(SSL *s) { unsigned char *p; if (s->state == SSL2_ST_SEND_SERVER_VERIFY_A) { p=(unsigned char *)s->init_buf->data; *(p++)=SSL2_MT_SERVER_VERIFY; if (s->s2->challenge_length > sizeof s->s2->challenge) { SSLerr(SSL_F_SERVER_VERIFY, ERR_R_INTERNAL_ERROR); return -1; } memcpy(p,s->s2->challenge,(unsigned int)s->s2->challenge_length); /* p+=s->s2->challenge_length; */ s->state=SSL2_ST_SEND_SERVER_VERIFY_B; s->init_num=s->s2->challenge_length+1; s->init_off=0; } return(ssl2_do_write(s)); } static int server_finish(SSL *s) { unsigned char *p; if (s->state == SSL2_ST_SEND_SERVER_FINISHED_A) { p=(unsigned char *)s->init_buf->data; *(p++)=SSL2_MT_SERVER_FINISHED; if (s->session->session_id_length > sizeof s->session->session_id) { SSLerr(SSL_F_SERVER_FINISH, ERR_R_INTERNAL_ERROR); return -1; } memcpy(p,s->session->session_id, (unsigned int)s->session->session_id_length); /* p+=s->session->session_id_length; */ s->state=SSL2_ST_SEND_SERVER_FINISHED_B; s->init_num=s->session->session_id_length+1; s->init_off=0; } /* SSL2_ST_SEND_SERVER_FINISHED_B */ return(ssl2_do_write(s)); } /* send the request and check the response */ static int request_certificate(SSL *s) { const unsigned char *cp; unsigned char *p,*p2,*buf2; unsigned char *ccd; int i,j,ctype,ret= -1; unsigned long len; X509 *x509=NULL; STACK_OF(X509) *sk=NULL; ccd=s->s2->tmp.ccl; if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_A) { p=(unsigned char *)s->init_buf->data; *(p++)=SSL2_MT_REQUEST_CERTIFICATE; *(p++)=SSL2_AT_MD5_WITH_RSA_ENCRYPTION; if (RAND_pseudo_bytes(ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH) <= 0) return -1; memcpy(p,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH); s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_B; s->init_num=SSL2_MIN_CERT_CHALLENGE_LENGTH+2; s->init_off=0; } if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_B) { i=ssl2_do_write(s); if (i <= 0) { ret=i; goto end; } s->init_num=0; s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_C; } if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_C) { p=(unsigned char *)s->init_buf->data; i=ssl2_read(s,(char *)&(p[s->init_num]),6-s->init_num); /* try to read 6 octets ... */ if (i < 3-s->init_num) /* ... but don't call ssl2_part_read now if we got at least 3 * (probably NO-CERTIFICATE-ERROR) */ { ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i); goto end; } s->init_num += i; if ((s->init_num >= 3) && (p[0] == SSL2_MT_ERROR)) { n2s(p,i); if (i != SSL2_PE_NO_CERTIFICATE) { /* not the error message we expected -- let ssl2_part_read handle it */ s->init_num -= 3; ret = ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE, 3); goto end; } if (s->msg_callback) s->msg_callback(0, s->version, 0, p, 3, s, s->msg_callback_arg); /* ERROR */ /* this is the one place where we can recover from an SSL 2.0 error */ if (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE); SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); goto end; } ret=1; goto end; } if ((*(p++) != SSL2_MT_CLIENT_CERTIFICATE) || (s->init_num < 6)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_SHORT_READ); goto end; } if (s->init_num != 6) { SSLerr(SSL_F_REQUEST_CERTIFICATE, ERR_R_INTERNAL_ERROR); goto end; } /* ok we have a response */ /* certificate type, there is only one right now. */ ctype= *(p++); if (ctype != SSL2_AT_MD5_WITH_RSA_ENCRYPTION) { ssl2_return_error(s,SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE); SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_RESPONSE_ARGUMENT); goto end; } n2s(p,i); s->s2->tmp.clen=i; n2s(p,i); s->s2->tmp.rlen=i; s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_D; } /* SSL2_ST_SEND_REQUEST_CERTIFICATE_D */ p=(unsigned char *)s->init_buf->data; len = 6 + (unsigned long)s->s2->tmp.clen + (unsigned long)s->s2->tmp.rlen; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_MESSAGE_TOO_LONG); goto end; } j = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),j); if (i < j) { ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i); goto end; } if (s->msg_callback) s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-CERTIFICATE */ p += 6; cp = p; x509=(X509 *)d2i_X509(NULL,&cp,(long)s->s2->tmp.clen); if (x509 == NULL) { SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_X509_LIB); goto msg_end; } if (((sk=sk_X509_new_null()) == NULL) || (!sk_X509_push(sk,x509))) { SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE); goto msg_end; } i=ssl_verify_cert_chain(s,sk); if (i > 0) /* we like the packet, now check the chksum */ { EVP_MD_CTX ctx; EVP_PKEY *pkey=NULL; EVP_MD_CTX_init(&ctx); if (!EVP_VerifyInit_ex(&ctx,s->ctx->rsa_md5, NULL) || !EVP_VerifyUpdate(&ctx,s->s2->key_material, s->s2->key_material_length) || !EVP_VerifyUpdate(&ctx,ccd, SSL2_MIN_CERT_CHALLENGE_LENGTH)) goto msg_end; i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL); buf2=OPENSSL_malloc((unsigned int)i); if (buf2 == NULL) { SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE); goto msg_end; } p2=buf2; i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&p2); if (!EVP_VerifyUpdate(&ctx,buf2,(unsigned int)i)) { OPENSSL_free(buf2); goto msg_end; } OPENSSL_free(buf2); pkey=X509_get_pubkey(x509); if (pkey == NULL) goto end; i=EVP_VerifyFinal(&ctx,cp,s->s2->tmp.rlen,pkey); EVP_PKEY_free(pkey); EVP_MD_CTX_cleanup(&ctx); if (i > 0) { if (s->session->peer != NULL) X509_free(s->session->peer); s->session->peer=x509; CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); s->session->verify_result = s->verify_result; ret=1; goto end; } else { SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_CHECKSUM); goto msg_end; } } else { msg_end: ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE); } end: sk_X509_free(sk); X509_free(x509); return(ret); } static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from, unsigned char *to, int padding) { RSA *rsa; int i; if ((c == NULL) || (c->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL)) { SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_NO_PRIVATEKEY); return(-1); } if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey->type != EVP_PKEY_RSA) { SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_PUBLIC_KEY_IS_NOT_RSA); return(-1); } rsa=c->pkeys[SSL_PKEY_RSA_ENC].privatekey->pkey.rsa; /* we have the public key */ i=RSA_private_decrypt(len,from,to,rsa,padding); if (i < 0) SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,ERR_R_RSA_LIB); return(i); } #else /* !OPENSSL_NO_SSL2 */ # if PEDANTIC static void *dummy=&dummy; # endif #endif Index: releng/10.1/secure/lib/libcrypto/man/d2i_X509.3 =================================================================== --- releng/10.1/secure/lib/libcrypto/man/d2i_X509.3 (revision 280267) +++ releng/10.1/secure/lib/libcrypto/man/d2i_X509.3 (revision 280268) @@ -1,369 +1,377 @@ .\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "d2i_X509 3" .TH d2i_X509 3 "2015-01-15" "1.0.1l" "OpenSSL" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio, i2d_X509_fp \- X509 encode and decode functions .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& #include \& \& X509 *d2i_X509(X509 **px, const unsigned char **in, int len); \& int i2d_X509(X509 *x, unsigned char **out); \& \& X509 *d2i_X509_bio(BIO *bp, X509 **x); \& X509 *d2i_X509_fp(FILE *fp, X509 **x); \& \& int i2d_X509_bio(BIO *bp, X509 *x); \& int i2d_X509_fp(FILE *fp, X509 *x); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" The X509 encode and decode routines encode and parse an \&\fBX509\fR structure, which represents an X509 certificate. .PP \&\fId2i_X509()\fR attempts to decode \fBlen\fR bytes at \fB*in\fR. If successful a pointer to the \fBX509\fR structure is returned. If an error occurred then \fB\s-1NULL\s0\fR is returned. If \fBpx\fR is not \fB\s-1NULL\s0\fR then the returned structure is written to \fB*px\fR. If \fB*px\fR is not \fB\s-1NULL\s0\fR then it is assumed that \fB*px\fR contains a valid \fBX509\fR structure and an attempt is made to reuse it. If the call is successful \fB*in\fR is incremented to the byte following the parsed data. .PP \&\fIi2d_X509()\fR encodes the structure pointed to by \fBx\fR into \s-1DER\s0 format. If \fBout\fR is not \fB\s-1NULL\s0\fR is writes the \s-1DER\s0 encoded data to the buffer at \fB*out\fR, and increments it to point after the data just written. If the return value is negative an error occurred, otherwise it returns the length of the encoded data. .PP For OpenSSL 0.9.7 and later if \fB*out\fR is \fB\s-1NULL\s0\fR memory will be allocated for a buffer and the encoded data written to it. In this case \fB*out\fR is not incremented and it points to the start of the data just written. .PP \&\fId2i_X509_bio()\fR is similar to \fId2i_X509()\fR except it attempts to parse data from \s-1BIO \s0\fBbp\fR. .PP \&\fId2i_X509_fp()\fR is similar to \fId2i_X509()\fR except it attempts to parse data from \s-1FILE\s0 pointer \fBfp\fR. .PP \&\fIi2d_X509_bio()\fR is similar to \fIi2d_X509()\fR except it writes the encoding of the structure \fBx\fR to \s-1BIO \s0\fBbp\fR and it returns 1 for success and 0 for failure. .PP \&\fIi2d_X509_fp()\fR is similar to \fIi2d_X509()\fR except it writes the encoding of the structure \fBx\fR to \s-1BIO \s0\fBbp\fR and it returns 1 for success and 0 for failure. .SH "NOTES" .IX Header "NOTES" The letters \fBi\fR and \fBd\fR in for example \fBi2d_X509\fR stand for \&\*(L"internal\*(R" (that is an internal C structure) and \*(L"\s-1DER\*(R".\s0 So that \&\fBi2d_X509\fR converts from internal to \s-1DER.\s0 .PP The functions can also understand \fB\s-1BER\s0\fR forms. .PP The actual X509 structure passed to \fIi2d_X509()\fR must be a valid populated \fBX509\fR structure it can \fBnot\fR simply be fed with an empty structure such as that returned by \fIX509_new()\fR. .PP The encoded data is in binary form and may contain embedded zeroes. Therefore any \s-1FILE\s0 pointers or BIOs should be opened in binary mode. Functions such as \fB\f(BIstrlen()\fB\fR will \fBnot\fR return the correct length of the encoded structure. .PP The ways that \fB*in\fR and \fB*out\fR are incremented after the operation can trap the unwary. See the \fB\s-1WARNINGS\s0\fR section for some common errors. .PP The reason for the auto increment behaviour is to reflect a typical usage of \s-1ASN1\s0 functions: after one structure is encoded or decoded another will processed after it. .SH "EXAMPLES" .IX Header "EXAMPLES" Allocate and encode the \s-1DER\s0 encoding of an X509 structure: .PP .Vb 2 \& int len; \& unsigned char *buf, *p; \& \& len = i2d_X509(x, NULL); \& \& buf = OPENSSL_malloc(len); \& \& if (buf == NULL) \& /* error */ \& \& p = buf; \& \& i2d_X509(x, &p); .Ve .PP If you are using OpenSSL 0.9.7 or later then this can be simplified to: .PP .Vb 2 \& int len; \& unsigned char *buf; \& \& buf = NULL; \& \& len = i2d_X509(x, &buf); \& \& if (len < 0) \& /* error */ .Ve .PP Attempt to decode a buffer: .PP .Vb 1 \& X509 *x; \& \& unsigned char *buf, *p; \& \& int len; \& \& /* Something to setup buf and len */ \& \& p = buf; \& \& x = d2i_X509(NULL, &p, len); \& \& if (x == NULL) \& /* Some error */ .Ve .PP Alternative technique: .PP .Vb 1 \& X509 *x; \& \& unsigned char *buf, *p; \& \& int len; \& \& /* Something to setup buf and len */ \& \& p = buf; \& \& x = NULL; \& \& if(!d2i_X509(&x, &p, len)) \& /* Some error */ .Ve .SH "WARNINGS" .IX Header "WARNINGS" The use of temporary variable is mandatory. A common mistake is to attempt to use a buffer directly as follows: .PP .Vb 2 \& int len; \& unsigned char *buf; \& \& len = i2d_X509(x, NULL); \& \& buf = OPENSSL_malloc(len); \& \& if (buf == NULL) \& /* error */ \& \& i2d_X509(x, &buf); \& \& /* Other stuff ... */ \& \& OPENSSL_free(buf); .Ve .PP This code will result in \fBbuf\fR apparently containing garbage because it was incremented after the call to point after the data just written. Also \fBbuf\fR will no longer contain the pointer allocated by \fB\f(BIOPENSSL_malloc()\fB\fR and the subsequent call to \fB\f(BIOPENSSL_free()\fB\fR may well crash. .PP The auto allocation feature (setting buf to \s-1NULL\s0) only works on OpenSSL 0.9.7 and later. Attempts to use it on earlier versions will typically cause a segmentation violation. .PP Another trap to avoid is misuse of the \fBxp\fR argument to \fB\f(BId2i_X509()\fB\fR: .PP .Vb 1 \& X509 *x; \& \& if (!d2i_X509(&x, &p, len)) \& /* Some error */ .Ve .PP This will probably crash somewhere in \fB\f(BId2i_X509()\fB\fR. The reason for this is that the variable \fBx\fR is uninitialized and an attempt will be made to interpret its (invalid) value as an \fBX509\fR structure, typically causing a segmentation violation. If \fBx\fR is set to \s-1NULL\s0 first then this will not happen. .SH "BUGS" .IX Header "BUGS" In some versions of OpenSSL the \*(L"reuse\*(R" behaviour of \fId2i_X509()\fR when \&\fB*px\fR is valid is broken and some parts of the reused structure may persist if they are not present in the new one. As a result the use of this \*(L"reuse\*(R" behaviour is strongly discouraged. .PP +Current versions of OpenSSL will not modify \fB*px\fR if an error occurs. +If parsing succeeds then \fB*px\fR is freed (if it is not \s-1NULL\s0) and then +set to the value of the newly decoded structure. As a result \fB*px\fR +\&\fBmust not\fR be allocated on the stack or an attempt will be made to +free an invalid pointer. +.PP \&\fIi2d_X509()\fR will not return an error in many versions of OpenSSL, if mandatory fields are not initialized due to a programming error then the encoded structure may contain invalid data or omit the fields entirely and will not be parsed by \fId2i_X509()\fR. This may be fixed in future so code should not assume that \fIi2d_X509()\fR will always succeed. .SH "RETURN VALUES" .IX Header "RETURN VALUES" \&\fId2i_X509()\fR, \fId2i_X509_bio()\fR and \fId2i_X509_fp()\fR return a valid \fBX509\fR structure or \fB\s-1NULL\s0\fR if an error occurs. The error code that can be obtained by -\&\fIERR_get_error\fR\|(3). +\&\fIERR_get_error\fR\|(3). If the \*(L"reuse\*(R" capability has been used +with a valid X509 structure being passed in via \fBpx\fR then the object is not +modified in the event of error. .PP \&\fIi2d_X509()\fR returns the number of bytes successfully encoded or a negative value if an error occurs. The error code can be obtained by \&\fIERR_get_error\fR\|(3). .PP \&\fIi2d_X509_bio()\fR and \fIi2d_X509_fp()\fR return 1 for success and 0 if an error occurs The error code can be obtained by \fIERR_get_error\fR\|(3). .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIERR_get_error\fR\|(3) .SH "HISTORY" .IX Header "HISTORY" d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio and i2d_X509_fp are available in all versions of SSLeay and OpenSSL. Index: releng/8.4/crypto/openssl/crypto/asn1/a_type.c =================================================================== --- releng/8.4/crypto/openssl/crypto/asn1/a_type.c (revision 280267) +++ releng/8.4/crypto/openssl/crypto/asn1/a_type.c (revision 280268) @@ -1,156 +1,159 @@ /* crypto/asn1/a_type.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include "cryptlib.h" #include #include int ASN1_TYPE_get(ASN1_TYPE *a) { if ((a->value.ptr != NULL) || (a->type == V_ASN1_NULL)) return(a->type); else return(0); } void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value) { if (a->value.ptr != NULL) { ASN1_TYPE **tmp_a = &a; ASN1_primitive_free((ASN1_VALUE **)tmp_a, NULL); } a->type=type; a->value.ptr=value; } int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value) { if (!value || (type == V_ASN1_BOOLEAN)) { void *p = (void *)value; ASN1_TYPE_set(a, type, p); } else if (type == V_ASN1_OBJECT) { ASN1_OBJECT *odup; odup = OBJ_dup(value); if (!odup) return 0; ASN1_TYPE_set(a, type, odup); } else { ASN1_STRING *sdup; sdup = ASN1_STRING_dup((ASN1_STRING *)value); if (!sdup) return 0; ASN1_TYPE_set(a, type, sdup); } return 1; } IMPLEMENT_STACK_OF(ASN1_TYPE) IMPLEMENT_ASN1_SET_OF(ASN1_TYPE) /* Returns 0 if they are equal, != 0 otherwise. */ int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b) { int result = -1; if (!a || !b || a->type != b->type) return -1; switch (a->type) { case V_ASN1_OBJECT: result = OBJ_cmp(a->value.object, b->value.object); break; + case V_ASN1_BOOLEAN: + result = a->value.boolean - b->value.boolean; + break; case V_ASN1_NULL: result = 0; /* They do not have content. */ break; case V_ASN1_INTEGER: case V_ASN1_NEG_INTEGER: case V_ASN1_ENUMERATED: case V_ASN1_NEG_ENUMERATED: case V_ASN1_BIT_STRING: case V_ASN1_OCTET_STRING: case V_ASN1_SEQUENCE: case V_ASN1_SET: case V_ASN1_NUMERICSTRING: case V_ASN1_PRINTABLESTRING: case V_ASN1_T61STRING: case V_ASN1_VIDEOTEXSTRING: case V_ASN1_IA5STRING: case V_ASN1_UTCTIME: case V_ASN1_GENERALIZEDTIME: case V_ASN1_GRAPHICSTRING: case V_ASN1_VISIBLESTRING: case V_ASN1_GENERALSTRING: case V_ASN1_UNIVERSALSTRING: case V_ASN1_BMPSTRING: case V_ASN1_UTF8STRING: case V_ASN1_OTHER: default: result = ASN1_STRING_cmp((ASN1_STRING *) a->value.ptr, (ASN1_STRING *) b->value.ptr); break; } return result; } Index: releng/8.4/crypto/openssl/crypto/asn1/tasn_dec.c =================================================================== --- releng/8.4/crypto/openssl/crypto/asn1/tasn_dec.c (revision 280267) +++ releng/8.4/crypto/openssl/crypto/asn1/tasn_dec.c (revision 280268) @@ -1,1351 +1,1376 @@ /* tasn_dec.c */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2000. */ /* ==================================================================== * Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * licensing@OpenSSL.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ #include #include #include #include #include #include #include static int asn1_check_eoc(const unsigned char **in, long len); static int asn1_find_end(const unsigned char **in, long len, char inf); static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, char inf, int tag, int aclass, int depth); static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen); static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst, const unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx); static int asn1_template_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx); static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx); static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx); /* Table to convert tags to bit values, used for MSTRING type */ static const unsigned long tag2bit[32] = { 0, 0, 0, B_ASN1_BIT_STRING, /* tags 0 - 3 */ B_ASN1_OCTET_STRING, 0, 0, B_ASN1_UNKNOWN,/* tags 4- 7 */ B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN,/* tags 8-11 */ B_ASN1_UTF8STRING,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,/* tags 12-15 */ B_ASN1_SEQUENCE,0,B_ASN1_NUMERICSTRING,B_ASN1_PRINTABLESTRING, /* tags 16-19 */ B_ASN1_T61STRING,B_ASN1_VIDEOTEXSTRING,B_ASN1_IA5STRING, /* tags 20-22 */ B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME, /* tags 23-24 */ B_ASN1_GRAPHICSTRING,B_ASN1_ISO64STRING,B_ASN1_GENERALSTRING, /* tags 25-27 */ B_ASN1_UNIVERSALSTRING,B_ASN1_UNKNOWN,B_ASN1_BMPSTRING,B_ASN1_UNKNOWN, /* tags 28-31 */ }; unsigned long ASN1_tag2bit(int tag) { if ((tag < 0) || (tag > 30)) return 0; return tag2bit[tag]; } /* Macro to initialize and invalidate the cache */ #define asn1_tlc_clear(c) if (c) (c)->valid = 0 /* Decode an ASN1 item, this currently behaves just * like a standard 'd2i' function. 'in' points to * a buffer to read the data from, in future we will * have more advanced versions that can input data * a piece at a time and this will simply be a special * case. */ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it) - { +{ ASN1_TLC c; ASN1_VALUE *ptmpval = NULL; - if (!pval) - pval = &ptmpval; c.valid = 0; - if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0) - return *pval; - return NULL; + if (pval && *pval && it->itype == ASN1_ITYPE_PRIMITIVE) + ptmpval = *pval; + + if (ASN1_item_ex_d2i(&ptmpval, in, len, it, -1, 0, 0, &c) > 0) { + if (pval && it->itype != ASN1_ITYPE_PRIMITIVE) { + if (*pval) + ASN1_item_free(*pval, it); + *pval = ptmpval; + } + return ptmpval; } + return NULL; +} int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt) { ASN1_TLC c; c.valid = 0; return asn1_template_ex_d2i(pval, in, len, tt, 0, &c); } /* Decode an item, taking care of IMPLICIT tagging, if any. * If 'opt' set and tag mismatch return -1 to handle OPTIONAL */ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx) { const ASN1_TEMPLATE *tt, *errtt = NULL; const ASN1_COMPAT_FUNCS *cf; const ASN1_EXTERN_FUNCS *ef; const ASN1_AUX *aux = it->funcs; ASN1_aux_cb *asn1_cb; const unsigned char *p = NULL, *q; unsigned char *wp=NULL; /* BIG FAT WARNING! BREAKS CONST WHERE USED */ unsigned char imphack = 0, oclass; char seq_eoc, seq_nolen, cst, isopt; long tmplen; int i; int otag; int ret = 0; ASN1_VALUE **pchptr, *ptmpval; if (!pval) return 0; if (aux && aux->asn1_cb) asn1_cb = aux->asn1_cb; else asn1_cb = 0; switch(it->itype) { case ASN1_ITYPE_PRIMITIVE: if (it->templates) { /* tagging or OPTIONAL is currently illegal on an item * template because the flags can't get passed down. * In practice this isn't a problem: we include the * relevant flags from the item template in the * template itself. */ if ((tag != -1) || opt) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE); goto err; } return asn1_template_ex_d2i(pval, in, len, it->templates, opt, ctx); } return asn1_d2i_ex_primitive(pval, in, len, it, tag, aclass, opt, ctx); break; case ASN1_ITYPE_MSTRING: p = *in; /* Just read in tag and class */ ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, &p, len, -1, 0, 1, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } /* Must be UNIVERSAL class */ if (oclass != V_ASN1_UNIVERSAL) { /* If OPTIONAL, assume this is OK */ if (opt) return -1; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_NOT_UNIVERSAL); goto err; } /* Check tag matches bit map */ if (!(ASN1_tag2bit(otag) & it->utype)) { /* If OPTIONAL, assume this is OK */ if (opt) return -1; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_WRONG_TAG); goto err; } return asn1_d2i_ex_primitive(pval, in, len, it, otag, 0, 0, ctx); case ASN1_ITYPE_EXTERN: /* Use new style d2i */ ef = it->funcs; return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx); case ASN1_ITYPE_COMPAT: /* we must resort to old style evil hackery */ cf = it->funcs; /* If OPTIONAL see if it is there */ if (opt) { int exptag; p = *in; if (tag == -1) exptag = it->utype; else exptag = tag; /* Don't care about anything other than presence * of expected tag */ ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL, &p, len, exptag, aclass, 1, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } if (ret == -1) return -1; } /* This is the old style evil hack IMPLICIT handling: * since the underlying code is expecting a tag and * class other than the one present we change the * buffer temporarily then change it back afterwards. * This doesn't and never did work for tags > 30. * * Yes this is *horrible* but it is only needed for * old style d2i which will hopefully not be around * for much longer. * FIXME: should copy the buffer then modify it so * the input buffer can be const: we should *always* * copy because the old style d2i might modify the * buffer. */ if (tag != -1) { wp = *(unsigned char **)in; imphack = *wp; if (p == NULL) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } *wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED) | it->utype); } ptmpval = cf->asn1_d2i(pval, in, len); if (tag != -1) *wp = imphack; if (ptmpval) return 1; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; case ASN1_ITYPE_CHOICE: if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it)) goto auxerr; - /* Allocate structure */ - if (!*pval && !ASN1_item_ex_new(pval, it)) - { + if (*pval) { + /* Free up and zero CHOICE value if initialised */ + i = asn1_get_choice_selector(pval, it); + if ((i >= 0) && (i < it->tcount)) { + tt = it->templates + i; + pchptr = asn1_get_field_ptr(pval, tt); + ASN1_template_free(pchptr, tt); + asn1_set_choice_selector(pval, -1, it); + } + } else if (!ASN1_item_ex_new(pval, it)) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; - } + } /* CHOICE type, try each possibility in turn */ p = *in; for (i = 0, tt=it->templates; i < it->tcount; i++, tt++) { pchptr = asn1_get_field_ptr(pval, tt); /* We mark field as OPTIONAL so its absence * can be recognised. */ ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx); /* If field not present, try the next one */ if (ret == -1) continue; /* If positive return, read OK, break loop */ if (ret > 0) break; /* Otherwise must be an ASN1 parsing error */ errtt = tt; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } /* Did we fall off the end without reading anything? */ if (i == it->tcount) { /* If OPTIONAL, this is OK */ if (opt) { /* Free and zero it */ ASN1_item_ex_free(pval, it); return -1; } ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_NO_MATCHING_CHOICE_TYPE); goto err; } asn1_set_choice_selector(pval, i, it); *in = p; if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it)) goto auxerr; return 1; case ASN1_ITYPE_NDEF_SEQUENCE: case ASN1_ITYPE_SEQUENCE: p = *in; tmplen = len; /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ if (tag == -1) { tag = V_ASN1_SEQUENCE; aclass = V_ASN1_UNIVERSAL; } /* Get SEQUENCE length and update len, p */ ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst, &p, len, tag, aclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if (ret == -1) return -1; if (aux && (aux->flags & ASN1_AFLG_BROKEN)) { len = tmplen - (p - *in); seq_nolen = 1; } /* If indefinite we don't do a length check */ else seq_nolen = seq_eoc; if (!cst) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_NOT_CONSTRUCTED); goto err; } if (!*pval && !ASN1_item_ex_new(pval, it)) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it)) goto auxerr; + + /* Free up and zero any ADB found */ + for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { + if (tt->flags & ASN1_TFLG_ADB_MASK) { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + pseqval = asn1_get_field_ptr(pval, seqtt); + ASN1_template_free(pseqval, seqtt); + } + } /* Get each field entry */ for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { const ASN1_TEMPLATE *seqtt; ASN1_VALUE **pseqval; seqtt = asn1_do_adb(pval, tt, 1); if (!seqtt) goto err; pseqval = asn1_get_field_ptr(pval, seqtt); /* Have we ran out of data? */ if (!len) break; q = p; if (asn1_check_eoc(&p, len)) { if (!seq_eoc) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_UNEXPECTED_EOC); goto err; } len -= p - q; seq_eoc = 0; q = p; break; } /* This determines the OPTIONAL flag value. The field * cannot be omitted if it is the last of a SEQUENCE * and there is still data to be read. This isn't * strictly necessary but it increases efficiency in * some cases. */ if (i == (it->tcount - 1)) isopt = 0; else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL); /* attempt to read in field, allowing each to be * OPTIONAL */ ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx); if (!ret) { errtt = seqtt; goto err; } else if (ret == -1) { /* OPTIONAL component absent. * Free and zero the field. */ ASN1_template_free(pseqval, seqtt); continue; } /* Update length */ len -= p - q; } /* Check for EOC if expecting one */ if (seq_eoc && !asn1_check_eoc(&p, len)) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MISSING_EOC); goto err; } /* Check all data read */ if (!seq_nolen && len) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_LENGTH_MISMATCH); goto err; } /* If we get here we've got no more data in the SEQUENCE, * however we may not have read all fields so check all * remaining are OPTIONAL and clear any that are. */ for (; i < it->tcount; tt++, i++) { const ASN1_TEMPLATE *seqtt; seqtt = asn1_do_adb(pval, tt, 1); if (!seqtt) goto err; if (seqtt->flags & ASN1_TFLG_OPTIONAL) { ASN1_VALUE **pseqval; pseqval = asn1_get_field_ptr(pval, seqtt); ASN1_template_free(pseqval, seqtt); } else { errtt = seqtt; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_FIELD_MISSING); goto err; } } /* Save encoding */ if (!asn1_enc_save(pval, *in, p - *in, it)) goto auxerr; *in = p; if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it)) goto auxerr; return 1; default: return 0; } auxerr: ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_AUX_ERROR); err: ASN1_item_ex_free(pval, it); if (errtt) ERR_add_error_data(4, "Field=", errtt->field_name, ", Type=", it->sname); else ERR_add_error_data(2, "Type=", it->sname); return 0; } /* Templates are handled with two separate functions. * One handles any EXPLICIT tag and the other handles the rest. */ static int asn1_template_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx) { int flags, aclass; int ret; long len; const unsigned char *p, *q; char exp_eoc; if (!val) return 0; flags = tt->flags; aclass = flags & ASN1_TFLG_TAG_CLASS; p = *in; /* Check if EXPLICIT tag expected */ if (flags & ASN1_TFLG_EXPTAG) { char cst; /* Need to work out amount of data available to the inner * content and where it starts: so read in EXPLICIT header to * get the info. */ ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst, &p, inlen, tt->tag, aclass, opt, ctx); q = p; if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR); return 0; } else if (ret == -1) return -1; if (!cst) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED); return 0; } /* We've found the field so it can't be OPTIONAL now */ ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR); return 0; } /* We read the field in OK so update length */ len -= p - q; if (exp_eoc) { /* If NDEF we must have an EOC here */ if (!asn1_check_eoc(&p, len)) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_MISSING_EOC); goto err; } } else { /* Otherwise we must hit the EXPLICIT tag end or its * an error */ if (len) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_EXPLICIT_LENGTH_MISMATCH); goto err; } } } else return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx); *in = p; return 1; err: ASN1_template_free(val, tt); return 0; } static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx) { int flags, aclass; int ret; const unsigned char *p, *q; if (!val) return 0; flags = tt->flags; aclass = flags & ASN1_TFLG_TAG_CLASS; p = *in; q = p; if (flags & ASN1_TFLG_SK_MASK) { /* SET OF, SEQUENCE OF */ int sktag, skaclass; char sk_eoc; /* First work out expected inner tag value */ if (flags & ASN1_TFLG_IMPTAG) { sktag = tt->tag; skaclass = aclass; } else { skaclass = V_ASN1_UNIVERSAL; if (flags & ASN1_TFLG_SET_OF) sktag = V_ASN1_SET; else sktag = V_ASN1_SEQUENCE; } /* Get the tag */ ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL, &p, len, sktag, skaclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); return 0; } else if (ret == -1) return -1; if (!*val) *val = (ASN1_VALUE *)sk_new_null(); else { /* We've got a valid STACK: free up any items present */ STACK *sktmp = (STACK *)*val; ASN1_VALUE *vtmp; while(sk_num(sktmp) > 0) { vtmp = (ASN1_VALUE *)sk_pop(sktmp); ASN1_item_ex_free(&vtmp, ASN1_ITEM_ptr(tt->item)); } } if (!*val) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_MALLOC_FAILURE); goto err; } /* Read as many items as we can */ while(len > 0) { ASN1_VALUE *skfield; q = p; /* See if EOC found */ if (asn1_check_eoc(&p, len)) { if (!sk_eoc) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1_R_UNEXPECTED_EOC); goto err; } len -= p - q; sk_eoc = 0; break; } skfield = NULL; if (!ASN1_item_ex_d2i(&skfield, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } len -= p - q; if (!sk_push((STACK *)*val, (char *)skfield)) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_MALLOC_FAILURE); goto err; } } if (sk_eoc) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1_R_MISSING_EOC); goto err; } } else if (flags & ASN1_TFLG_IMPTAG) { /* IMPLICIT tagging */ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if (ret == -1) return -1; } else { /* Nothing special */ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if (ret == -1) return -1; } *in = p; return 1; err: ASN1_template_free(val, tt); return 0; } static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx) { int ret = 0, utype; long plen; char cst, inf, free_cont = 0; const unsigned char *p; BUF_MEM buf; const unsigned char *cont = NULL; long len; if (!pval) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_NULL); return 0; /* Should never happen */ } if (it->itype == ASN1_ITYPE_MSTRING) { utype = tag; tag = -1; } else utype = it->utype; if (utype == V_ASN1_ANY) { /* If type is ANY need to figure out type from tag */ unsigned char oclass; if (tag >= 0) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_TAGGED_ANY); return 0; } if (opt) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_OPTIONAL_ANY); return 0; } p = *in; ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL, &p, inlen, -1, 0, 0, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR); return 0; } if (oclass != V_ASN1_UNIVERSAL) utype = V_ASN1_OTHER; } if (tag == -1) { tag = utype; aclass = V_ASN1_UNIVERSAL; } p = *in; /* Check header */ ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst, &p, inlen, tag, aclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR); return 0; } else if (ret == -1) return -1; ret = 0; /* SEQUENCE, SET and "OTHER" are left in encoded form */ if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) { /* Clear context cache for type OTHER because the auto clear * when we have a exact match wont work */ if (utype == V_ASN1_OTHER) { asn1_tlc_clear(ctx); } /* SEQUENCE and SET must be constructed */ else if (!cst) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_TYPE_NOT_CONSTRUCTED); return 0; } cont = *in; /* If indefinite length constructed find the real end */ if (inf) { if (!asn1_find_end(&p, plen, inf)) goto err; len = p - cont; } else { len = p - cont + plen; p += plen; buf.data = NULL; } } else if (cst) { if (utype == V_ASN1_NULL || utype == V_ASN1_BOOLEAN || utype == V_ASN1_OBJECT || utype == V_ASN1_INTEGER || utype == V_ASN1_ENUMERATED) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_TYPE_NOT_PRIMITIVE); return 0; } buf.length = 0; buf.max = 0; buf.data = NULL; /* Should really check the internal tags are correct but * some things may get this wrong. The relevant specs * say that constructed string types should be OCTET STRINGs * internally irrespective of the type. So instead just check * for UNIVERSAL class and ignore the tag. */ if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) { free_cont = 1; goto err; } len = buf.length; /* Append a final null to string */ if (!BUF_MEM_grow_clean(&buf, len + 1)) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE); return 0; } buf.data[len] = 0; cont = (const unsigned char *)buf.data; free_cont = 1; } else { cont = p; len = plen; p += plen; } /* We now have content length and type: translate into a structure */ if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it)) goto err; *in = p; ret = 1; err: if (free_cont && buf.data) OPENSSL_free(buf.data); return ret; } /* Translate ASN1 content octets into a structure */ int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it) { ASN1_VALUE **opval = NULL; ASN1_STRING *stmp; ASN1_TYPE *typ = NULL; int ret = 0; const ASN1_PRIMITIVE_FUNCS *pf; ASN1_INTEGER **tint; pf = it->funcs; if (pf && pf->prim_c2i) return pf->prim_c2i(pval, cont, len, utype, free_cont, it); /* If ANY type clear type and set pointer to internal value */ if (it->utype == V_ASN1_ANY) { if (!*pval) { typ = ASN1_TYPE_new(); if (typ == NULL) goto err; *pval = (ASN1_VALUE *)typ; } else typ = (ASN1_TYPE *)*pval; if (utype != typ->type) ASN1_TYPE_set(typ, utype, NULL); opval = pval; pval = &typ->value.asn1_value; } switch(utype) { case V_ASN1_OBJECT: if (!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len)) goto err; break; case V_ASN1_NULL: if (len) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_NULL_IS_WRONG_LENGTH); goto err; } *pval = (ASN1_VALUE *)1; break; case V_ASN1_BOOLEAN: if (len != 1) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_BOOLEAN_IS_WRONG_LENGTH); goto err; } else { ASN1_BOOLEAN *tbool; tbool = (ASN1_BOOLEAN *)pval; *tbool = *cont; } break; case V_ASN1_BIT_STRING: if (!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len)) goto err; break; case V_ASN1_INTEGER: case V_ASN1_NEG_INTEGER: case V_ASN1_ENUMERATED: case V_ASN1_NEG_ENUMERATED: tint = (ASN1_INTEGER **)pval; if (!c2i_ASN1_INTEGER(tint, &cont, len)) goto err; /* Fixup type to match the expected form */ (*tint)->type = utype | ((*tint)->type & V_ASN1_NEG); break; case V_ASN1_OCTET_STRING: case V_ASN1_NUMERICSTRING: case V_ASN1_PRINTABLESTRING: case V_ASN1_T61STRING: case V_ASN1_VIDEOTEXSTRING: case V_ASN1_IA5STRING: case V_ASN1_UTCTIME: case V_ASN1_GENERALIZEDTIME: case V_ASN1_GRAPHICSTRING: case V_ASN1_VISIBLESTRING: case V_ASN1_GENERALSTRING: case V_ASN1_UNIVERSALSTRING: case V_ASN1_BMPSTRING: case V_ASN1_UTF8STRING: case V_ASN1_OTHER: case V_ASN1_SET: case V_ASN1_SEQUENCE: default: if (utype == V_ASN1_BMPSTRING && (len & 1)) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_BMPSTRING_IS_WRONG_LENGTH); goto err; } if (utype == V_ASN1_UNIVERSALSTRING && (len & 3)) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH); goto err; } /* All based on ASN1_STRING and handled the same */ if (!*pval) { stmp = ASN1_STRING_type_new(utype); if (!stmp) { ASN1err(ASN1_F_ASN1_EX_C2I, ERR_R_MALLOC_FAILURE); goto err; } *pval = (ASN1_VALUE *)stmp; } else { stmp = (ASN1_STRING *)*pval; stmp->type = utype; } /* If we've already allocated a buffer use it */ if (*free_cont) { if (stmp->data) OPENSSL_free(stmp->data); stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */ stmp->length = len; *free_cont = 0; } else { if (!ASN1_STRING_set(stmp, cont, len)) { ASN1err(ASN1_F_ASN1_EX_C2I, ERR_R_MALLOC_FAILURE); ASN1_STRING_free(stmp); *pval = NULL; goto err; } } break; } /* If ASN1_ANY and NULL type fix up value */ if (typ && (utype == V_ASN1_NULL)) typ->value.ptr = NULL; ret = 1; err: if (!ret) { ASN1_TYPE_free(typ); if (opval) *opval = NULL; } return ret; } /* This function finds the end of an ASN1 structure when passed its maximum * length, whether it is indefinite length and a pointer to the content. * This is more efficient than calling asn1_collect because it does not * recurse on each indefinite length header. */ static int asn1_find_end(const unsigned char **in, long len, char inf) { int expected_eoc; long plen; const unsigned char *p = *in, *q; /* If not indefinite length constructed just add length */ if (inf == 0) { *in += len; return 1; } expected_eoc = 1; /* Indefinite length constructed form. Find the end when enough EOCs * are found. If more indefinite length constructed headers * are encountered increment the expected eoc count otherwise just * skip to the end of the data. */ while (len > 0) { if(asn1_check_eoc(&p, len)) { expected_eoc--; if (expected_eoc == 0) break; len -= 2; continue; } q = p; /* Just read in a header: only care about the length */ if(!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len, -1, 0, 0, NULL)) { ASN1err(ASN1_F_ASN1_FIND_END, ERR_R_NESTED_ASN1_ERROR); return 0; } if (inf) expected_eoc++; else p += plen; len -= p - q; } if (expected_eoc) { ASN1err(ASN1_F_ASN1_FIND_END, ASN1_R_MISSING_EOC); return 0; } *in = p; return 1; } /* This function collects the asn1 data from a constructred string * type into a buffer. The values of 'in' and 'len' should refer * to the contents of the constructed type and 'inf' should be set * if it is indefinite length. */ #ifndef ASN1_MAX_STRING_NEST /* This determines how many levels of recursion are permitted in ASN1 * string types. If it is not limited stack overflows can occur. If set * to zero no recursion is allowed at all. Although zero should be adequate * examples exist that require a value of 1. So 5 should be more than enough. */ #define ASN1_MAX_STRING_NEST 5 #endif static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, char inf, int tag, int aclass, int depth) { const unsigned char *p, *q; long plen; char cst, ininf; p = *in; inf &= 1; /* If no buffer and not indefinite length constructed just pass over * the encoded data */ if (!buf && !inf) { *in += len; return 1; } while(len > 0) { q = p; /* Check for EOC */ if (asn1_check_eoc(&p, len)) { /* EOC is illegal outside indefinite length * constructed form */ if (!inf) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_UNEXPECTED_EOC); return 0; } inf = 0; break; } if (!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p, len, tag, aclass, 0, NULL)) { ASN1err(ASN1_F_ASN1_COLLECT, ERR_R_NESTED_ASN1_ERROR); return 0; } /* If indefinite length constructed update max length */ if (cst) { if (depth >= ASN1_MAX_STRING_NEST) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_NESTED_ASN1_STRING); return 0; } if (!asn1_collect(buf, &p, plen, ininf, tag, aclass, depth + 1)) return 0; } else if (plen && !collect_data(buf, &p, plen)) return 0; len -= p - q; } if (inf) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_MISSING_EOC); return 0; } *in = p; return 1; } static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen) { int len; if (buf) { len = buf->length; if (!BUF_MEM_grow_clean(buf, len + plen)) { ASN1err(ASN1_F_COLLECT_DATA, ERR_R_MALLOC_FAILURE); return 0; } memcpy(buf->data + len, *p, plen); } *p += plen; return 1; } /* Check for ASN1 EOC and swallow it if found */ static int asn1_check_eoc(const unsigned char **in, long len) { const unsigned char *p; if (len < 2) return 0; p = *in; if (!p[0] && !p[1]) { *in += 2; return 1; } return 0; } /* Check an ASN1 tag and length: a bit like ASN1_get_object * but it sets the length for indefinite length constructed * form, we don't know the exact length but we can set an * upper bound to the amount of data available minus the * header length just read. */ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst, const unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx) { int i; int ptag, pclass; long plen; const unsigned char *p, *q; p = *in; q = p; if (ctx && ctx->valid) { i = ctx->ret; plen = ctx->plen; pclass = ctx->pclass; ptag = ctx->ptag; p += ctx->hdrlen; } else { i = ASN1_get_object(&p, &plen, &ptag, &pclass, len); if (ctx) { ctx->ret = i; ctx->plen = plen; ctx->pclass = pclass; ctx->ptag = ptag; ctx->hdrlen = p - q; ctx->valid = 1; /* If definite length, and no error, length + * header can't exceed total amount of data available. */ if (!(i & 0x81) && ((plen + ctx->hdrlen) > len)) { ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_TOO_LONG); asn1_tlc_clear(ctx); return 0; } } } if (i & 0x80) { ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_BAD_OBJECT_HEADER); asn1_tlc_clear(ctx); return 0; } if (exptag >= 0) { if ((exptag != ptag) || (expclass != pclass)) { /* If type is OPTIONAL, not an error: * indicate missing type. */ if (opt) return -1; asn1_tlc_clear(ctx); ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG); return 0; } /* We have a tag and class match: * assume we are going to do something with it */ asn1_tlc_clear(ctx); } if (i & 1) plen = len - (p - q); if (inf) *inf = i & 1; if (cst) *cst = i & V_ASN1_CONSTRUCTED; if (olen) *olen = plen; if (oclass) *oclass = pclass; if (otag) *otag = ptag; *in = p; return 1; } Index: releng/8.4/crypto/openssl/crypto/pkcs7/pk7_doit.c =================================================================== --- releng/8.4/crypto/openssl/crypto/pkcs7/pk7_doit.c (revision 280267) +++ releng/8.4/crypto/openssl/crypto/pkcs7/pk7_doit.c (revision 280268) @@ -1,1177 +1,1233 @@ /* crypto/pkcs7/pk7_doit.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include "cryptlib.h" #include #include #include #include #include static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, void *value); static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid); static int PKCS7_type_is_other(PKCS7* p7) { int isOther=1; int nid=OBJ_obj2nid(p7->type); switch( nid ) { case NID_pkcs7_data: case NID_pkcs7_signed: case NID_pkcs7_enveloped: case NID_pkcs7_signedAndEnveloped: case NID_pkcs7_digest: case NID_pkcs7_encrypted: isOther=0; break; default: isOther=1; } return isOther; } static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7) { if ( PKCS7_type_is_data(p7)) return p7->d.data; if ( PKCS7_type_is_other(p7) && p7->d.other && (p7->d.other->type == V_ASN1_OCTET_STRING)) return p7->d.other->value.octet_string; return NULL; } static int PKCS7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) { BIO *btmp; const EVP_MD *md; if ((btmp=BIO_new(BIO_f_md())) == NULL) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB); goto err; } md=EVP_get_digestbyobj(alg->algorithm); if (md == NULL) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,PKCS7_R_UNKNOWN_DIGEST_TYPE); goto err; } BIO_set_md(btmp,md); if (*pbio == NULL) *pbio=btmp; else if (!BIO_push(*pbio,btmp)) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB); goto err; } btmp=NULL; return 1; err: if (btmp) BIO_free(btmp); return 0; } BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { int i; BIO *out=NULL,*btmp=NULL; X509_ALGOR *xa = NULL; const EVP_CIPHER *evp_cipher=NULL; STACK_OF(X509_ALGOR) *md_sk=NULL; STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; X509_ALGOR *xalg=NULL; PKCS7_RECIP_INFO *ri=NULL; EVP_PKEY *pkey; ASN1_OCTET_STRING *os=NULL; + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_INVALID_NULL_POINTER); + return NULL; + } + /* + * The content field in the PKCS7 ContentInfo is optional, but that really + * only applies to inner content (precisely, detached signatures). + * + * When reading content, missing outer content is therefore treated as an + * error. + * + * When creating content, PKCS7_content_new() must be called before + * calling this method, so a NULL p7->d is always an error. + */ + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_NO_CONTENT); + return NULL; + } + i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signed: md_sk=p7->d.sign->md_algs; os = PKCS7_get_octet_string(p7->d.sign->contents); break; case NID_pkcs7_signedAndEnveloped: rsk=p7->d.signed_and_enveloped->recipientinfo; md_sk=p7->d.signed_and_enveloped->md_algs; xalg=p7->d.signed_and_enveloped->enc_data->algorithm; evp_cipher=p7->d.signed_and_enveloped->enc_data->cipher; if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED); goto err; } break; case NID_pkcs7_enveloped: rsk=p7->d.enveloped->recipientinfo; xalg=p7->d.enveloped->enc_data->algorithm; evp_cipher=p7->d.enveloped->enc_data->cipher; if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED); goto err; } break; case NID_pkcs7_digest: xa = p7->d.digest->md; os = PKCS7_get_octet_string(p7->d.digest->contents); break; default: PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } for (i=0; ialgorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher)); if (ivlen > 0) if (RAND_pseudo_bytes(iv,ivlen) <= 0) goto err; if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1)<=0) goto err; if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0) goto err; if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0) goto err; if (ivlen > 0) { if (xalg->parameter == NULL) { xalg->parameter = ASN1_TYPE_new(); if (xalg->parameter == NULL) goto err; } if(EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0) goto err; } /* Lets do the pub key stuff :-) */ max=0; for (i=0; icert == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_MISSING_CERIPEND_INFO); goto err; } if ((pkey=X509_get_pubkey(ri->cert)) == NULL) goto err; jj=EVP_PKEY_size(pkey); EVP_PKEY_free(pkey); if (max < jj) max=jj; } if ((tmp=(unsigned char *)OPENSSL_malloc(max)) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_MALLOC_FAILURE); goto err; } for (i=0; icert)) == NULL) goto err; jj=EVP_PKEY_encrypt(tmp,key,keylen,pkey); EVP_PKEY_free(pkey); if (jj <= 0) { PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_EVP_LIB); OPENSSL_free(tmp); goto err; } if (!M_ASN1_OCTET_STRING_set(ri->enc_key,tmp,jj)) { PKCS7err(PKCS7_F_PKCS7_DATAINIT, ERR_R_MALLOC_FAILURE); OPENSSL_free(tmp); goto err; } } OPENSSL_free(tmp); OPENSSL_cleanse(key, keylen); if (out == NULL) out=btmp; else BIO_push(out,btmp); btmp=NULL; } if (bio == NULL) { if (PKCS7_is_detached(p7)) bio=BIO_new(BIO_s_null()); else if (os && os->length > 0) bio = BIO_new_mem_buf(os->data, os->length); if(bio == NULL) { bio=BIO_new(BIO_s_mem()); if (bio == NULL) goto err; BIO_set_mem_eof_return(bio,0); } } BIO_push(out,bio); bio=NULL; if (0) { err: if (out != NULL) BIO_free_all(out); if (btmp != NULL) BIO_free_all(btmp); out=NULL; } return(out); } static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert) { int ret; ret = X509_NAME_cmp(ri->issuer_and_serial->issuer, pcert->cert_info->issuer); if (ret) return ret; return M_ASN1_INTEGER_cmp(pcert->cert_info->serialNumber, ri->issuer_and_serial->serial); } /* int */ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) { int i,j; BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL; unsigned char *tmp=NULL; X509_ALGOR *xa; ASN1_OCTET_STRING *data_body=NULL; const EVP_MD *evp_md; const EVP_CIPHER *evp_cipher=NULL; EVP_CIPHER_CTX *evp_ctx=NULL; X509_ALGOR *enc_alg=NULL; STACK_OF(X509_ALGOR) *md_sk=NULL; STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; PKCS7_RECIP_INFO *ri=NULL; + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER); + return NULL; + } + + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); + return NULL; + } + i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signed: data_body=PKCS7_get_octet_string(p7->d.sign->contents); md_sk=p7->d.sign->md_algs; break; case NID_pkcs7_signedAndEnveloped: rsk=p7->d.signed_and_enveloped->recipientinfo; md_sk=p7->d.signed_and_enveloped->md_algs; data_body=p7->d.signed_and_enveloped->enc_data->enc_data; enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm; evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } break; case NID_pkcs7_enveloped: rsk=p7->d.enveloped->recipientinfo; enc_alg=p7->d.enveloped->enc_data->algorithm; data_body=p7->d.enveloped->enc_data->enc_data; evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } break; default: PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } /* We will be checking the signature */ if (md_sk != NULL) { for (i=0; ialgorithm); evp_md=EVP_get_digestbynid(j); if (evp_md == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE); goto err; } BIO_set_md(btmp,evp_md); if (out == NULL) out=btmp; else BIO_push(out,btmp); btmp=NULL; } } if (evp_cipher != NULL) { #if 0 unsigned char key[EVP_MAX_KEY_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char *p; int keylen,ivlen; int max; X509_OBJECT ret; #endif unsigned char *tkey = NULL; int tkeylen; int jj; if ((etmp=BIO_new(BIO_f_cipher())) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); goto err; } /* It was encrypted, we need to decrypt the secret key * with the private key */ /* Find the recipientInfo which matches the passed certificate * (if any) */ if (pcert) { for (i=0; ienc_key), M_ASN1_STRING_length(ri->enc_key), pkey); if (tret > 0) { memcpy(tmp, tmp2, tret); OPENSSL_cleanse(tmp2, tret); jj = tret; } ERR_clear_error(); } OPENSSL_free(tmp2); } else { jj=EVP_PKEY_decrypt(tmp, M_ASN1_STRING_data(ri->enc_key), M_ASN1_STRING_length(ri->enc_key), pkey); ERR_clear_error(); } evp_ctx=NULL; BIO_get_cipher_ctx(etmp,&evp_ctx); if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0) goto err; if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0) goto err; /* Generate random key to counter MMA */ tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx); tkey = OPENSSL_malloc(tkeylen); if (!tkey) goto err; if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0) goto err; /* If we have no key use random key */ if (jj <= 0) { OPENSSL_free(tmp); jj = tkeylen; tmp = tkey; tkey = NULL; } if (jj != tkeylen) { /* Some S/MIME clients don't use the same key * and effective key length. The key length is * determined by the size of the decrypted RSA key. */ if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, jj)) { /* As MMA defence use random key instead */ OPENSSL_cleanse(tmp, jj); OPENSSL_free(tmp); jj = tkeylen; tmp = tkey; tkey = NULL; } } ERR_clear_error(); if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0) goto err; OPENSSL_cleanse(tmp,jj); if (tkey) { OPENSSL_cleanse(tkey, tkeylen); OPENSSL_free(tkey); } if (out == NULL) out=etmp; else BIO_push(out,etmp); etmp=NULL; } #if 1 if (PKCS7_is_detached(p7) || (in_bio != NULL)) { bio=in_bio; } else { #if 0 bio=BIO_new(BIO_s_mem()); /* We need to set this so that when we have read all * the data, the encrypt BIO, if present, will read * EOF and encode the last few bytes */ BIO_set_mem_eof_return(bio,0); if (data_body->length > 0) BIO_write(bio,(char *)data_body->data,data_body->length); #else if (data_body->length > 0) bio = BIO_new_mem_buf(data_body->data,data_body->length); else { bio=BIO_new(BIO_s_mem()); BIO_set_mem_eof_return(bio,0); } if (bio == NULL) goto err; #endif } BIO_push(out,bio); bio=NULL; #endif if (0) { err: if (out != NULL) BIO_free_all(out); if (btmp != NULL) BIO_free_all(btmp); if (etmp != NULL) BIO_free_all(etmp); if (bio != NULL) BIO_free_all(bio); out=NULL; } if (tmp != NULL) OPENSSL_free(tmp); return(out); } static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { for (;;) { bio=BIO_find_type(bio,BIO_TYPE_MD); if (bio == NULL) { PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); return NULL; } BIO_get_md_ctx(bio,pmd); if (*pmd == NULL) { PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,ERR_R_INTERNAL_ERROR); return NULL; } if (EVP_MD_CTX_type(*pmd) == nid) return bio; bio=BIO_next(bio); } return NULL; } int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { int ret=0; int i,j; BIO *btmp; BUF_MEM *buf_mem=NULL; BUF_MEM *buf=NULL; PKCS7_SIGNER_INFO *si; EVP_MD_CTX *mdc,ctx_tmp; STACK_OF(X509_ATTRIBUTE) *sk; STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL; ASN1_OCTET_STRING *os=NULL; + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_INVALID_NULL_POINTER); + return 0; + } + + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_NO_CONTENT); + return 0; + } + EVP_MD_CTX_init(&ctx_tmp); i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signedAndEnveloped: /* XXXXXXXXXXXXXXXX */ si_sk=p7->d.signed_and_enveloped->signer_info; if (!(os=M_ASN1_OCTET_STRING_new())) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE); goto err; } p7->d.signed_and_enveloped->enc_data->enc_data=os; break; case NID_pkcs7_enveloped: /* XXXXXXXXXXXXXXXX */ if (!(os=M_ASN1_OCTET_STRING_new())) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE); goto err; } p7->d.enveloped->enc_data->enc_data=os; break; case NID_pkcs7_signed: si_sk=p7->d.sign->signer_info; os=PKCS7_get_octet_string(p7->d.sign->contents); /* If detached data then the content is excluded */ if(PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) { M_ASN1_OCTET_STRING_free(os); + os = NULL; p7->d.sign->contents->d.data = NULL; } break; case NID_pkcs7_digest: os=PKCS7_get_octet_string(p7->d.digest->contents); /* If detached data then the content is excluded */ if(PKCS7_type_is_data(p7->d.digest->contents) && p7->detached) { M_ASN1_OCTET_STRING_free(os); + os = NULL; p7->d.digest->contents->d.data = NULL; } break; } if (si_sk != NULL) { if ((buf=BUF_MEM_new()) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_BIO_LIB); goto err; } for (i=0; ipkey == NULL) continue; j=OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; btmp = PKCS7_find_digest(&mdc, btmp, j); if (btmp == NULL) goto err; /* We now have the EVP_MD_CTX, lets do the * signing. */ EVP_MD_CTX_copy_ex(&ctx_tmp,mdc); if (!BUF_MEM_grow_clean(buf,EVP_PKEY_size(si->pkey))) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_BIO_LIB); goto err; } sk=si->auth_attr; /* If there are attributes, we add the digest * attribute and only sign the attributes */ if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { unsigned char md_data[EVP_MAX_MD_SIZE], *abuf=NULL; unsigned int md_len, alen; ASN1_OCTET_STRING *digest; ASN1_UTCTIME *sign_time; const EVP_MD *md_tmp; /* Add signing time if not already present */ if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime)) { if (!(sign_time=X509_gmtime_adj(NULL,0))) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE); goto err; } if (!PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, V_ASN1_UTCTIME,sign_time)) { M_ASN1_UTCTIME_free(sign_time); goto err; } } /* Add digest */ md_tmp=EVP_MD_CTX_md(&ctx_tmp); EVP_DigestFinal_ex(&ctx_tmp,md_data,&md_len); if (!(digest=M_ASN1_OCTET_STRING_new())) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE); goto err; } if (!M_ASN1_OCTET_STRING_set(digest,md_data, md_len)) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE); M_ASN1_OCTET_STRING_free(digest); goto err; } if (!PKCS7_add_signed_attribute(si, NID_pkcs9_messageDigest, V_ASN1_OCTET_STRING,digest)) { M_ASN1_OCTET_STRING_free(digest); goto err; } /* Now sign the attributes */ EVP_SignInit_ex(&ctx_tmp,md_tmp,NULL); alen = ASN1_item_i2d((ASN1_VALUE *)sk,&abuf, ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); if(!abuf) goto err; EVP_SignUpdate(&ctx_tmp,abuf,alen); OPENSSL_free(abuf); } #ifndef OPENSSL_NO_DSA if (si->pkey->type == EVP_PKEY_DSA) ctx_tmp.digest=EVP_dss1(); #endif #ifndef OPENSSL_NO_ECDSA if (si->pkey->type == EVP_PKEY_EC) ctx_tmp.digest=EVP_ecdsa(); #endif if (!EVP_SignFinal(&ctx_tmp,(unsigned char *)buf->data, (unsigned int *)&buf->length,si->pkey)) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_EVP_LIB); goto err; } if (!ASN1_STRING_set(si->enc_digest, (unsigned char *)buf->data,buf->length)) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_ASN1_LIB); goto err; } } } else if (i == NID_pkcs7_digest) { unsigned char md_data[EVP_MAX_MD_SIZE]; unsigned int md_len; if (!PKCS7_find_digest(&mdc, bio, OBJ_obj2nid(p7->d.digest->md->algorithm))) goto err; EVP_DigestFinal_ex(mdc,md_data,&md_len); M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len); } - if (!PKCS7_is_detached(p7)) - { + if (!PKCS7_is_detached(p7)) { + /* + * NOTE(emilia): I think we only reach os == NULL here because detached + * digested data support is broken. + */ + if (os == NULL) + goto err; btmp=BIO_find_type(bio,BIO_TYPE_MEM); if (btmp == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNABLE_TO_FIND_MEM_BIO); goto err; } BIO_get_mem_ptr(btmp,&buf_mem); /* Mark the BIO read only then we can use its copy of the data * instead of making an extra copy. */ BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY); BIO_set_mem_eof_return(btmp, 0); os->data = (unsigned char *)buf_mem->data; os->length = buf_mem->length; #if 0 M_ASN1_OCTET_STRING_set(os, (unsigned char *)buf_mem->data,buf_mem->length); #endif } ret=1; err: EVP_MD_CTX_cleanup(&ctx_tmp); if (buf != NULL) BUF_MEM_free(buf); return(ret); } int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si) { PKCS7_ISSUER_AND_SERIAL *ias; int ret=0,i; STACK_OF(X509) *cert; X509 *x509; + + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_INVALID_NULL_POINTER); + return 0; + } + + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_NO_CONTENT); + return 0; + } if (PKCS7_type_is_signed(p7)) { cert=p7->d.sign->cert; } else if (PKCS7_type_is_signedAndEnveloped(p7)) { cert=p7->d.signed_and_enveloped->cert; } else { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_WRONG_PKCS7_TYPE); goto err; } /* XXXXXXXXXXXXXXXXXXXXXXX */ ias=si->issuer_and_serial; x509=X509_find_by_issuer_and_serial(cert,ias->issuer,ias->serial); /* were we able to find the cert in passed to us */ if (x509 == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_UNABLE_TO_FIND_CERTIFICATE); goto err; } /* Lets verify */ if(!X509_STORE_CTX_init(ctx,cert_store,x509,cert)) { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); goto err; } X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN); i=X509_verify_cert(ctx); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); X509_STORE_CTX_cleanup(ctx); goto err; } X509_STORE_CTX_cleanup(ctx); return PKCS7_signatureVerify(bio, p7, si, x509); err: return ret; } int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, X509 *x509) { ASN1_OCTET_STRING *os; EVP_MD_CTX mdc_tmp,*mdc; int ret=0,i; int md_type; STACK_OF(X509_ATTRIBUTE) *sk; BIO *btmp; EVP_PKEY *pkey; EVP_MD_CTX_init(&mdc_tmp); if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); goto err; } md_type=OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; for (;;) { if ((btmp == NULL) || ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } BIO_get_md_ctx(btmp,&mdc); if (mdc == NULL) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_INTERNAL_ERROR); goto err; } if (EVP_MD_CTX_type(mdc) == md_type) break; /* Workaround for some broken clients that put the signature * OID instead of the digest OID in digest_alg->algorithm */ if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type) break; btmp=BIO_next(btmp); } /* mdc is the digest ctx that we want, unless there are attributes, * in which case the digest is the signed attributes */ EVP_MD_CTX_copy_ex(&mdc_tmp,mdc); sk=si->auth_attr; if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL; unsigned int md_len, alen; ASN1_OCTET_STRING *message_digest; EVP_DigestFinal_ex(&mdc_tmp,md_dat,&md_len); message_digest=PKCS7_digest_from_attributes(sk); if (!message_digest) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } if ((message_digest->length != (int)md_len) || (memcmp(message_digest->data,md_dat,md_len))) { #if 0 { int ii; for (ii=0; iilength; ii++) printf("%02X",message_digest->data[ii]); printf(" sent\n"); for (ii=0; iienc_digest; pkey = X509_get_pubkey(x509); if (!pkey) { ret = -1; goto err; } #ifndef OPENSSL_NO_DSA if(pkey->type == EVP_PKEY_DSA) mdc_tmp.digest=EVP_dss1(); #endif #ifndef OPENSSL_NO_ECDSA if (pkey->type == EVP_PKEY_EC) mdc_tmp.digest=EVP_ecdsa(); #endif i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey); EVP_PKEY_free(pkey); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE); ret= -1; goto err; } else ret=1; err: EVP_MD_CTX_cleanup(&mdc_tmp); return(ret); } PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx) { STACK_OF(PKCS7_RECIP_INFO) *rsk; PKCS7_RECIP_INFO *ri; int i; i=OBJ_obj2nid(p7->type); if (i != NID_pkcs7_signedAndEnveloped) return NULL; if (p7->d.signed_and_enveloped == NULL) return NULL; rsk=p7->d.signed_and_enveloped->recipientinfo; if (rsk == NULL) return NULL; ri=sk_PKCS7_RECIP_INFO_value(rsk,0); if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) return(NULL); ri=sk_PKCS7_RECIP_INFO_value(rsk,idx); return(ri->issuer_and_serial); } ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid) { return(get_attribute(si->auth_attr,nid)); } ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid) { return(get_attribute(si->unauth_attr,nid)); } static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid) { int i; X509_ATTRIBUTE *xa; ASN1_OBJECT *o; o=OBJ_nid2obj(nid); if (!o || !sk) return(NULL); for (i=0; iobject,o) == 0) { if (!xa->single && sk_ASN1_TYPE_num(xa->value.set)) return(sk_ASN1_TYPE_value(xa->value.set,0)); else return(NULL); } } return(NULL); } ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk) { ASN1_TYPE *astype; if(!(astype = get_attribute(sk, NID_pkcs9_messageDigest))) return NULL; return astype->value.octet_string; } int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk) { int i; if (p7si->auth_attr != NULL) sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr,X509_ATTRIBUTE_free); p7si->auth_attr=sk_X509_ATTRIBUTE_dup(sk); if (p7si->auth_attr == NULL) return 0; for (i=0; iauth_attr,i, X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) == NULL) return(0); } return(1); } int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk) { int i; if (p7si->unauth_attr != NULL) sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr, X509_ATTRIBUTE_free); p7si->unauth_attr=sk_X509_ATTRIBUTE_dup(sk); if (p7si->unauth_attr == NULL) return 0; for (i=0; iunauth_attr,i, X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) == NULL) return(0); } return(1); } int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, void *value) { return(add_attribute(&(p7si->auth_attr),nid,atrtype,value)); } int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, void *value) { return(add_attribute(&(p7si->unauth_attr),nid,atrtype,value)); } static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, void *value) { X509_ATTRIBUTE *attr=NULL; if (*sk == NULL) { if (!(*sk = sk_X509_ATTRIBUTE_new_null())) return 0; new_attrib: if (!(attr=X509_ATTRIBUTE_create(nid,atrtype,value))) return 0; if (!sk_X509_ATTRIBUTE_push(*sk,attr)) { X509_ATTRIBUTE_free(attr); return 0; } } else { int i; for (i=0; iobject) == nid) { X509_ATTRIBUTE_free(attr); attr=X509_ATTRIBUTE_create(nid,atrtype,value); if (attr == NULL) return 0; if (!sk_X509_ATTRIBUTE_set(*sk,i,attr)) { X509_ATTRIBUTE_free(attr); return 0; } goto end; } } goto new_attrib; } end: return(1); } Index: releng/8.4/crypto/openssl/crypto/pkcs7/pk7_lib.c =================================================================== --- releng/8.4/crypto/openssl/crypto/pkcs7/pk7_lib.c (revision 280267) +++ releng/8.4/crypto/openssl/crypto/pkcs7/pk7_lib.c (revision 280268) @@ -1,587 +1,590 @@ /* crypto/pkcs7/pk7_lib.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include "cryptlib.h" #include #include long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg) { int nid; long ret; nid=OBJ_obj2nid(p7->type); switch (cmd) { + /* NOTE(emilia): does not support detached digested data. */ case PKCS7_OP_SET_DETACHED_SIGNATURE: if (nid == NID_pkcs7_signed) { ret=p7->detached=(int)larg; if (ret && PKCS7_type_is_data(p7->d.sign->contents)) { ASN1_OCTET_STRING *os; os=p7->d.sign->contents->d.data; ASN1_OCTET_STRING_free(os); p7->d.sign->contents->d.data = NULL; } } else { PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); ret=0; } break; case PKCS7_OP_GET_DETACHED_SIGNATURE: if (nid == NID_pkcs7_signed) { if(!p7->d.sign || !p7->d.sign->contents->d.ptr) ret = 1; else ret = 0; p7->detached = ret; } else { PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); ret=0; } break; default: PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_UNKNOWN_OPERATION); ret=0; } return(ret); } int PKCS7_content_new(PKCS7 *p7, int type) { PKCS7 *ret=NULL; if ((ret=PKCS7_new()) == NULL) goto err; if (!PKCS7_set_type(ret,type)) goto err; if (!PKCS7_set_content(p7,ret)) goto err; return(1); err: if (ret != NULL) PKCS7_free(ret); return(0); } int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data) { int i; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: if (p7->d.sign->contents != NULL) PKCS7_free(p7->d.sign->contents); p7->d.sign->contents=p7_data; break; case NID_pkcs7_digest: if (p7->d.digest->contents != NULL) PKCS7_free(p7->d.digest->contents); p7->d.digest->contents=p7_data; break; case NID_pkcs7_data: case NID_pkcs7_enveloped: case NID_pkcs7_signedAndEnveloped: case NID_pkcs7_encrypted: default: PKCS7err(PKCS7_F_PKCS7_SET_CONTENT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } return(1); err: return(0); } int PKCS7_set_type(PKCS7 *p7, int type) { ASN1_OBJECT *obj; /*PKCS7_content_free(p7);*/ obj=OBJ_nid2obj(type); /* will not fail */ switch (type) { case NID_pkcs7_signed: p7->type=obj; if ((p7->d.sign=PKCS7_SIGNED_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.sign->version,1)) { PKCS7_SIGNED_free(p7->d.sign); p7->d.sign=NULL; goto err; } break; case NID_pkcs7_data: p7->type=obj; if ((p7->d.data=M_ASN1_OCTET_STRING_new()) == NULL) goto err; break; case NID_pkcs7_signedAndEnveloped: p7->type=obj; if ((p7->d.signed_and_enveloped=PKCS7_SIGN_ENVELOPE_new()) == NULL) goto err; ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1); if (!ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1)) goto err; p7->d.signed_and_enveloped->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data); break; case NID_pkcs7_enveloped: p7->type=obj; if ((p7->d.enveloped=PKCS7_ENVELOPE_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.enveloped->version,0)) goto err; p7->d.enveloped->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data); break; case NID_pkcs7_encrypted: p7->type=obj; if ((p7->d.encrypted=PKCS7_ENCRYPT_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.encrypted->version,0)) goto err; p7->d.encrypted->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data); break; case NID_pkcs7_digest: p7->type=obj; if ((p7->d.digest=PKCS7_DIGEST_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.digest->version,0)) goto err; break; default: PKCS7err(PKCS7_F_PKCS7_SET_TYPE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } return(1); err: return(0); } int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other) { p7->type = OBJ_nid2obj(type); p7->d.other = other; return 1; } int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *psi) { int i,j,nid; X509_ALGOR *alg; STACK_OF(PKCS7_SIGNER_INFO) *signer_sk; STACK_OF(X509_ALGOR) *md_sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: signer_sk= p7->d.sign->signer_info; md_sk= p7->d.sign->md_algs; break; case NID_pkcs7_signedAndEnveloped: signer_sk= p7->d.signed_and_enveloped->signer_info; md_sk= p7->d.signed_and_enveloped->md_algs; break; default: PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } nid=OBJ_obj2nid(psi->digest_alg->algorithm); /* If the digest is not currently listed, add it */ j=0; for (i=0; ialgorithm) == nid) { j=1; break; } } if (!j) /* we need to add another algorithm */ { if(!(alg=X509_ALGOR_new()) || !(alg->parameter = ASN1_TYPE_new())) { X509_ALGOR_free(alg); PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,ERR_R_MALLOC_FAILURE); return(0); } alg->algorithm=OBJ_nid2obj(nid); alg->parameter->type = V_ASN1_NULL; if (!sk_X509_ALGOR_push(md_sk,alg)) { X509_ALGOR_free(alg); return 0; } } if (!sk_PKCS7_SIGNER_INFO_push(signer_sk,psi)) return 0; return(1); } int PKCS7_add_certificate(PKCS7 *p7, X509 *x509) { int i; STACK_OF(X509) **sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: sk= &(p7->d.sign->cert); break; case NID_pkcs7_signedAndEnveloped: sk= &(p7->d.signed_and_enveloped->cert); break; default: PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } if (*sk == NULL) *sk=sk_X509_new_null(); if (*sk == NULL) { PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,ERR_R_MALLOC_FAILURE); return 0; } CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); if (!sk_X509_push(*sk,x509)) { X509_free(x509); return 0; } return(1); } int PKCS7_add_crl(PKCS7 *p7, X509_CRL *crl) { int i; STACK_OF(X509_CRL) **sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: sk= &(p7->d.sign->crl); break; case NID_pkcs7_signedAndEnveloped: sk= &(p7->d.signed_and_enveloped->crl); break; default: PKCS7err(PKCS7_F_PKCS7_ADD_CRL,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } if (*sk == NULL) *sk=sk_X509_CRL_new_null(); if (*sk == NULL) { PKCS7err(PKCS7_F_PKCS7_ADD_CRL,ERR_R_MALLOC_FAILURE); return 0; } CRYPTO_add(&crl->references,1,CRYPTO_LOCK_X509_CRL); if (!sk_X509_CRL_push(*sk,crl)) { X509_CRL_free(crl); return 0; } return(1); } int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, const EVP_MD *dgst) { int nid; char is_dsa; if (pkey->type == EVP_PKEY_DSA || pkey->type == EVP_PKEY_EC) is_dsa = 1; else is_dsa = 0; /* We now need to add another PKCS7_SIGNER_INFO entry */ if (!ASN1_INTEGER_set(p7i->version,1)) goto err; if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, X509_get_issuer_name(x509))) goto err; /* because ASN1_INTEGER_set is used to set a 'long' we will do * things the ugly way. */ M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); if (!(p7i->issuer_and_serial->serial= M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) goto err; /* lets keep the pkey around for a while */ CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY); p7i->pkey=pkey; /* Set the algorithms */ if (is_dsa) p7i->digest_alg->algorithm=OBJ_nid2obj(NID_sha1); else p7i->digest_alg->algorithm=OBJ_nid2obj(EVP_MD_type(dgst)); if (p7i->digest_alg->parameter != NULL) ASN1_TYPE_free(p7i->digest_alg->parameter); if ((p7i->digest_alg->parameter=ASN1_TYPE_new()) == NULL) goto err; p7i->digest_alg->parameter->type=V_ASN1_NULL; if (p7i->digest_enc_alg->parameter != NULL) ASN1_TYPE_free(p7i->digest_enc_alg->parameter); nid = EVP_PKEY_type(pkey->type); if (nid == EVP_PKEY_RSA) { p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_rsaEncryption); if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) goto err; p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; } else if (nid == EVP_PKEY_DSA) { #if 1 /* use 'dsaEncryption' OID for compatibility with other software * (PKCS #7 v1.5 does specify how to handle DSA) ... */ p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_dsa); #else /* ... although the 'dsaWithSHA1' OID (as required by RFC 2630 for CMS) * would make more sense. */ p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_dsaWithSHA1); #endif p7i->digest_enc_alg->parameter = NULL; /* special case for DSA: omit 'parameter'! */ } else if (nid == EVP_PKEY_EC) { p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_ecdsa_with_SHA1); if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) goto err; p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; } else return(0); return(1); err: return(0); } PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey, const EVP_MD *dgst) { PKCS7_SIGNER_INFO *si; if ((si=PKCS7_SIGNER_INFO_new()) == NULL) goto err; if (!PKCS7_SIGNER_INFO_set(si,x509,pkey,dgst)) goto err; if (!PKCS7_add_signer(p7,si)) goto err; return(si); err: PKCS7_SIGNER_INFO_free(si); return(NULL); } int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) { if (PKCS7_type_is_digest(p7)) { if(!(p7->d.digest->md->parameter = ASN1_TYPE_new())) { PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,ERR_R_MALLOC_FAILURE); return 0; } p7->d.digest->md->parameter->type = V_ASN1_NULL; p7->d.digest->md->algorithm = OBJ_nid2obj(EVP_MD_nid(md)); return 1; } PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,PKCS7_R_WRONG_CONTENT_TYPE); return 1; } STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7) { + if (p7 == NULL || p7->d.ptr == NULL) + return NULL; if (PKCS7_type_is_signed(p7)) { return(p7->d.sign->signer_info); } else if (PKCS7_type_is_signedAndEnveloped(p7)) { return(p7->d.signed_and_enveloped->signer_info); } else return(NULL); } PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509) { PKCS7_RECIP_INFO *ri; if ((ri=PKCS7_RECIP_INFO_new()) == NULL) goto err; if (!PKCS7_RECIP_INFO_set(ri,x509)) goto err; if (!PKCS7_add_recipient_info(p7,ri)) goto err; return(ri); err: PKCS7_RECIP_INFO_free(ri); return(NULL); } int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri) { int i; STACK_OF(PKCS7_RECIP_INFO) *sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signedAndEnveloped: sk= p7->d.signed_and_enveloped->recipientinfo; break; case NID_pkcs7_enveloped: sk= p7->d.enveloped->recipientinfo; break; default: PKCS7err(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } if (!sk_PKCS7_RECIP_INFO_push(sk,ri)) return 0; return(1); } int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509) { if (!ASN1_INTEGER_set(p7i->version,0)) return 0; if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, X509_get_issuer_name(x509))) return 0; M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); if (!(p7i->issuer_and_serial->serial= M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) return 0; X509_ALGOR_free(p7i->key_enc_algor); if (!(p7i->key_enc_algor= X509_ALGOR_dup(x509->cert_info->key->algor))) return 0; CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); p7i->cert=x509; return(1); } X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si) { if (PKCS7_type_is_signed(p7)) return(X509_find_by_issuer_and_serial(p7->d.sign->cert, si->issuer_and_serial->issuer, si->issuer_and_serial->serial)); else return(NULL); } int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher) { int i; PKCS7_ENC_CONTENT *ec; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signedAndEnveloped: ec=p7->d.signed_and_enveloped->enc_data; break; case NID_pkcs7_enveloped: ec=p7->d.enveloped->enc_data; break; default: PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } /* Check cipher OID exists and has data in it*/ i = EVP_CIPHER_type(cipher); if(i == NID_undef) { PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); return(0); } ec->cipher = cipher; return 1; } Index: releng/8.4/crypto/openssl/doc/crypto/d2i_X509.pod =================================================================== --- releng/8.4/crypto/openssl/doc/crypto/d2i_X509.pod (revision 280267) +++ releng/8.4/crypto/openssl/doc/crypto/d2i_X509.pod (revision 280268) @@ -1,231 +1,239 @@ =pod =head1 NAME d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio, i2d_X509_fp - X509 encode and decode functions =head1 SYNOPSIS #include X509 *d2i_X509(X509 **px, const unsigned char **in, int len); int i2d_X509(X509 *x, unsigned char **out); X509 *d2i_X509_bio(BIO *bp, X509 **x); X509 *d2i_X509_fp(FILE *fp, X509 **x); int i2d_X509_bio(BIO *bp, X509 *x); int i2d_X509_fp(FILE *fp, X509 *x); =head1 DESCRIPTION The X509 encode and decode routines encode and parse an B structure, which represents an X509 certificate. d2i_X509() attempts to decode B bytes at B<*in>. If successful a pointer to the B structure is returned. If an error occurred then B is returned. If B is not B then the returned structure is written to B<*px>. If B<*px> is not B then it is assumed that B<*px> contains a valid B structure and an attempt is made to reuse it. If the call is successful B<*in> is incremented to the byte following the parsed data. i2d_X509() encodes the structure pointed to by B into DER format. If B is not B is writes the DER encoded data to the buffer at B<*out>, and increments it to point after the data just written. If the return value is negative an error occurred, otherwise it returns the length of the encoded data. For OpenSSL 0.9.7 and later if B<*out> is B memory will be allocated for a buffer and the encoded data written to it. In this case B<*out> is not incremented and it points to the start of the data just written. d2i_X509_bio() is similar to d2i_X509() except it attempts to parse data from BIO B. d2i_X509_fp() is similar to d2i_X509() except it attempts to parse data from FILE pointer B. i2d_X509_bio() is similar to i2d_X509() except it writes the encoding of the structure B to BIO B and it returns 1 for success and 0 for failure. i2d_X509_fp() is similar to i2d_X509() except it writes the encoding of the structure B to BIO B and it returns 1 for success and 0 for failure. =head1 NOTES The letters B and B in for example B stand for "internal" (that is an internal C structure) and "DER". So that B converts from internal to DER. The functions can also understand B forms. The actual X509 structure passed to i2d_X509() must be a valid populated B structure it can B simply be fed with an empty structure such as that returned by X509_new(). The encoded data is in binary form and may contain embedded zeroes. Therefore any FILE pointers or BIOs should be opened in binary mode. Functions such as B will B return the correct length of the encoded structure. The ways that B<*in> and B<*out> are incremented after the operation can trap the unwary. See the B section for some common errors. The reason for the auto increment behaviour is to reflect a typical usage of ASN1 functions: after one structure is encoded or decoded another will processed after it. =head1 EXAMPLES Allocate and encode the DER encoding of an X509 structure: int len; unsigned char *buf, *p; len = i2d_X509(x, NULL); buf = OPENSSL_malloc(len); if (buf == NULL) /* error */ p = buf; i2d_X509(x, &p); If you are using OpenSSL 0.9.7 or later then this can be simplified to: int len; unsigned char *buf; buf = NULL; len = i2d_X509(x, &buf); if (len < 0) /* error */ Attempt to decode a buffer: X509 *x; unsigned char *buf, *p; int len; /* Something to setup buf and len */ p = buf; x = d2i_X509(NULL, &p, len); if (x == NULL) /* Some error */ Alternative technique: X509 *x; unsigned char *buf, *p; int len; /* Something to setup buf and len */ p = buf; x = NULL; if(!d2i_X509(&x, &p, len)) /* Some error */ =head1 WARNINGS The use of temporary variable is mandatory. A common mistake is to attempt to use a buffer directly as follows: int len; unsigned char *buf; len = i2d_X509(x, NULL); buf = OPENSSL_malloc(len); if (buf == NULL) /* error */ i2d_X509(x, &buf); /* Other stuff ... */ OPENSSL_free(buf); This code will result in B apparently containing garbage because it was incremented after the call to point after the data just written. Also B will no longer contain the pointer allocated by B and the subsequent call to B may well crash. The auto allocation feature (setting buf to NULL) only works on OpenSSL 0.9.7 and later. Attempts to use it on earlier versions will typically cause a segmentation violation. Another trap to avoid is misuse of the B argument to B: X509 *x; if (!d2i_X509(&x, &p, len)) /* Some error */ This will probably crash somewhere in B. The reason for this is that the variable B is uninitialized and an attempt will be made to interpret its (invalid) value as an B structure, typically causing a segmentation violation. If B is set to NULL first then this will not happen. =head1 BUGS In some versions of OpenSSL the "reuse" behaviour of d2i_X509() when B<*px> is valid is broken and some parts of the reused structure may persist if they are not present in the new one. As a result the use of this "reuse" behaviour is strongly discouraged. +Current versions of OpenSSL will not modify B<*px> if an error occurs. +If parsing succeeds then B<*px> is freed (if it is not NULL) and then +set to the value of the newly decoded structure. As a result B<*px> +B be allocated on the stack or an attempt will be made to +free an invalid pointer. + i2d_X509() will not return an error in many versions of OpenSSL, if mandatory fields are not initialized due to a programming error then the encoded structure may contain invalid data or omit the fields entirely and will not be parsed by d2i_X509(). This may be fixed in future so code should not assume that i2d_X509() will always succeed. =head1 RETURN VALUES d2i_X509(), d2i_X509_bio() and d2i_X509_fp() return a valid B structure or B if an error occurs. The error code that can be obtained by -L. +L. If the "reuse" capability has been used +with a valid X509 structure being passed in via B then the object is not +modified in the event of error. i2d_X509() returns the number of bytes successfully encoded or a negative value if an error occurs. The error code can be obtained by L. i2d_X509_bio() and i2d_X509_fp() return 1 for success and 0 if an error occurs The error code can be obtained by L. =head1 SEE ALSO L =head1 HISTORY d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio and i2d_X509_fp are available in all versions of SSLeay and OpenSSL. =cut Index: releng/8.4/crypto/openssl/ssl/s2_lib.c =================================================================== --- releng/8.4/crypto/openssl/ssl/s2_lib.c (revision 280267) +++ releng/8.4/crypto/openssl/ssl/s2_lib.c (revision 280268) @@ -1,480 +1,480 @@ /* ssl/s2_lib.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include "ssl_locl.h" #ifndef OPENSSL_NO_SSL2 #include #include #include #include const char ssl2_version_str[]="SSLv2" OPENSSL_VERSION_PTEXT; #define SSL2_NUM_CIPHERS (sizeof(ssl2_ciphers)/sizeof(SSL_CIPHER)) /* list of available SSLv2 ciphers (sorted by id) */ OPENSSL_GLOBAL SSL_CIPHER ssl2_ciphers[]={ /* NULL_WITH_MD5 v3 */ #if 0 { 1, SSL2_TXT_NULL_WITH_MD5, SSL2_CK_NULL_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_MD5|SSL_SSLV2, SSL_EXPORT|SSL_EXP40|SSL_STRONG_NONE, 0, 0, 0, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, #endif /* RC4_128_WITH_MD5 */ { 1, SSL2_TXT_RC4_128_WITH_MD5, SSL2_CK_RC4_128_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_MEDIUM, 0, 128, 128, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* RC4_128_EXPORT40_WITH_MD5 */ { 1, SSL2_TXT_RC4_128_EXPORT40_WITH_MD5, SSL2_CK_RC4_128_EXPORT40_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5|SSL_SSLV2, SSL_EXPORT|SSL_EXP40, SSL2_CF_5_BYTE_ENC, 40, 128, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* RC2_128_CBC_WITH_MD5 */ { 1, SSL2_TXT_RC2_128_CBC_WITH_MD5, SSL2_CK_RC2_128_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_MEDIUM, 0, 128, 128, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* RC2_128_CBC_EXPORT40_WITH_MD5 */ { 1, SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5, SSL2_CK_RC2_128_CBC_EXPORT40_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5|SSL_SSLV2, SSL_EXPORT|SSL_EXP40, SSL2_CF_5_BYTE_ENC, 40, 128, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* IDEA_128_CBC_WITH_MD5 */ #ifndef OPENSSL_NO_IDEA { 1, SSL2_TXT_IDEA_128_CBC_WITH_MD5, SSL2_CK_IDEA_128_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_IDEA|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_MEDIUM, 0, 128, 128, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, #endif /* DES_64_CBC_WITH_MD5 */ { 1, SSL2_TXT_DES_64_CBC_WITH_MD5, SSL2_CK_DES_64_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_DES|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_LOW, 0, 56, 56, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* DES_192_EDE3_CBC_WITH_MD5 */ { 1, SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5, SSL2_CK_DES_192_EDE3_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_HIGH, 0, 168, 168, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* RC4_64_WITH_MD5 */ #if 0 { 1, SSL2_TXT_RC4_64_WITH_MD5, SSL2_CK_RC4_64_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_LOW, SSL2_CF_8_BYTE_ENC, 64, 64, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, #endif /* NULL SSLeay (testing) */ #if 0 { 0, SSL2_TXT_NULL, SSL2_CK_NULL, 0, SSL_STRONG_NONE, 0, 0, 0, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, #endif /* end of list :-) */ }; long ssl2_default_timeout(void) { return(300); } IMPLEMENT_ssl2_meth_func(sslv2_base_method, ssl_undefined_function, ssl_undefined_function, ssl_bad_method) int ssl2_num_ciphers(void) { return(SSL2_NUM_CIPHERS); } SSL_CIPHER *ssl2_get_cipher(unsigned int u) { if (u < SSL2_NUM_CIPHERS) return(&(ssl2_ciphers[SSL2_NUM_CIPHERS-1-u])); else return(NULL); } int ssl2_pending(const SSL *s) { return SSL_in_init(s) ? 0 : s->s2->ract_data_length; } int ssl2_new(SSL *s) { SSL2_STATE *s2; if ((s2=OPENSSL_malloc(sizeof *s2)) == NULL) goto err; memset(s2,0,sizeof *s2); #if SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER + 3 > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2 # error "assertion failed" #endif if ((s2->rbuf=OPENSSL_malloc( SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2)) == NULL) goto err; /* wbuf needs one byte more because when using two-byte headers, * we leave the first byte unused in do_ssl_write (s2_pkt.c) */ if ((s2->wbuf=OPENSSL_malloc( SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+3)) == NULL) goto err; s->s2=s2; ssl2_clear(s); return(1); err: if (s2 != NULL) { if (s2->wbuf != NULL) OPENSSL_free(s2->wbuf); if (s2->rbuf != NULL) OPENSSL_free(s2->rbuf); OPENSSL_free(s2); } return(0); } void ssl2_free(SSL *s) { SSL2_STATE *s2; if(s == NULL) return; s2=s->s2; if (s2->rbuf != NULL) OPENSSL_free(s2->rbuf); if (s2->wbuf != NULL) OPENSSL_free(s2->wbuf); OPENSSL_cleanse(s2,sizeof *s2); OPENSSL_free(s2); s->s2=NULL; } void ssl2_clear(SSL *s) { SSL2_STATE *s2; unsigned char *rbuf,*wbuf; s2=s->s2; rbuf=s2->rbuf; wbuf=s2->wbuf; memset(s2,0,sizeof *s2); s2->rbuf=rbuf; s2->wbuf=wbuf; s2->clear_text=1; s->packet=s2->rbuf; s->version=SSL2_VERSION; s->packet_length=0; } long ssl2_ctrl(SSL *s, int cmd, long larg, void *parg) { int ret=0; switch(cmd) { case SSL_CTRL_GET_SESSION_REUSED: ret=s->hit; break; case SSL_CTRL_CHECK_PROTO_VERSION: return ssl3_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, larg, parg); default: break; } return(ret); } long ssl2_callback_ctrl(SSL *s, int cmd, void (*fp)(void)) { return(0); } long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { return(0); } long ssl2_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) { return(0); } /* This function needs to check if the ciphers required are actually * available */ SSL_CIPHER *ssl2_get_cipher_by_char(const unsigned char *p) { SSL_CIPHER c,*cp; unsigned long id; id=0x02000000L|((unsigned long)p[0]<<16L)| ((unsigned long)p[1]<<8L)|(unsigned long)p[2]; c.id=id; cp = (SSL_CIPHER *)OBJ_bsearch((char *)&c, (char *)ssl2_ciphers, SSL2_NUM_CIPHERS,sizeof(SSL_CIPHER), FP_ICC ssl_cipher_id_cmp); if ((cp == NULL) || (cp->valid == 0)) return NULL; else return cp; } int ssl2_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p) { long l; if (p != NULL) { l=c->id; if ((l & 0xff000000) != 0x02000000 && l != SSL3_CK_FALLBACK_SCSV) return(0); p[0]=((unsigned char)(l>>16L))&0xFF; p[1]=((unsigned char)(l>> 8L))&0xFF; p[2]=((unsigned char)(l ))&0xFF; } return(3); } int ssl2_generate_key_material(SSL *s) { unsigned int i; EVP_MD_CTX ctx; unsigned char *km; unsigned char c='0'; const EVP_MD *md5; md5 = EVP_md5(); #ifdef CHARSET_EBCDIC c = os_toascii['0']; /* Must be an ASCII '0', not EBCDIC '0', see SSLv2 docu */ #endif EVP_MD_CTX_init(&ctx); km=s->s2->key_material; if (s->session->master_key_length < 0 || s->session->master_key_length > (int)sizeof(s->session->master_key)) { SSLerr(SSL_F_SSL2_GENERATE_KEY_MATERIAL, ERR_R_INTERNAL_ERROR); return 0; } for (i=0; is2->key_material_length; i += EVP_MD_size(md5)) { if (((km - s->s2->key_material) + EVP_MD_size(md5)) > (int)sizeof(s->s2->key_material)) { /* EVP_DigestFinal_ex() below would write beyond buffer */ SSLerr(SSL_F_SSL2_GENERATE_KEY_MATERIAL, ERR_R_INTERNAL_ERROR); return 0; } EVP_DigestInit_ex(&ctx, md5, NULL); OPENSSL_assert(s->session->master_key_length >= 0 && s->session->master_key_length - < (int)sizeof(s->session->master_key)); + <= (int)sizeof(s->session->master_key)); EVP_DigestUpdate(&ctx,s->session->master_key,s->session->master_key_length); EVP_DigestUpdate(&ctx,&c,1); c++; EVP_DigestUpdate(&ctx,s->s2->challenge,s->s2->challenge_length); EVP_DigestUpdate(&ctx,s->s2->conn_id,s->s2->conn_id_length); EVP_DigestFinal_ex(&ctx,km,NULL); km += EVP_MD_size(md5); } EVP_MD_CTX_cleanup(&ctx); return 1; } void ssl2_return_error(SSL *s, int err) { if (!s->error) { s->error=3; s->error_code=err; ssl2_write_error(s); } } void ssl2_write_error(SSL *s) { unsigned char buf[3]; int i,error; buf[0]=SSL2_MT_ERROR; buf[1]=(s->error_code>>8)&0xff; buf[2]=(s->error_code)&0xff; /* state=s->rwstate;*/ error=s->error; /* number of bytes left to write */ s->error=0; OPENSSL_assert(error >= 0 && error <= (int)sizeof(buf)); i=ssl2_write(s,&(buf[3-error]),error); /* if (i == error) s->rwstate=state; */ if (i < 0) s->error=error; else { s->error=error-i; if (s->error == 0) if (s->msg_callback) s->msg_callback(1, s->version, 0, buf, 3, s, s->msg_callback_arg); /* ERROR */ } } int ssl2_shutdown(SSL *s) { s->shutdown=(SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); return(1); } #else /* !OPENSSL_NO_SSL2 */ # if PEDANTIC static void *dummy=&dummy; # endif #endif Index: releng/8.4/crypto/openssl/ssl/s2_srvr.c =================================================================== --- releng/8.4/crypto/openssl/ssl/s2_srvr.c (revision 280267) +++ releng/8.4/crypto/openssl/ssl/s2_srvr.c (revision 280268) @@ -1,1142 +1,1178 @@ /* ssl/s2_srvr.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* ==================================================================== * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ #include "ssl_locl.h" #ifndef OPENSSL_NO_SSL2 #include #include #include #include #include static SSL_METHOD *ssl2_get_server_method(int ver); static int get_client_master_key(SSL *s); static int get_client_hello(SSL *s); static int server_hello(SSL *s); static int get_client_finished(SSL *s); static int server_verify(SSL *s); static int server_finish(SSL *s); static int request_certificate(SSL *s); static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from, unsigned char *to,int padding); #define BREAK break static SSL_METHOD *ssl2_get_server_method(int ver) { if (ver == SSL2_VERSION) return(SSLv2_server_method()); else return(NULL); } IMPLEMENT_ssl2_meth_func(SSLv2_server_method, ssl2_accept, ssl_undefined_function, ssl2_get_server_method) int ssl2_accept(SSL *s) { unsigned long l=(unsigned long)time(NULL); BUF_MEM *buf=NULL; int ret= -1; long num1; void (*cb)(const SSL *ssl,int type,int val)=NULL; int new_state,state; RAND_add(&l,sizeof(l),0); ERR_clear_error(); clear_sys_error(); if (s->info_callback != NULL) cb=s->info_callback; else if (s->ctx->info_callback != NULL) cb=s->ctx->info_callback; /* init things to blank */ s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); if (s->cert == NULL) { SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_NO_CERTIFICATE_SET); return(-1); } clear_sys_error(); for (;;) { state=s->state; switch (s->state) { case SSL_ST_BEFORE: case SSL_ST_ACCEPT: case SSL_ST_BEFORE|SSL_ST_ACCEPT: case SSL_ST_OK|SSL_ST_ACCEPT: s->server=1; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1); s->version=SSL2_VERSION; s->type=SSL_ST_ACCEPT; buf=s->init_buf; if ((buf == NULL) && ((buf=BUF_MEM_new()) == NULL)) { ret= -1; goto end; } if (!BUF_MEM_grow(buf,(int) SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)) { ret= -1; goto end; } s->init_buf=buf; s->init_num=0; s->ctx->stats.sess_accept++; s->handshake_func=ssl2_accept; s->state=SSL2_ST_GET_CLIENT_HELLO_A; BREAK; case SSL2_ST_GET_CLIENT_HELLO_A: case SSL2_ST_GET_CLIENT_HELLO_B: case SSL2_ST_GET_CLIENT_HELLO_C: s->shutdown=0; ret=get_client_hello(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SEND_SERVER_HELLO_A; BREAK; case SSL2_ST_SEND_SERVER_HELLO_A: case SSL2_ST_SEND_SERVER_HELLO_B: ret=server_hello(s); if (ret <= 0) goto end; s->init_num=0; if (!s->hit) { s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_A; BREAK; } else { s->state=SSL2_ST_SERVER_START_ENCRYPTION; BREAK; } case SSL2_ST_GET_CLIENT_MASTER_KEY_A: case SSL2_ST_GET_CLIENT_MASTER_KEY_B: ret=get_client_master_key(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SERVER_START_ENCRYPTION; BREAK; case SSL2_ST_SERVER_START_ENCRYPTION: /* Ok we how have sent all the stuff needed to * start encrypting, the next packet back will * be encrypted. */ if (!ssl2_enc_init(s,0)) { ret= -1; goto end; } s->s2->clear_text=0; s->state=SSL2_ST_SEND_SERVER_VERIFY_A; BREAK; case SSL2_ST_SEND_SERVER_VERIFY_A: case SSL2_ST_SEND_SERVER_VERIFY_B: ret=server_verify(s); if (ret <= 0) goto end; s->init_num=0; if (s->hit) { /* If we are in here, we have been * buffering the output, so we need to * flush it and remove buffering from * future traffic */ s->state=SSL2_ST_SEND_SERVER_VERIFY_C; BREAK; } else { s->state=SSL2_ST_GET_CLIENT_FINISHED_A; break; } case SSL2_ST_SEND_SERVER_VERIFY_C: /* get the number of bytes to write */ num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL); if (num1 > 0) { s->rwstate=SSL_WRITING; num1=BIO_flush(s->wbio); if (num1 <= 0) { ret= -1; goto end; } s->rwstate=SSL_NOTHING; } /* flushed and now remove buffering */ s->wbio=BIO_pop(s->wbio); s->state=SSL2_ST_GET_CLIENT_FINISHED_A; BREAK; case SSL2_ST_GET_CLIENT_FINISHED_A: case SSL2_ST_GET_CLIENT_FINISHED_B: ret=get_client_finished(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_A; BREAK; case SSL2_ST_SEND_REQUEST_CERTIFICATE_A: case SSL2_ST_SEND_REQUEST_CERTIFICATE_B: case SSL2_ST_SEND_REQUEST_CERTIFICATE_C: case SSL2_ST_SEND_REQUEST_CERTIFICATE_D: /* don't do a 'request certificate' if we * don't want to, or we already have one, and * we only want to do it once. */ if (!(s->verify_mode & SSL_VERIFY_PEER) || ((s->session->peer != NULL) && (s->verify_mode & SSL_VERIFY_CLIENT_ONCE))) { s->state=SSL2_ST_SEND_SERVER_FINISHED_A; break; } else { ret=request_certificate(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SEND_SERVER_FINISHED_A; } BREAK; case SSL2_ST_SEND_SERVER_FINISHED_A: case SSL2_ST_SEND_SERVER_FINISHED_B: ret=server_finish(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL_ST_OK; break; case SSL_ST_OK: BUF_MEM_free(s->init_buf); ssl_free_wbio_buffer(s); s->init_buf=NULL; s->init_num=0; /* ERR_clear_error();*/ ssl_update_cache(s,SSL_SESS_CACHE_SERVER); s->ctx->stats.sess_accept_good++; /* s->server=1; */ ret=1; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1); goto end; /* BREAK; */ default: SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_UNKNOWN_STATE); ret= -1; goto end; /* BREAK; */ } if ((cb != NULL) && (s->state != state)) { new_state=s->state; s->state=state; cb(s,SSL_CB_ACCEPT_LOOP,1); s->state=new_state; } } end: s->in_handshake--; if (cb != NULL) cb(s,SSL_CB_ACCEPT_EXIT,ret); return(ret); } static int get_client_master_key(SSL *s) { int is_export,i,n,keya,ek; unsigned long len; unsigned char *p; SSL_CIPHER *cp; const EVP_CIPHER *c; const EVP_MD *md; p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_GET_CLIENT_MASTER_KEY_A) { i=ssl2_read(s,(char *)&(p[s->init_num]),10-s->init_num); if (i < (10-s->init_num)) return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i)); s->init_num = 10; if (*(p++) != SSL2_MT_CLIENT_MASTER_KEY) { if (p[-1] != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_READ_WRONG_PACKET_TYPE); } else SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_PEER_ERROR); return(-1); } cp=ssl2_get_cipher_by_char(p); if (cp == NULL) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_NO_CIPHER_MATCH); return(-1); } s->session->cipher= cp; p+=3; n2s(p,i); s->s2->tmp.clear=i; n2s(p,i); s->s2->tmp.enc=i; n2s(p,i); if(i > SSL_MAX_KEY_ARG_LENGTH) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_KEY_ARG_TOO_LONG); return -1; } s->session->key_arg_length=i; s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_B; } /* SSL2_ST_GET_CLIENT_MASTER_KEY_B */ p=(unsigned char *)s->init_buf->data; if (s->init_buf->length < SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); return -1; } keya=s->session->key_arg_length; len = 10 + (unsigned long)s->s2->tmp.clear + (unsigned long)s->s2->tmp.enc + (unsigned long)keya; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_MESSAGE_TOO_LONG); return -1; } n = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),n); if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i)); if (s->msg_callback) s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-MASTER-KEY */ p += 10; memcpy(s->session->key_arg,&(p[s->s2->tmp.clear+s->s2->tmp.enc]), (unsigned int)keya); if (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_NO_PRIVATEKEY); return(-1); } - i=ssl_rsa_private_decrypt(s->cert,s->s2->tmp.enc, - &(p[s->s2->tmp.clear]),&(p[s->s2->tmp.clear]), - (s->s2->ssl2_rollback)?RSA_SSLV23_PADDING:RSA_PKCS1_PADDING); is_export=SSL_C_IS_EXPORT(s->session->cipher); if (!ssl_cipher_get_evp(s->session,&c,&md,NULL)) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS); return(0); } if (s->session->cipher->algorithm2 & SSL2_CF_8_BYTE_ENC) { is_export=1; ek=8; } else ek=5; + /* + * The format of the CLIENT-MASTER-KEY message is + * 1 byte message type + * 3 bytes cipher + * 2-byte clear key length (stored in s->s2->tmp.clear) + * 2-byte encrypted key length (stored in s->s2->tmp.enc) + * 2-byte key args length (IV etc) + * clear key + * encrypted key + * key args + * + * If the cipher is an export cipher, then the encrypted key bytes + * are a fixed portion of the total key (5 or 8 bytes). The size of + * this portion is in |ek|. If the cipher is not an export cipher, + * then the entire key material is encrypted (i.e., clear key length + * must be zero). + */ + if ((!is_export && s->s2->tmp.clear != 0) || + (is_export && s->s2->tmp.clear + ek != EVP_CIPHER_key_length(c))) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_LENGTH); + return -1; + } + /* + * The encrypted blob must decrypt to the encrypted portion of the key. + * Decryption can't be expanding, so if we don't have enough encrypted + * bytes to fit the key in the buffer, stop now. + */ + if ((is_export && s->s2->tmp.enc < ek) || + (!is_export && s->s2->tmp.enc < EVP_CIPHER_key_length(c))) { + ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_LENGTH_TOO_SHORT); + return -1; + } + + i = ssl_rsa_private_decrypt(s->cert, s->s2->tmp.enc, + &(p[s->s2->tmp.clear]), + &(p[s->s2->tmp.clear]), + (s->s2->ssl2_rollback) ? RSA_SSLV23_PADDING : + RSA_PKCS1_PADDING); + /* bad decrypt */ #if 1 /* If a bad decrypt, continue with protocol but with a * random master secret (Bleichenbacher attack) */ - if ((i < 0) || - ((!is_export && (i != EVP_CIPHER_key_length(c))) - || (is_export && ((i != ek) || (s->s2->tmp.clear+(unsigned int)i != - (unsigned int)EVP_CIPHER_key_length(c)))))) - { + if ((i < 0) || ((!is_export && i != EVP_CIPHER_key_length(c)) + || (is_export && i != ek))) { ERR_clear_error(); if (is_export) i=ek; else i=EVP_CIPHER_key_length(c); - if (RAND_pseudo_bytes(p,i) <= 0) + if (RAND_pseudo_bytes(&p[s->s2->tmp.clear], i) <= 0) return 0; - } + } #else if (i < 0) { error=1; SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_RSA_DECRYPT); } /* incorrect number of key bytes for non export cipher */ else if ((!is_export && (i != EVP_CIPHER_key_length(c))) || (is_export && ((i != ek) || (s->s2->tmp.clear+i != EVP_CIPHER_key_length(c))))) { error=1; SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_WRONG_NUMBER_OF_KEY_BITS); } if (error) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } #endif - if (is_export) i+=s->s2->tmp.clear; + if (is_export) + i = EVP_CIPHER_key_length(c); if (i > SSL_MAX_MASTER_KEY_LENGTH) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); return -1; } s->session->master_key_length=i; memcpy(s->session->master_key,p,(unsigned int)i); return(1); } static int get_client_hello(SSL *s) { int i,n; unsigned long len; unsigned char *p; STACK_OF(SSL_CIPHER) *cs; /* a stack of SSL_CIPHERS */ STACK_OF(SSL_CIPHER) *cl; /* the ones we want to use */ STACK_OF(SSL_CIPHER) *prio, *allow; int z; /* This is a bit of a hack to check for the correct packet * type the first time round. */ if (s->state == SSL2_ST_GET_CLIENT_HELLO_A) { s->first_packet=1; s->state=SSL2_ST_GET_CLIENT_HELLO_B; } p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_GET_CLIENT_HELLO_B) { i=ssl2_read(s,(char *)&(p[s->init_num]),9-s->init_num); if (i < (9-s->init_num)) return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i)); s->init_num = 9; if (*(p++) != SSL2_MT_CLIENT_HELLO) { if (p[-1] != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_READ_WRONG_PACKET_TYPE); } else SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_PEER_ERROR); return(-1); } n2s(p,i); if (i < s->version) s->version=i; n2s(p,i); s->s2->tmp.cipher_spec_length=i; n2s(p,i); s->s2->tmp.session_id_length=i; n2s(p,i); s->s2->challenge_length=i; if ( (i < SSL2_MIN_CHALLENGE_LENGTH) || (i > SSL2_MAX_CHALLENGE_LENGTH)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_INVALID_CHALLENGE_LENGTH); return(-1); } s->state=SSL2_ST_GET_CLIENT_HELLO_C; } /* SSL2_ST_GET_CLIENT_HELLO_C */ p=(unsigned char *)s->init_buf->data; len = 9 + (unsigned long)s->s2->tmp.cipher_spec_length + (unsigned long)s->s2->challenge_length + (unsigned long)s->s2->tmp.session_id_length; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_MESSAGE_TOO_LONG); return -1; } n = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),n); if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i)); if (s->msg_callback) s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-HELLO */ p += 9; /* get session-id before cipher stuff so we can get out session * structure if it is cached */ /* session-id */ if ((s->s2->tmp.session_id_length != 0) && (s->s2->tmp.session_id_length != SSL2_SSL_SESSION_ID_LENGTH)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_BAD_SSL_SESSION_ID_LENGTH); return(-1); } if (s->s2->tmp.session_id_length == 0) { if (!ssl_get_new_session(s,1)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } } else { i=ssl_get_prev_session(s,&(p[s->s2->tmp.cipher_spec_length]), s->s2->tmp.session_id_length, NULL); if (i == 1) { /* previous session */ s->hit=1; } else if (i == -1) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } else { if (s->cert == NULL) { ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_NO_CERTIFICATE_SET); return(-1); } if (!ssl_get_new_session(s,1)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } } } if (!s->hit) { cs=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.cipher_spec_length, &s->session->ciphers); if (cs == NULL) goto mem_err; cl=SSL_get_ciphers(s); if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { prio=sk_SSL_CIPHER_dup(cl); if (prio == NULL) goto mem_err; allow = cs; } else { prio = cs; allow = cl; } for (z=0; zoptions & SSL_OP_CIPHER_SERVER_PREFERENCE) { sk_SSL_CIPHER_free(s->session->ciphers); s->session->ciphers = prio; } /* s->session->ciphers should now have a list of * ciphers that are on both the client and server. * This list is ordered by the order the client sent * the ciphers or in the order of the server's preference * if SSL_OP_CIPHER_SERVER_PREFERENCE was set. */ } p+=s->s2->tmp.cipher_spec_length; /* done cipher selection */ /* session id extracted already */ p+=s->s2->tmp.session_id_length; /* challenge */ if (s->s2->challenge_length > sizeof s->s2->challenge) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); return -1; } memcpy(s->s2->challenge,p,(unsigned int)s->s2->challenge_length); return(1); mem_err: SSLerr(SSL_F_GET_CLIENT_HELLO,ERR_R_MALLOC_FAILURE); return(0); } static int server_hello(SSL *s) { unsigned char *p,*d; int n,hit; p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_SEND_SERVER_HELLO_A) { d=p+11; *(p++)=SSL2_MT_SERVER_HELLO; /* type */ hit=s->hit; *(p++)=(unsigned char)hit; #if 1 if (!hit) { if (s->session->sess_cert != NULL) /* This can't really happen because get_client_hello * has called ssl_get_new_session, which does not set * sess_cert. */ ssl_sess_cert_free(s->session->sess_cert); s->session->sess_cert = ssl_sess_cert_new(); if (s->session->sess_cert == NULL) { SSLerr(SSL_F_SERVER_HELLO, ERR_R_MALLOC_FAILURE); return(-1); } } /* If 'hit' is set, then s->sess_cert may be non-NULL or NULL, * depending on whether it survived in the internal cache * or was retrieved from an external cache. * If it is NULL, we cannot put any useful data in it anyway, * so we don't touch it. */ #else /* That's what used to be done when cert_st and sess_cert_st were * the same. */ if (!hit) { /* else add cert to session */ CRYPTO_add(&s->cert->references,1,CRYPTO_LOCK_SSL_CERT); if (s->session->sess_cert != NULL) ssl_cert_free(s->session->sess_cert); s->session->sess_cert=s->cert; } else /* We have a session id-cache hit, if the * session-id has no certificate listed against * the 'cert' structure, grab the 'old' one * listed against the SSL connection */ { if (s->session->sess_cert == NULL) { CRYPTO_add(&s->cert->references,1, CRYPTO_LOCK_SSL_CERT); s->session->sess_cert=s->cert; } } #endif if (s->cert == NULL) { ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE); SSLerr(SSL_F_SERVER_HELLO,SSL_R_NO_CERTIFICATE_SPECIFIED); return(-1); } if (hit) { *(p++)=0; /* no certificate type */ s2n(s->version,p); /* version */ s2n(0,p); /* cert len */ s2n(0,p); /* ciphers len */ } else { /* EAY EAY */ /* put certificate type */ *(p++)=SSL2_CT_X509_CERTIFICATE; s2n(s->version,p); /* version */ n=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL); s2n(n,p); /* certificate length */ i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&d); n=0; /* lets send out the ciphers we like in the * prefered order */ n=ssl_cipher_list_to_bytes(s,s->session->ciphers,d,0); d+=n; s2n(n,p); /* add cipher length */ } /* make and send conn_id */ s2n(SSL2_CONNECTION_ID_LENGTH,p); /* add conn_id length */ s->s2->conn_id_length=SSL2_CONNECTION_ID_LENGTH; if (RAND_pseudo_bytes(s->s2->conn_id,(int)s->s2->conn_id_length) <= 0) return -1; memcpy(d,s->s2->conn_id,SSL2_CONNECTION_ID_LENGTH); d+=SSL2_CONNECTION_ID_LENGTH; s->state=SSL2_ST_SEND_SERVER_HELLO_B; s->init_num=d-(unsigned char *)s->init_buf->data; s->init_off=0; } /* SSL2_ST_SEND_SERVER_HELLO_B */ /* If we are using TCP/IP, the performance is bad if we do 2 * writes without a read between them. This occurs when * Session-id reuse is used, so I will put in a buffering module */ if (s->hit) { if (!ssl_init_wbio_buffer(s,1)) return(-1); } return(ssl2_do_write(s)); } static int get_client_finished(SSL *s) { unsigned char *p; int i, n; unsigned long len; p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_GET_CLIENT_FINISHED_A) { i=ssl2_read(s,(char *)&(p[s->init_num]),1-s->init_num); if (i < 1-s->init_num) return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i)); s->init_num += i; if (*p != SSL2_MT_CLIENT_FINISHED) { if (*p != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_READ_WRONG_PACKET_TYPE); } else { SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_PEER_ERROR); /* try to read the error message */ i=ssl2_read(s,(char *)&(p[s->init_num]),3-s->init_num); return ssl2_part_read(s,SSL_F_GET_SERVER_VERIFY,i); } return(-1); } s->state=SSL2_ST_GET_CLIENT_FINISHED_B; } /* SSL2_ST_GET_CLIENT_FINISHED_B */ if (s->s2->conn_id_length > sizeof s->s2->conn_id) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_FINISHED, ERR_R_INTERNAL_ERROR); return -1; } len = 1 + (unsigned long)s->s2->conn_id_length; n = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),n); if (i < n) { return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i)); } if (s->msg_callback) s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-FINISHED */ p += 1; if (memcmp(p,s->s2->conn_id,s->s2->conn_id_length) != 0) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_CONNECTION_ID_IS_DIFFERENT); return(-1); } return(1); } static int server_verify(SSL *s) { unsigned char *p; if (s->state == SSL2_ST_SEND_SERVER_VERIFY_A) { p=(unsigned char *)s->init_buf->data; *(p++)=SSL2_MT_SERVER_VERIFY; if (s->s2->challenge_length > sizeof s->s2->challenge) { SSLerr(SSL_F_SERVER_VERIFY, ERR_R_INTERNAL_ERROR); return -1; } memcpy(p,s->s2->challenge,(unsigned int)s->s2->challenge_length); /* p+=s->s2->challenge_length; */ s->state=SSL2_ST_SEND_SERVER_VERIFY_B; s->init_num=s->s2->challenge_length+1; s->init_off=0; } return(ssl2_do_write(s)); } static int server_finish(SSL *s) { unsigned char *p; if (s->state == SSL2_ST_SEND_SERVER_FINISHED_A) { p=(unsigned char *)s->init_buf->data; *(p++)=SSL2_MT_SERVER_FINISHED; if (s->session->session_id_length > sizeof s->session->session_id) { SSLerr(SSL_F_SERVER_FINISH, ERR_R_INTERNAL_ERROR); return -1; } memcpy(p,s->session->session_id, (unsigned int)s->session->session_id_length); /* p+=s->session->session_id_length; */ s->state=SSL2_ST_SEND_SERVER_FINISHED_B; s->init_num=s->session->session_id_length+1; s->init_off=0; } /* SSL2_ST_SEND_SERVER_FINISHED_B */ return(ssl2_do_write(s)); } /* send the request and check the response */ static int request_certificate(SSL *s) { const unsigned char *cp; unsigned char *p,*p2,*buf2; unsigned char *ccd; int i,j,ctype,ret= -1; unsigned long len; X509 *x509=NULL; STACK_OF(X509) *sk=NULL; ccd=s->s2->tmp.ccl; if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_A) { p=(unsigned char *)s->init_buf->data; *(p++)=SSL2_MT_REQUEST_CERTIFICATE; *(p++)=SSL2_AT_MD5_WITH_RSA_ENCRYPTION; if (RAND_pseudo_bytes(ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH) <= 0) return -1; memcpy(p,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH); s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_B; s->init_num=SSL2_MIN_CERT_CHALLENGE_LENGTH+2; s->init_off=0; } if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_B) { i=ssl2_do_write(s); if (i <= 0) { ret=i; goto end; } s->init_num=0; s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_C; } if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_C) { p=(unsigned char *)s->init_buf->data; i=ssl2_read(s,(char *)&(p[s->init_num]),6-s->init_num); /* try to read 6 octets ... */ if (i < 3-s->init_num) /* ... but don't call ssl2_part_read now if we got at least 3 * (probably NO-CERTIFICATE-ERROR) */ { ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i); goto end; } s->init_num += i; if ((s->init_num >= 3) && (p[0] == SSL2_MT_ERROR)) { n2s(p,i); if (i != SSL2_PE_NO_CERTIFICATE) { /* not the error message we expected -- let ssl2_part_read handle it */ s->init_num -= 3; ret = ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE, 3); goto end; } if (s->msg_callback) s->msg_callback(0, s->version, 0, p, 3, s, s->msg_callback_arg); /* ERROR */ /* this is the one place where we can recover from an SSL 2.0 error */ if (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE); SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); goto end; } ret=1; goto end; } if ((*(p++) != SSL2_MT_CLIENT_CERTIFICATE) || (s->init_num < 6)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_SHORT_READ); goto end; } if (s->init_num != 6) { SSLerr(SSL_F_REQUEST_CERTIFICATE, ERR_R_INTERNAL_ERROR); goto end; } /* ok we have a response */ /* certificate type, there is only one right now. */ ctype= *(p++); if (ctype != SSL2_AT_MD5_WITH_RSA_ENCRYPTION) { ssl2_return_error(s,SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE); SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_RESPONSE_ARGUMENT); goto end; } n2s(p,i); s->s2->tmp.clen=i; n2s(p,i); s->s2->tmp.rlen=i; s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_D; } /* SSL2_ST_SEND_REQUEST_CERTIFICATE_D */ p=(unsigned char *)s->init_buf->data; len = 6 + (unsigned long)s->s2->tmp.clen + (unsigned long)s->s2->tmp.rlen; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_MESSAGE_TOO_LONG); goto end; } j = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),j); if (i < j) { ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i); goto end; } if (s->msg_callback) s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-CERTIFICATE */ p += 6; cp = p; x509=(X509 *)d2i_X509(NULL,&cp,(long)s->s2->tmp.clen); if (x509 == NULL) { SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_X509_LIB); goto msg_end; } if (((sk=sk_X509_new_null()) == NULL) || (!sk_X509_push(sk,x509))) { SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE); goto msg_end; } i=ssl_verify_cert_chain(s,sk); if (i > 0) /* we like the packet, now check the chksum */ { EVP_MD_CTX ctx; EVP_PKEY *pkey=NULL; EVP_MD_CTX_init(&ctx); EVP_VerifyInit_ex(&ctx,s->ctx->rsa_md5, NULL); EVP_VerifyUpdate(&ctx,s->s2->key_material, s->s2->key_material_length); EVP_VerifyUpdate(&ctx,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH); i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL); buf2=OPENSSL_malloc((unsigned int)i); if (buf2 == NULL) { SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE); goto msg_end; } p2=buf2; i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&p2); EVP_VerifyUpdate(&ctx,buf2,(unsigned int)i); OPENSSL_free(buf2); pkey=X509_get_pubkey(x509); if (pkey == NULL) goto end; i=EVP_VerifyFinal(&ctx,cp,s->s2->tmp.rlen,pkey); EVP_PKEY_free(pkey); EVP_MD_CTX_cleanup(&ctx); if (i > 0) { if (s->session->peer != NULL) X509_free(s->session->peer); s->session->peer=x509; CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); s->session->verify_result = s->verify_result; ret=1; goto end; } else { SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_CHECKSUM); goto msg_end; } } else { msg_end: ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE); } end: sk_X509_free(sk); X509_free(x509); return(ret); } static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from, unsigned char *to, int padding) { RSA *rsa; int i; if ((c == NULL) || (c->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL)) { SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_NO_PRIVATEKEY); return(-1); } if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey->type != EVP_PKEY_RSA) { SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_PUBLIC_KEY_IS_NOT_RSA); return(-1); } rsa=c->pkeys[SSL_PKEY_RSA_ENC].privatekey->pkey.rsa; /* we have the public key */ i=RSA_private_decrypt(len,from,to,rsa,padding); if (i < 0) SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,ERR_R_RSA_LIB); return(i); } #else /* !OPENSSL_NO_SSL2 */ # if PEDANTIC static void *dummy=&dummy; # endif #endif Index: releng/8.4/secure/lib/libcrypto/man/d2i_X509.3 =================================================================== --- releng/8.4/secure/lib/libcrypto/man/d2i_X509.3 (revision 280267) +++ releng/8.4/secure/lib/libcrypto/man/d2i_X509.3 (revision 280268) @@ -1,369 +1,377 @@ .\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "d2i_X509 3" .TH d2i_X509 3 "2015-01-08" "0.9.8zd" "OpenSSL" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio, i2d_X509_fp \- X509 encode and decode functions .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& #include \& \& X509 *d2i_X509(X509 **px, const unsigned char **in, int len); \& int i2d_X509(X509 *x, unsigned char **out); \& \& X509 *d2i_X509_bio(BIO *bp, X509 **x); \& X509 *d2i_X509_fp(FILE *fp, X509 **x); \& \& int i2d_X509_bio(BIO *bp, X509 *x); \& int i2d_X509_fp(FILE *fp, X509 *x); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" The X509 encode and decode routines encode and parse an \&\fBX509\fR structure, which represents an X509 certificate. .PP \&\fId2i_X509()\fR attempts to decode \fBlen\fR bytes at \fB*in\fR. If successful a pointer to the \fBX509\fR structure is returned. If an error occurred then \fB\s-1NULL\s0\fR is returned. If \fBpx\fR is not \fB\s-1NULL\s0\fR then the returned structure is written to \fB*px\fR. If \fB*px\fR is not \fB\s-1NULL\s0\fR then it is assumed that \fB*px\fR contains a valid \fBX509\fR structure and an attempt is made to reuse it. If the call is successful \fB*in\fR is incremented to the byte following the parsed data. .PP \&\fIi2d_X509()\fR encodes the structure pointed to by \fBx\fR into \s-1DER\s0 format. If \fBout\fR is not \fB\s-1NULL\s0\fR is writes the \s-1DER\s0 encoded data to the buffer at \fB*out\fR, and increments it to point after the data just written. If the return value is negative an error occurred, otherwise it returns the length of the encoded data. .PP For OpenSSL 0.9.7 and later if \fB*out\fR is \fB\s-1NULL\s0\fR memory will be allocated for a buffer and the encoded data written to it. In this case \fB*out\fR is not incremented and it points to the start of the data just written. .PP \&\fId2i_X509_bio()\fR is similar to \fId2i_X509()\fR except it attempts to parse data from \s-1BIO \s0\fBbp\fR. .PP \&\fId2i_X509_fp()\fR is similar to \fId2i_X509()\fR except it attempts to parse data from \s-1FILE\s0 pointer \fBfp\fR. .PP \&\fIi2d_X509_bio()\fR is similar to \fIi2d_X509()\fR except it writes the encoding of the structure \fBx\fR to \s-1BIO \s0\fBbp\fR and it returns 1 for success and 0 for failure. .PP \&\fIi2d_X509_fp()\fR is similar to \fIi2d_X509()\fR except it writes the encoding of the structure \fBx\fR to \s-1BIO \s0\fBbp\fR and it returns 1 for success and 0 for failure. .SH "NOTES" .IX Header "NOTES" The letters \fBi\fR and \fBd\fR in for example \fBi2d_X509\fR stand for \&\*(L"internal\*(R" (that is an internal C structure) and \*(L"\s-1DER\*(R".\s0 So that \&\fBi2d_X509\fR converts from internal to \s-1DER.\s0 .PP The functions can also understand \fB\s-1BER\s0\fR forms. .PP The actual X509 structure passed to \fIi2d_X509()\fR must be a valid populated \fBX509\fR structure it can \fBnot\fR simply be fed with an empty structure such as that returned by \fIX509_new()\fR. .PP The encoded data is in binary form and may contain embedded zeroes. Therefore any \s-1FILE\s0 pointers or BIOs should be opened in binary mode. Functions such as \fB\f(BIstrlen()\fB\fR will \fBnot\fR return the correct length of the encoded structure. .PP The ways that \fB*in\fR and \fB*out\fR are incremented after the operation can trap the unwary. See the \fB\s-1WARNINGS\s0\fR section for some common errors. .PP The reason for the auto increment behaviour is to reflect a typical usage of \s-1ASN1\s0 functions: after one structure is encoded or decoded another will processed after it. .SH "EXAMPLES" .IX Header "EXAMPLES" Allocate and encode the \s-1DER\s0 encoding of an X509 structure: .PP .Vb 2 \& int len; \& unsigned char *buf, *p; \& \& len = i2d_X509(x, NULL); \& \& buf = OPENSSL_malloc(len); \& \& if (buf == NULL) \& /* error */ \& \& p = buf; \& \& i2d_X509(x, &p); .Ve .PP If you are using OpenSSL 0.9.7 or later then this can be simplified to: .PP .Vb 2 \& int len; \& unsigned char *buf; \& \& buf = NULL; \& \& len = i2d_X509(x, &buf); \& \& if (len < 0) \& /* error */ .Ve .PP Attempt to decode a buffer: .PP .Vb 1 \& X509 *x; \& \& unsigned char *buf, *p; \& \& int len; \& \& /* Something to setup buf and len */ \& \& p = buf; \& \& x = d2i_X509(NULL, &p, len); \& \& if (x == NULL) \& /* Some error */ .Ve .PP Alternative technique: .PP .Vb 1 \& X509 *x; \& \& unsigned char *buf, *p; \& \& int len; \& \& /* Something to setup buf and len */ \& \& p = buf; \& \& x = NULL; \& \& if(!d2i_X509(&x, &p, len)) \& /* Some error */ .Ve .SH "WARNINGS" .IX Header "WARNINGS" The use of temporary variable is mandatory. A common mistake is to attempt to use a buffer directly as follows: .PP .Vb 2 \& int len; \& unsigned char *buf; \& \& len = i2d_X509(x, NULL); \& \& buf = OPENSSL_malloc(len); \& \& if (buf == NULL) \& /* error */ \& \& i2d_X509(x, &buf); \& \& /* Other stuff ... */ \& \& OPENSSL_free(buf); .Ve .PP This code will result in \fBbuf\fR apparently containing garbage because it was incremented after the call to point after the data just written. Also \fBbuf\fR will no longer contain the pointer allocated by \fB\f(BIOPENSSL_malloc()\fB\fR and the subsequent call to \fB\f(BIOPENSSL_free()\fB\fR may well crash. .PP The auto allocation feature (setting buf to \s-1NULL\s0) only works on OpenSSL 0.9.7 and later. Attempts to use it on earlier versions will typically cause a segmentation violation. .PP Another trap to avoid is misuse of the \fBxp\fR argument to \fB\f(BId2i_X509()\fB\fR: .PP .Vb 1 \& X509 *x; \& \& if (!d2i_X509(&x, &p, len)) \& /* Some error */ .Ve .PP This will probably crash somewhere in \fB\f(BId2i_X509()\fB\fR. The reason for this is that the variable \fBx\fR is uninitialized and an attempt will be made to interpret its (invalid) value as an \fBX509\fR structure, typically causing a segmentation violation. If \fBx\fR is set to \s-1NULL\s0 first then this will not happen. .SH "BUGS" .IX Header "BUGS" In some versions of OpenSSL the \*(L"reuse\*(R" behaviour of \fId2i_X509()\fR when \&\fB*px\fR is valid is broken and some parts of the reused structure may persist if they are not present in the new one. As a result the use of this \*(L"reuse\*(R" behaviour is strongly discouraged. .PP +Current versions of OpenSSL will not modify \fB*px\fR if an error occurs. +If parsing succeeds then \fB*px\fR is freed (if it is not \s-1NULL\s0) and then +set to the value of the newly decoded structure. As a result \fB*px\fR +\&\fBmust not\fR be allocated on the stack or an attempt will be made to +free an invalid pointer. +.PP \&\fIi2d_X509()\fR will not return an error in many versions of OpenSSL, if mandatory fields are not initialized due to a programming error then the encoded structure may contain invalid data or omit the fields entirely and will not be parsed by \fId2i_X509()\fR. This may be fixed in future so code should not assume that \fIi2d_X509()\fR will always succeed. .SH "RETURN VALUES" .IX Header "RETURN VALUES" \&\fId2i_X509()\fR, \fId2i_X509_bio()\fR and \fId2i_X509_fp()\fR return a valid \fBX509\fR structure or \fB\s-1NULL\s0\fR if an error occurs. The error code that can be obtained by -\&\fIERR_get_error\fR\|(3). +\&\fIERR_get_error\fR\|(3). If the \*(L"reuse\*(R" capability has been used +with a valid X509 structure being passed in via \fBpx\fR then the object is not +modified in the event of error. .PP \&\fIi2d_X509()\fR returns the number of bytes successfully encoded or a negative value if an error occurs. The error code can be obtained by \&\fIERR_get_error\fR\|(3). .PP \&\fIi2d_X509_bio()\fR and \fIi2d_X509_fp()\fR return 1 for success and 0 if an error occurs The error code can be obtained by \fIERR_get_error\fR\|(3). .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIERR_get_error\fR\|(3) .SH "HISTORY" .IX Header "HISTORY" d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio and i2d_X509_fp are available in all versions of SSLeay and OpenSSL. Index: releng/9.3/crypto/openssl/crypto/asn1/a_type.c =================================================================== --- releng/9.3/crypto/openssl/crypto/asn1/a_type.c (revision 280267) +++ releng/9.3/crypto/openssl/crypto/asn1/a_type.c (revision 280268) @@ -1,156 +1,159 @@ /* crypto/asn1/a_type.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include "cryptlib.h" #include #include int ASN1_TYPE_get(ASN1_TYPE *a) { if ((a->value.ptr != NULL) || (a->type == V_ASN1_NULL)) return(a->type); else return(0); } void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value) { if (a->value.ptr != NULL) { ASN1_TYPE **tmp_a = &a; ASN1_primitive_free((ASN1_VALUE **)tmp_a, NULL); } a->type=type; a->value.ptr=value; } int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value) { if (!value || (type == V_ASN1_BOOLEAN)) { void *p = (void *)value; ASN1_TYPE_set(a, type, p); } else if (type == V_ASN1_OBJECT) { ASN1_OBJECT *odup; odup = OBJ_dup(value); if (!odup) return 0; ASN1_TYPE_set(a, type, odup); } else { ASN1_STRING *sdup; sdup = ASN1_STRING_dup((ASN1_STRING *)value); if (!sdup) return 0; ASN1_TYPE_set(a, type, sdup); } return 1; } IMPLEMENT_STACK_OF(ASN1_TYPE) IMPLEMENT_ASN1_SET_OF(ASN1_TYPE) /* Returns 0 if they are equal, != 0 otherwise. */ int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b) { int result = -1; if (!a || !b || a->type != b->type) return -1; switch (a->type) { case V_ASN1_OBJECT: result = OBJ_cmp(a->value.object, b->value.object); break; + case V_ASN1_BOOLEAN: + result = a->value.boolean - b->value.boolean; + break; case V_ASN1_NULL: result = 0; /* They do not have content. */ break; case V_ASN1_INTEGER: case V_ASN1_NEG_INTEGER: case V_ASN1_ENUMERATED: case V_ASN1_NEG_ENUMERATED: case V_ASN1_BIT_STRING: case V_ASN1_OCTET_STRING: case V_ASN1_SEQUENCE: case V_ASN1_SET: case V_ASN1_NUMERICSTRING: case V_ASN1_PRINTABLESTRING: case V_ASN1_T61STRING: case V_ASN1_VIDEOTEXSTRING: case V_ASN1_IA5STRING: case V_ASN1_UTCTIME: case V_ASN1_GENERALIZEDTIME: case V_ASN1_GRAPHICSTRING: case V_ASN1_VISIBLESTRING: case V_ASN1_GENERALSTRING: case V_ASN1_UNIVERSALSTRING: case V_ASN1_BMPSTRING: case V_ASN1_UTF8STRING: case V_ASN1_OTHER: default: result = ASN1_STRING_cmp((ASN1_STRING *) a->value.ptr, (ASN1_STRING *) b->value.ptr); break; } return result; } Index: releng/9.3/crypto/openssl/crypto/asn1/tasn_dec.c =================================================================== --- releng/9.3/crypto/openssl/crypto/asn1/tasn_dec.c (revision 280267) +++ releng/9.3/crypto/openssl/crypto/asn1/tasn_dec.c (revision 280268) @@ -1,1351 +1,1376 @@ /* tasn_dec.c */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2000. */ /* ==================================================================== * Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * licensing@OpenSSL.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ #include #include #include #include #include #include #include static int asn1_check_eoc(const unsigned char **in, long len); static int asn1_find_end(const unsigned char **in, long len, char inf); static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, char inf, int tag, int aclass, int depth); static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen); static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst, const unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx); static int asn1_template_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx); static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx); static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx); /* Table to convert tags to bit values, used for MSTRING type */ static const unsigned long tag2bit[32] = { 0, 0, 0, B_ASN1_BIT_STRING, /* tags 0 - 3 */ B_ASN1_OCTET_STRING, 0, 0, B_ASN1_UNKNOWN,/* tags 4- 7 */ B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN,/* tags 8-11 */ B_ASN1_UTF8STRING,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,/* tags 12-15 */ B_ASN1_SEQUENCE,0,B_ASN1_NUMERICSTRING,B_ASN1_PRINTABLESTRING, /* tags 16-19 */ B_ASN1_T61STRING,B_ASN1_VIDEOTEXSTRING,B_ASN1_IA5STRING, /* tags 20-22 */ B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME, /* tags 23-24 */ B_ASN1_GRAPHICSTRING,B_ASN1_ISO64STRING,B_ASN1_GENERALSTRING, /* tags 25-27 */ B_ASN1_UNIVERSALSTRING,B_ASN1_UNKNOWN,B_ASN1_BMPSTRING,B_ASN1_UNKNOWN, /* tags 28-31 */ }; unsigned long ASN1_tag2bit(int tag) { if ((tag < 0) || (tag > 30)) return 0; return tag2bit[tag]; } /* Macro to initialize and invalidate the cache */ #define asn1_tlc_clear(c) if (c) (c)->valid = 0 /* Decode an ASN1 item, this currently behaves just * like a standard 'd2i' function. 'in' points to * a buffer to read the data from, in future we will * have more advanced versions that can input data * a piece at a time and this will simply be a special * case. */ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it) - { +{ ASN1_TLC c; ASN1_VALUE *ptmpval = NULL; - if (!pval) - pval = &ptmpval; c.valid = 0; - if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0) - return *pval; - return NULL; + if (pval && *pval && it->itype == ASN1_ITYPE_PRIMITIVE) + ptmpval = *pval; + + if (ASN1_item_ex_d2i(&ptmpval, in, len, it, -1, 0, 0, &c) > 0) { + if (pval && it->itype != ASN1_ITYPE_PRIMITIVE) { + if (*pval) + ASN1_item_free(*pval, it); + *pval = ptmpval; + } + return ptmpval; } + return NULL; +} int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt) { ASN1_TLC c; c.valid = 0; return asn1_template_ex_d2i(pval, in, len, tt, 0, &c); } /* Decode an item, taking care of IMPLICIT tagging, if any. * If 'opt' set and tag mismatch return -1 to handle OPTIONAL */ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx) { const ASN1_TEMPLATE *tt, *errtt = NULL; const ASN1_COMPAT_FUNCS *cf; const ASN1_EXTERN_FUNCS *ef; const ASN1_AUX *aux = it->funcs; ASN1_aux_cb *asn1_cb; const unsigned char *p = NULL, *q; unsigned char *wp=NULL; /* BIG FAT WARNING! BREAKS CONST WHERE USED */ unsigned char imphack = 0, oclass; char seq_eoc, seq_nolen, cst, isopt; long tmplen; int i; int otag; int ret = 0; ASN1_VALUE **pchptr, *ptmpval; if (!pval) return 0; if (aux && aux->asn1_cb) asn1_cb = aux->asn1_cb; else asn1_cb = 0; switch(it->itype) { case ASN1_ITYPE_PRIMITIVE: if (it->templates) { /* tagging or OPTIONAL is currently illegal on an item * template because the flags can't get passed down. * In practice this isn't a problem: we include the * relevant flags from the item template in the * template itself. */ if ((tag != -1) || opt) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE); goto err; } return asn1_template_ex_d2i(pval, in, len, it->templates, opt, ctx); } return asn1_d2i_ex_primitive(pval, in, len, it, tag, aclass, opt, ctx); break; case ASN1_ITYPE_MSTRING: p = *in; /* Just read in tag and class */ ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, &p, len, -1, 0, 1, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } /* Must be UNIVERSAL class */ if (oclass != V_ASN1_UNIVERSAL) { /* If OPTIONAL, assume this is OK */ if (opt) return -1; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_NOT_UNIVERSAL); goto err; } /* Check tag matches bit map */ if (!(ASN1_tag2bit(otag) & it->utype)) { /* If OPTIONAL, assume this is OK */ if (opt) return -1; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_WRONG_TAG); goto err; } return asn1_d2i_ex_primitive(pval, in, len, it, otag, 0, 0, ctx); case ASN1_ITYPE_EXTERN: /* Use new style d2i */ ef = it->funcs; return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx); case ASN1_ITYPE_COMPAT: /* we must resort to old style evil hackery */ cf = it->funcs; /* If OPTIONAL see if it is there */ if (opt) { int exptag; p = *in; if (tag == -1) exptag = it->utype; else exptag = tag; /* Don't care about anything other than presence * of expected tag */ ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL, &p, len, exptag, aclass, 1, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } if (ret == -1) return -1; } /* This is the old style evil hack IMPLICIT handling: * since the underlying code is expecting a tag and * class other than the one present we change the * buffer temporarily then change it back afterwards. * This doesn't and never did work for tags > 30. * * Yes this is *horrible* but it is only needed for * old style d2i which will hopefully not be around * for much longer. * FIXME: should copy the buffer then modify it so * the input buffer can be const: we should *always* * copy because the old style d2i might modify the * buffer. */ if (tag != -1) { wp = *(unsigned char **)in; imphack = *wp; if (p == NULL) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } *wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED) | it->utype); } ptmpval = cf->asn1_d2i(pval, in, len); if (tag != -1) *wp = imphack; if (ptmpval) return 1; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; case ASN1_ITYPE_CHOICE: if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it)) goto auxerr; - /* Allocate structure */ - if (!*pval && !ASN1_item_ex_new(pval, it)) - { + if (*pval) { + /* Free up and zero CHOICE value if initialised */ + i = asn1_get_choice_selector(pval, it); + if ((i >= 0) && (i < it->tcount)) { + tt = it->templates + i; + pchptr = asn1_get_field_ptr(pval, tt); + ASN1_template_free(pchptr, tt); + asn1_set_choice_selector(pval, -1, it); + } + } else if (!ASN1_item_ex_new(pval, it)) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; - } + } /* CHOICE type, try each possibility in turn */ p = *in; for (i = 0, tt=it->templates; i < it->tcount; i++, tt++) { pchptr = asn1_get_field_ptr(pval, tt); /* We mark field as OPTIONAL so its absence * can be recognised. */ ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx); /* If field not present, try the next one */ if (ret == -1) continue; /* If positive return, read OK, break loop */ if (ret > 0) break; /* Otherwise must be an ASN1 parsing error */ errtt = tt; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } /* Did we fall off the end without reading anything? */ if (i == it->tcount) { /* If OPTIONAL, this is OK */ if (opt) { /* Free and zero it */ ASN1_item_ex_free(pval, it); return -1; } ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_NO_MATCHING_CHOICE_TYPE); goto err; } asn1_set_choice_selector(pval, i, it); *in = p; if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it)) goto auxerr; return 1; case ASN1_ITYPE_NDEF_SEQUENCE: case ASN1_ITYPE_SEQUENCE: p = *in; tmplen = len; /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ if (tag == -1) { tag = V_ASN1_SEQUENCE; aclass = V_ASN1_UNIVERSAL; } /* Get SEQUENCE length and update len, p */ ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst, &p, len, tag, aclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if (ret == -1) return -1; if (aux && (aux->flags & ASN1_AFLG_BROKEN)) { len = tmplen - (p - *in); seq_nolen = 1; } /* If indefinite we don't do a length check */ else seq_nolen = seq_eoc; if (!cst) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_NOT_CONSTRUCTED); goto err; } if (!*pval && !ASN1_item_ex_new(pval, it)) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it)) goto auxerr; + + /* Free up and zero any ADB found */ + for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { + if (tt->flags & ASN1_TFLG_ADB_MASK) { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + pseqval = asn1_get_field_ptr(pval, seqtt); + ASN1_template_free(pseqval, seqtt); + } + } /* Get each field entry */ for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { const ASN1_TEMPLATE *seqtt; ASN1_VALUE **pseqval; seqtt = asn1_do_adb(pval, tt, 1); if (!seqtt) goto err; pseqval = asn1_get_field_ptr(pval, seqtt); /* Have we ran out of data? */ if (!len) break; q = p; if (asn1_check_eoc(&p, len)) { if (!seq_eoc) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_UNEXPECTED_EOC); goto err; } len -= p - q; seq_eoc = 0; q = p; break; } /* This determines the OPTIONAL flag value. The field * cannot be omitted if it is the last of a SEQUENCE * and there is still data to be read. This isn't * strictly necessary but it increases efficiency in * some cases. */ if (i == (it->tcount - 1)) isopt = 0; else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL); /* attempt to read in field, allowing each to be * OPTIONAL */ ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx); if (!ret) { errtt = seqtt; goto err; } else if (ret == -1) { /* OPTIONAL component absent. * Free and zero the field. */ ASN1_template_free(pseqval, seqtt); continue; } /* Update length */ len -= p - q; } /* Check for EOC if expecting one */ if (seq_eoc && !asn1_check_eoc(&p, len)) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MISSING_EOC); goto err; } /* Check all data read */ if (!seq_nolen && len) { ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_LENGTH_MISMATCH); goto err; } /* If we get here we've got no more data in the SEQUENCE, * however we may not have read all fields so check all * remaining are OPTIONAL and clear any that are. */ for (; i < it->tcount; tt++, i++) { const ASN1_TEMPLATE *seqtt; seqtt = asn1_do_adb(pval, tt, 1); if (!seqtt) goto err; if (seqtt->flags & ASN1_TFLG_OPTIONAL) { ASN1_VALUE **pseqval; pseqval = asn1_get_field_ptr(pval, seqtt); ASN1_template_free(pseqval, seqtt); } else { errtt = seqtt; ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_FIELD_MISSING); goto err; } } /* Save encoding */ if (!asn1_enc_save(pval, *in, p - *in, it)) goto auxerr; *in = p; if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it)) goto auxerr; return 1; default: return 0; } auxerr: ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_AUX_ERROR); err: ASN1_item_ex_free(pval, it); if (errtt) ERR_add_error_data(4, "Field=", errtt->field_name, ", Type=", it->sname); else ERR_add_error_data(2, "Type=", it->sname); return 0; } /* Templates are handled with two separate functions. * One handles any EXPLICIT tag and the other handles the rest. */ static int asn1_template_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx) { int flags, aclass; int ret; long len; const unsigned char *p, *q; char exp_eoc; if (!val) return 0; flags = tt->flags; aclass = flags & ASN1_TFLG_TAG_CLASS; p = *in; /* Check if EXPLICIT tag expected */ if (flags & ASN1_TFLG_EXPTAG) { char cst; /* Need to work out amount of data available to the inner * content and where it starts: so read in EXPLICIT header to * get the info. */ ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst, &p, inlen, tt->tag, aclass, opt, ctx); q = p; if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR); return 0; } else if (ret == -1) return -1; if (!cst) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED); return 0; } /* We've found the field so it can't be OPTIONAL now */ ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR); return 0; } /* We read the field in OK so update length */ len -= p - q; if (exp_eoc) { /* If NDEF we must have an EOC here */ if (!asn1_check_eoc(&p, len)) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_MISSING_EOC); goto err; } } else { /* Otherwise we must hit the EXPLICIT tag end or its * an error */ if (len) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_EXPLICIT_LENGTH_MISMATCH); goto err; } } } else return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx); *in = p; return 1; err: ASN1_template_free(val, tt); return 0; } static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx) { int flags, aclass; int ret; const unsigned char *p, *q; if (!val) return 0; flags = tt->flags; aclass = flags & ASN1_TFLG_TAG_CLASS; p = *in; q = p; if (flags & ASN1_TFLG_SK_MASK) { /* SET OF, SEQUENCE OF */ int sktag, skaclass; char sk_eoc; /* First work out expected inner tag value */ if (flags & ASN1_TFLG_IMPTAG) { sktag = tt->tag; skaclass = aclass; } else { skaclass = V_ASN1_UNIVERSAL; if (flags & ASN1_TFLG_SET_OF) sktag = V_ASN1_SET; else sktag = V_ASN1_SEQUENCE; } /* Get the tag */ ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL, &p, len, sktag, skaclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); return 0; } else if (ret == -1) return -1; if (!*val) *val = (ASN1_VALUE *)sk_new_null(); else { /* We've got a valid STACK: free up any items present */ STACK *sktmp = (STACK *)*val; ASN1_VALUE *vtmp; while(sk_num(sktmp) > 0) { vtmp = (ASN1_VALUE *)sk_pop(sktmp); ASN1_item_ex_free(&vtmp, ASN1_ITEM_ptr(tt->item)); } } if (!*val) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_MALLOC_FAILURE); goto err; } /* Read as many items as we can */ while(len > 0) { ASN1_VALUE *skfield; q = p; /* See if EOC found */ if (asn1_check_eoc(&p, len)) { if (!sk_eoc) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1_R_UNEXPECTED_EOC); goto err; } len -= p - q; sk_eoc = 0; break; } skfield = NULL; if (!ASN1_item_ex_d2i(&skfield, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } len -= p - q; if (!sk_push((STACK *)*val, (char *)skfield)) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_MALLOC_FAILURE); goto err; } } if (sk_eoc) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1_R_MISSING_EOC); goto err; } } else if (flags & ASN1_TFLG_IMPTAG) { /* IMPLICIT tagging */ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if (ret == -1) return -1; } else { /* Nothing special */ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if (ret == -1) return -1; } *in = p; return 1; err: ASN1_template_free(val, tt); return 0; } static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx) { int ret = 0, utype; long plen; char cst, inf, free_cont = 0; const unsigned char *p; BUF_MEM buf; const unsigned char *cont = NULL; long len; if (!pval) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_NULL); return 0; /* Should never happen */ } if (it->itype == ASN1_ITYPE_MSTRING) { utype = tag; tag = -1; } else utype = it->utype; if (utype == V_ASN1_ANY) { /* If type is ANY need to figure out type from tag */ unsigned char oclass; if (tag >= 0) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_TAGGED_ANY); return 0; } if (opt) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_OPTIONAL_ANY); return 0; } p = *in; ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL, &p, inlen, -1, 0, 0, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR); return 0; } if (oclass != V_ASN1_UNIVERSAL) utype = V_ASN1_OTHER; } if (tag == -1) { tag = utype; aclass = V_ASN1_UNIVERSAL; } p = *in; /* Check header */ ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst, &p, inlen, tag, aclass, opt, ctx); if (!ret) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR); return 0; } else if (ret == -1) return -1; ret = 0; /* SEQUENCE, SET and "OTHER" are left in encoded form */ if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) { /* Clear context cache for type OTHER because the auto clear * when we have a exact match wont work */ if (utype == V_ASN1_OTHER) { asn1_tlc_clear(ctx); } /* SEQUENCE and SET must be constructed */ else if (!cst) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_TYPE_NOT_CONSTRUCTED); return 0; } cont = *in; /* If indefinite length constructed find the real end */ if (inf) { if (!asn1_find_end(&p, plen, inf)) goto err; len = p - cont; } else { len = p - cont + plen; p += plen; buf.data = NULL; } } else if (cst) { if (utype == V_ASN1_NULL || utype == V_ASN1_BOOLEAN || utype == V_ASN1_OBJECT || utype == V_ASN1_INTEGER || utype == V_ASN1_ENUMERATED) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_TYPE_NOT_PRIMITIVE); return 0; } buf.length = 0; buf.max = 0; buf.data = NULL; /* Should really check the internal tags are correct but * some things may get this wrong. The relevant specs * say that constructed string types should be OCTET STRINGs * internally irrespective of the type. So instead just check * for UNIVERSAL class and ignore the tag. */ if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) { free_cont = 1; goto err; } len = buf.length; /* Append a final null to string */ if (!BUF_MEM_grow_clean(&buf, len + 1)) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE); return 0; } buf.data[len] = 0; cont = (const unsigned char *)buf.data; free_cont = 1; } else { cont = p; len = plen; p += plen; } /* We now have content length and type: translate into a structure */ if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it)) goto err; *in = p; ret = 1; err: if (free_cont && buf.data) OPENSSL_free(buf.data); return ret; } /* Translate ASN1 content octets into a structure */ int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it) { ASN1_VALUE **opval = NULL; ASN1_STRING *stmp; ASN1_TYPE *typ = NULL; int ret = 0; const ASN1_PRIMITIVE_FUNCS *pf; ASN1_INTEGER **tint; pf = it->funcs; if (pf && pf->prim_c2i) return pf->prim_c2i(pval, cont, len, utype, free_cont, it); /* If ANY type clear type and set pointer to internal value */ if (it->utype == V_ASN1_ANY) { if (!*pval) { typ = ASN1_TYPE_new(); if (typ == NULL) goto err; *pval = (ASN1_VALUE *)typ; } else typ = (ASN1_TYPE *)*pval; if (utype != typ->type) ASN1_TYPE_set(typ, utype, NULL); opval = pval; pval = &typ->value.asn1_value; } switch(utype) { case V_ASN1_OBJECT: if (!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len)) goto err; break; case V_ASN1_NULL: if (len) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_NULL_IS_WRONG_LENGTH); goto err; } *pval = (ASN1_VALUE *)1; break; case V_ASN1_BOOLEAN: if (len != 1) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_BOOLEAN_IS_WRONG_LENGTH); goto err; } else { ASN1_BOOLEAN *tbool; tbool = (ASN1_BOOLEAN *)pval; *tbool = *cont; } break; case V_ASN1_BIT_STRING: if (!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len)) goto err; break; case V_ASN1_INTEGER: case V_ASN1_NEG_INTEGER: case V_ASN1_ENUMERATED: case V_ASN1_NEG_ENUMERATED: tint = (ASN1_INTEGER **)pval; if (!c2i_ASN1_INTEGER(tint, &cont, len)) goto err; /* Fixup type to match the expected form */ (*tint)->type = utype | ((*tint)->type & V_ASN1_NEG); break; case V_ASN1_OCTET_STRING: case V_ASN1_NUMERICSTRING: case V_ASN1_PRINTABLESTRING: case V_ASN1_T61STRING: case V_ASN1_VIDEOTEXSTRING: case V_ASN1_IA5STRING: case V_ASN1_UTCTIME: case V_ASN1_GENERALIZEDTIME: case V_ASN1_GRAPHICSTRING: case V_ASN1_VISIBLESTRING: case V_ASN1_GENERALSTRING: case V_ASN1_UNIVERSALSTRING: case V_ASN1_BMPSTRING: case V_ASN1_UTF8STRING: case V_ASN1_OTHER: case V_ASN1_SET: case V_ASN1_SEQUENCE: default: if (utype == V_ASN1_BMPSTRING && (len & 1)) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_BMPSTRING_IS_WRONG_LENGTH); goto err; } if (utype == V_ASN1_UNIVERSALSTRING && (len & 3)) { ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH); goto err; } /* All based on ASN1_STRING and handled the same */ if (!*pval) { stmp = ASN1_STRING_type_new(utype); if (!stmp) { ASN1err(ASN1_F_ASN1_EX_C2I, ERR_R_MALLOC_FAILURE); goto err; } *pval = (ASN1_VALUE *)stmp; } else { stmp = (ASN1_STRING *)*pval; stmp->type = utype; } /* If we've already allocated a buffer use it */ if (*free_cont) { if (stmp->data) OPENSSL_free(stmp->data); stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */ stmp->length = len; *free_cont = 0; } else { if (!ASN1_STRING_set(stmp, cont, len)) { ASN1err(ASN1_F_ASN1_EX_C2I, ERR_R_MALLOC_FAILURE); ASN1_STRING_free(stmp); *pval = NULL; goto err; } } break; } /* If ASN1_ANY and NULL type fix up value */ if (typ && (utype == V_ASN1_NULL)) typ->value.ptr = NULL; ret = 1; err: if (!ret) { ASN1_TYPE_free(typ); if (opval) *opval = NULL; } return ret; } /* This function finds the end of an ASN1 structure when passed its maximum * length, whether it is indefinite length and a pointer to the content. * This is more efficient than calling asn1_collect because it does not * recurse on each indefinite length header. */ static int asn1_find_end(const unsigned char **in, long len, char inf) { int expected_eoc; long plen; const unsigned char *p = *in, *q; /* If not indefinite length constructed just add length */ if (inf == 0) { *in += len; return 1; } expected_eoc = 1; /* Indefinite length constructed form. Find the end when enough EOCs * are found. If more indefinite length constructed headers * are encountered increment the expected eoc count otherwise just * skip to the end of the data. */ while (len > 0) { if(asn1_check_eoc(&p, len)) { expected_eoc--; if (expected_eoc == 0) break; len -= 2; continue; } q = p; /* Just read in a header: only care about the length */ if(!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len, -1, 0, 0, NULL)) { ASN1err(ASN1_F_ASN1_FIND_END, ERR_R_NESTED_ASN1_ERROR); return 0; } if (inf) expected_eoc++; else p += plen; len -= p - q; } if (expected_eoc) { ASN1err(ASN1_F_ASN1_FIND_END, ASN1_R_MISSING_EOC); return 0; } *in = p; return 1; } /* This function collects the asn1 data from a constructred string * type into a buffer. The values of 'in' and 'len' should refer * to the contents of the constructed type and 'inf' should be set * if it is indefinite length. */ #ifndef ASN1_MAX_STRING_NEST /* This determines how many levels of recursion are permitted in ASN1 * string types. If it is not limited stack overflows can occur. If set * to zero no recursion is allowed at all. Although zero should be adequate * examples exist that require a value of 1. So 5 should be more than enough. */ #define ASN1_MAX_STRING_NEST 5 #endif static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, char inf, int tag, int aclass, int depth) { const unsigned char *p, *q; long plen; char cst, ininf; p = *in; inf &= 1; /* If no buffer and not indefinite length constructed just pass over * the encoded data */ if (!buf && !inf) { *in += len; return 1; } while(len > 0) { q = p; /* Check for EOC */ if (asn1_check_eoc(&p, len)) { /* EOC is illegal outside indefinite length * constructed form */ if (!inf) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_UNEXPECTED_EOC); return 0; } inf = 0; break; } if (!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p, len, tag, aclass, 0, NULL)) { ASN1err(ASN1_F_ASN1_COLLECT, ERR_R_NESTED_ASN1_ERROR); return 0; } /* If indefinite length constructed update max length */ if (cst) { if (depth >= ASN1_MAX_STRING_NEST) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_NESTED_ASN1_STRING); return 0; } if (!asn1_collect(buf, &p, plen, ininf, tag, aclass, depth + 1)) return 0; } else if (plen && !collect_data(buf, &p, plen)) return 0; len -= p - q; } if (inf) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_MISSING_EOC); return 0; } *in = p; return 1; } static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen) { int len; if (buf) { len = buf->length; if (!BUF_MEM_grow_clean(buf, len + plen)) { ASN1err(ASN1_F_COLLECT_DATA, ERR_R_MALLOC_FAILURE); return 0; } memcpy(buf->data + len, *p, plen); } *p += plen; return 1; } /* Check for ASN1 EOC and swallow it if found */ static int asn1_check_eoc(const unsigned char **in, long len) { const unsigned char *p; if (len < 2) return 0; p = *in; if (!p[0] && !p[1]) { *in += 2; return 1; } return 0; } /* Check an ASN1 tag and length: a bit like ASN1_get_object * but it sets the length for indefinite length constructed * form, we don't know the exact length but we can set an * upper bound to the amount of data available minus the * header length just read. */ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst, const unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx) { int i; int ptag, pclass; long plen; const unsigned char *p, *q; p = *in; q = p; if (ctx && ctx->valid) { i = ctx->ret; plen = ctx->plen; pclass = ctx->pclass; ptag = ctx->ptag; p += ctx->hdrlen; } else { i = ASN1_get_object(&p, &plen, &ptag, &pclass, len); if (ctx) { ctx->ret = i; ctx->plen = plen; ctx->pclass = pclass; ctx->ptag = ptag; ctx->hdrlen = p - q; ctx->valid = 1; /* If definite length, and no error, length + * header can't exceed total amount of data available. */ if (!(i & 0x81) && ((plen + ctx->hdrlen) > len)) { ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_TOO_LONG); asn1_tlc_clear(ctx); return 0; } } } if (i & 0x80) { ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_BAD_OBJECT_HEADER); asn1_tlc_clear(ctx); return 0; } if (exptag >= 0) { if ((exptag != ptag) || (expclass != pclass)) { /* If type is OPTIONAL, not an error: * indicate missing type. */ if (opt) return -1; asn1_tlc_clear(ctx); ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG); return 0; } /* We have a tag and class match: * assume we are going to do something with it */ asn1_tlc_clear(ctx); } if (i & 1) plen = len - (p - q); if (inf) *inf = i & 1; if (cst) *cst = i & V_ASN1_CONSTRUCTED; if (olen) *olen = plen; if (oclass) *oclass = pclass; if (otag) *otag = ptag; *in = p; return 1; } Index: releng/9.3/crypto/openssl/crypto/pkcs7/pk7_doit.c =================================================================== --- releng/9.3/crypto/openssl/crypto/pkcs7/pk7_doit.c (revision 280267) +++ releng/9.3/crypto/openssl/crypto/pkcs7/pk7_doit.c (revision 280268) @@ -1,1177 +1,1233 @@ /* crypto/pkcs7/pk7_doit.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include "cryptlib.h" #include #include #include #include #include static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, void *value); static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid); static int PKCS7_type_is_other(PKCS7* p7) { int isOther=1; int nid=OBJ_obj2nid(p7->type); switch( nid ) { case NID_pkcs7_data: case NID_pkcs7_signed: case NID_pkcs7_enveloped: case NID_pkcs7_signedAndEnveloped: case NID_pkcs7_digest: case NID_pkcs7_encrypted: isOther=0; break; default: isOther=1; } return isOther; } static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7) { if ( PKCS7_type_is_data(p7)) return p7->d.data; if ( PKCS7_type_is_other(p7) && p7->d.other && (p7->d.other->type == V_ASN1_OCTET_STRING)) return p7->d.other->value.octet_string; return NULL; } static int PKCS7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) { BIO *btmp; const EVP_MD *md; if ((btmp=BIO_new(BIO_f_md())) == NULL) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB); goto err; } md=EVP_get_digestbyobj(alg->algorithm); if (md == NULL) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,PKCS7_R_UNKNOWN_DIGEST_TYPE); goto err; } BIO_set_md(btmp,md); if (*pbio == NULL) *pbio=btmp; else if (!BIO_push(*pbio,btmp)) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB); goto err; } btmp=NULL; return 1; err: if (btmp) BIO_free(btmp); return 0; } BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { int i; BIO *out=NULL,*btmp=NULL; X509_ALGOR *xa = NULL; const EVP_CIPHER *evp_cipher=NULL; STACK_OF(X509_ALGOR) *md_sk=NULL; STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; X509_ALGOR *xalg=NULL; PKCS7_RECIP_INFO *ri=NULL; EVP_PKEY *pkey; ASN1_OCTET_STRING *os=NULL; + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_INVALID_NULL_POINTER); + return NULL; + } + /* + * The content field in the PKCS7 ContentInfo is optional, but that really + * only applies to inner content (precisely, detached signatures). + * + * When reading content, missing outer content is therefore treated as an + * error. + * + * When creating content, PKCS7_content_new() must be called before + * calling this method, so a NULL p7->d is always an error. + */ + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_NO_CONTENT); + return NULL; + } + i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signed: md_sk=p7->d.sign->md_algs; os = PKCS7_get_octet_string(p7->d.sign->contents); break; case NID_pkcs7_signedAndEnveloped: rsk=p7->d.signed_and_enveloped->recipientinfo; md_sk=p7->d.signed_and_enveloped->md_algs; xalg=p7->d.signed_and_enveloped->enc_data->algorithm; evp_cipher=p7->d.signed_and_enveloped->enc_data->cipher; if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED); goto err; } break; case NID_pkcs7_enveloped: rsk=p7->d.enveloped->recipientinfo; xalg=p7->d.enveloped->enc_data->algorithm; evp_cipher=p7->d.enveloped->enc_data->cipher; if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED); goto err; } break; case NID_pkcs7_digest: xa = p7->d.digest->md; os = PKCS7_get_octet_string(p7->d.digest->contents); break; default: PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } for (i=0; ialgorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher)); if (ivlen > 0) if (RAND_pseudo_bytes(iv,ivlen) <= 0) goto err; if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1)<=0) goto err; if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0) goto err; if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0) goto err; if (ivlen > 0) { if (xalg->parameter == NULL) { xalg->parameter = ASN1_TYPE_new(); if (xalg->parameter == NULL) goto err; } if(EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0) goto err; } /* Lets do the pub key stuff :-) */ max=0; for (i=0; icert == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_MISSING_CERIPEND_INFO); goto err; } if ((pkey=X509_get_pubkey(ri->cert)) == NULL) goto err; jj=EVP_PKEY_size(pkey); EVP_PKEY_free(pkey); if (max < jj) max=jj; } if ((tmp=(unsigned char *)OPENSSL_malloc(max)) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_MALLOC_FAILURE); goto err; } for (i=0; icert)) == NULL) goto err; jj=EVP_PKEY_encrypt(tmp,key,keylen,pkey); EVP_PKEY_free(pkey); if (jj <= 0) { PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_EVP_LIB); OPENSSL_free(tmp); goto err; } if (!M_ASN1_OCTET_STRING_set(ri->enc_key,tmp,jj)) { PKCS7err(PKCS7_F_PKCS7_DATAINIT, ERR_R_MALLOC_FAILURE); OPENSSL_free(tmp); goto err; } } OPENSSL_free(tmp); OPENSSL_cleanse(key, keylen); if (out == NULL) out=btmp; else BIO_push(out,btmp); btmp=NULL; } if (bio == NULL) { if (PKCS7_is_detached(p7)) bio=BIO_new(BIO_s_null()); else if (os && os->length > 0) bio = BIO_new_mem_buf(os->data, os->length); if(bio == NULL) { bio=BIO_new(BIO_s_mem()); if (bio == NULL) goto err; BIO_set_mem_eof_return(bio,0); } } BIO_push(out,bio); bio=NULL; if (0) { err: if (out != NULL) BIO_free_all(out); if (btmp != NULL) BIO_free_all(btmp); out=NULL; } return(out); } static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert) { int ret; ret = X509_NAME_cmp(ri->issuer_and_serial->issuer, pcert->cert_info->issuer); if (ret) return ret; return M_ASN1_INTEGER_cmp(pcert->cert_info->serialNumber, ri->issuer_and_serial->serial); } /* int */ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) { int i,j; BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL; unsigned char *tmp=NULL; X509_ALGOR *xa; ASN1_OCTET_STRING *data_body=NULL; const EVP_MD *evp_md; const EVP_CIPHER *evp_cipher=NULL; EVP_CIPHER_CTX *evp_ctx=NULL; X509_ALGOR *enc_alg=NULL; STACK_OF(X509_ALGOR) *md_sk=NULL; STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; PKCS7_RECIP_INFO *ri=NULL; + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER); + return NULL; + } + + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); + return NULL; + } + i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signed: data_body=PKCS7_get_octet_string(p7->d.sign->contents); md_sk=p7->d.sign->md_algs; break; case NID_pkcs7_signedAndEnveloped: rsk=p7->d.signed_and_enveloped->recipientinfo; md_sk=p7->d.signed_and_enveloped->md_algs; data_body=p7->d.signed_and_enveloped->enc_data->enc_data; enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm; evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } break; case NID_pkcs7_enveloped: rsk=p7->d.enveloped->recipientinfo; enc_alg=p7->d.enveloped->enc_data->algorithm; data_body=p7->d.enveloped->enc_data->enc_data; evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } break; default: PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } /* We will be checking the signature */ if (md_sk != NULL) { for (i=0; ialgorithm); evp_md=EVP_get_digestbynid(j); if (evp_md == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE); goto err; } BIO_set_md(btmp,evp_md); if (out == NULL) out=btmp; else BIO_push(out,btmp); btmp=NULL; } } if (evp_cipher != NULL) { #if 0 unsigned char key[EVP_MAX_KEY_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char *p; int keylen,ivlen; int max; X509_OBJECT ret; #endif unsigned char *tkey = NULL; int tkeylen; int jj; if ((etmp=BIO_new(BIO_f_cipher())) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); goto err; } /* It was encrypted, we need to decrypt the secret key * with the private key */ /* Find the recipientInfo which matches the passed certificate * (if any) */ if (pcert) { for (i=0; ienc_key), M_ASN1_STRING_length(ri->enc_key), pkey); if (tret > 0) { memcpy(tmp, tmp2, tret); OPENSSL_cleanse(tmp2, tret); jj = tret; } ERR_clear_error(); } OPENSSL_free(tmp2); } else { jj=EVP_PKEY_decrypt(tmp, M_ASN1_STRING_data(ri->enc_key), M_ASN1_STRING_length(ri->enc_key), pkey); ERR_clear_error(); } evp_ctx=NULL; BIO_get_cipher_ctx(etmp,&evp_ctx); if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0) goto err; if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0) goto err; /* Generate random key to counter MMA */ tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx); tkey = OPENSSL_malloc(tkeylen); if (!tkey) goto err; if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0) goto err; /* If we have no key use random key */ if (jj <= 0) { OPENSSL_free(tmp); jj = tkeylen; tmp = tkey; tkey = NULL; } if (jj != tkeylen) { /* Some S/MIME clients don't use the same key * and effective key length. The key length is * determined by the size of the decrypted RSA key. */ if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, jj)) { /* As MMA defence use random key instead */ OPENSSL_cleanse(tmp, jj); OPENSSL_free(tmp); jj = tkeylen; tmp = tkey; tkey = NULL; } } ERR_clear_error(); if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0) goto err; OPENSSL_cleanse(tmp,jj); if (tkey) { OPENSSL_cleanse(tkey, tkeylen); OPENSSL_free(tkey); } if (out == NULL) out=etmp; else BIO_push(out,etmp); etmp=NULL; } #if 1 if (PKCS7_is_detached(p7) || (in_bio != NULL)) { bio=in_bio; } else { #if 0 bio=BIO_new(BIO_s_mem()); /* We need to set this so that when we have read all * the data, the encrypt BIO, if present, will read * EOF and encode the last few bytes */ BIO_set_mem_eof_return(bio,0); if (data_body->length > 0) BIO_write(bio,(char *)data_body->data,data_body->length); #else if (data_body->length > 0) bio = BIO_new_mem_buf(data_body->data,data_body->length); else { bio=BIO_new(BIO_s_mem()); BIO_set_mem_eof_return(bio,0); } if (bio == NULL) goto err; #endif } BIO_push(out,bio); bio=NULL; #endif if (0) { err: if (out != NULL) BIO_free_all(out); if (btmp != NULL) BIO_free_all(btmp); if (etmp != NULL) BIO_free_all(etmp); if (bio != NULL) BIO_free_all(bio); out=NULL; } if (tmp != NULL) OPENSSL_free(tmp); return(out); } static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { for (;;) { bio=BIO_find_type(bio,BIO_TYPE_MD); if (bio == NULL) { PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); return NULL; } BIO_get_md_ctx(bio,pmd); if (*pmd == NULL) { PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,ERR_R_INTERNAL_ERROR); return NULL; } if (EVP_MD_CTX_type(*pmd) == nid) return bio; bio=BIO_next(bio); } return NULL; } int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { int ret=0; int i,j; BIO *btmp; BUF_MEM *buf_mem=NULL; BUF_MEM *buf=NULL; PKCS7_SIGNER_INFO *si; EVP_MD_CTX *mdc,ctx_tmp; STACK_OF(X509_ATTRIBUTE) *sk; STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL; ASN1_OCTET_STRING *os=NULL; + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_INVALID_NULL_POINTER); + return 0; + } + + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_NO_CONTENT); + return 0; + } + EVP_MD_CTX_init(&ctx_tmp); i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signedAndEnveloped: /* XXXXXXXXXXXXXXXX */ si_sk=p7->d.signed_and_enveloped->signer_info; if (!(os=M_ASN1_OCTET_STRING_new())) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE); goto err; } p7->d.signed_and_enveloped->enc_data->enc_data=os; break; case NID_pkcs7_enveloped: /* XXXXXXXXXXXXXXXX */ if (!(os=M_ASN1_OCTET_STRING_new())) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE); goto err; } p7->d.enveloped->enc_data->enc_data=os; break; case NID_pkcs7_signed: si_sk=p7->d.sign->signer_info; os=PKCS7_get_octet_string(p7->d.sign->contents); /* If detached data then the content is excluded */ if(PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) { M_ASN1_OCTET_STRING_free(os); + os = NULL; p7->d.sign->contents->d.data = NULL; } break; case NID_pkcs7_digest: os=PKCS7_get_octet_string(p7->d.digest->contents); /* If detached data then the content is excluded */ if(PKCS7_type_is_data(p7->d.digest->contents) && p7->detached) { M_ASN1_OCTET_STRING_free(os); + os = NULL; p7->d.digest->contents->d.data = NULL; } break; } if (si_sk != NULL) { if ((buf=BUF_MEM_new()) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_BIO_LIB); goto err; } for (i=0; ipkey == NULL) continue; j=OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; btmp = PKCS7_find_digest(&mdc, btmp, j); if (btmp == NULL) goto err; /* We now have the EVP_MD_CTX, lets do the * signing. */ EVP_MD_CTX_copy_ex(&ctx_tmp,mdc); if (!BUF_MEM_grow_clean(buf,EVP_PKEY_size(si->pkey))) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_BIO_LIB); goto err; } sk=si->auth_attr; /* If there are attributes, we add the digest * attribute and only sign the attributes */ if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { unsigned char md_data[EVP_MAX_MD_SIZE], *abuf=NULL; unsigned int md_len, alen; ASN1_OCTET_STRING *digest; ASN1_UTCTIME *sign_time; const EVP_MD *md_tmp; /* Add signing time if not already present */ if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime)) { if (!(sign_time=X509_gmtime_adj(NULL,0))) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE); goto err; } if (!PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, V_ASN1_UTCTIME,sign_time)) { M_ASN1_UTCTIME_free(sign_time); goto err; } } /* Add digest */ md_tmp=EVP_MD_CTX_md(&ctx_tmp); EVP_DigestFinal_ex(&ctx_tmp,md_data,&md_len); if (!(digest=M_ASN1_OCTET_STRING_new())) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE); goto err; } if (!M_ASN1_OCTET_STRING_set(digest,md_data, md_len)) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE); M_ASN1_OCTET_STRING_free(digest); goto err; } if (!PKCS7_add_signed_attribute(si, NID_pkcs9_messageDigest, V_ASN1_OCTET_STRING,digest)) { M_ASN1_OCTET_STRING_free(digest); goto err; } /* Now sign the attributes */ EVP_SignInit_ex(&ctx_tmp,md_tmp,NULL); alen = ASN1_item_i2d((ASN1_VALUE *)sk,&abuf, ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); if(!abuf) goto err; EVP_SignUpdate(&ctx_tmp,abuf,alen); OPENSSL_free(abuf); } #ifndef OPENSSL_NO_DSA if (si->pkey->type == EVP_PKEY_DSA) ctx_tmp.digest=EVP_dss1(); #endif #ifndef OPENSSL_NO_ECDSA if (si->pkey->type == EVP_PKEY_EC) ctx_tmp.digest=EVP_ecdsa(); #endif if (!EVP_SignFinal(&ctx_tmp,(unsigned char *)buf->data, (unsigned int *)&buf->length,si->pkey)) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_EVP_LIB); goto err; } if (!ASN1_STRING_set(si->enc_digest, (unsigned char *)buf->data,buf->length)) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_ASN1_LIB); goto err; } } } else if (i == NID_pkcs7_digest) { unsigned char md_data[EVP_MAX_MD_SIZE]; unsigned int md_len; if (!PKCS7_find_digest(&mdc, bio, OBJ_obj2nid(p7->d.digest->md->algorithm))) goto err; EVP_DigestFinal_ex(mdc,md_data,&md_len); M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len); } - if (!PKCS7_is_detached(p7)) - { + if (!PKCS7_is_detached(p7)) { + /* + * NOTE(emilia): I think we only reach os == NULL here because detached + * digested data support is broken. + */ + if (os == NULL) + goto err; btmp=BIO_find_type(bio,BIO_TYPE_MEM); if (btmp == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNABLE_TO_FIND_MEM_BIO); goto err; } BIO_get_mem_ptr(btmp,&buf_mem); /* Mark the BIO read only then we can use its copy of the data * instead of making an extra copy. */ BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY); BIO_set_mem_eof_return(btmp, 0); os->data = (unsigned char *)buf_mem->data; os->length = buf_mem->length; #if 0 M_ASN1_OCTET_STRING_set(os, (unsigned char *)buf_mem->data,buf_mem->length); #endif } ret=1; err: EVP_MD_CTX_cleanup(&ctx_tmp); if (buf != NULL) BUF_MEM_free(buf); return(ret); } int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si) { PKCS7_ISSUER_AND_SERIAL *ias; int ret=0,i; STACK_OF(X509) *cert; X509 *x509; + + if (p7 == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_INVALID_NULL_POINTER); + return 0; + } + + if (p7->d.ptr == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_NO_CONTENT); + return 0; + } if (PKCS7_type_is_signed(p7)) { cert=p7->d.sign->cert; } else if (PKCS7_type_is_signedAndEnveloped(p7)) { cert=p7->d.signed_and_enveloped->cert; } else { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_WRONG_PKCS7_TYPE); goto err; } /* XXXXXXXXXXXXXXXXXXXXXXX */ ias=si->issuer_and_serial; x509=X509_find_by_issuer_and_serial(cert,ias->issuer,ias->serial); /* were we able to find the cert in passed to us */ if (x509 == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_UNABLE_TO_FIND_CERTIFICATE); goto err; } /* Lets verify */ if(!X509_STORE_CTX_init(ctx,cert_store,x509,cert)) { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); goto err; } X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN); i=X509_verify_cert(ctx); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); X509_STORE_CTX_cleanup(ctx); goto err; } X509_STORE_CTX_cleanup(ctx); return PKCS7_signatureVerify(bio, p7, si, x509); err: return ret; } int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, X509 *x509) { ASN1_OCTET_STRING *os; EVP_MD_CTX mdc_tmp,*mdc; int ret=0,i; int md_type; STACK_OF(X509_ATTRIBUTE) *sk; BIO *btmp; EVP_PKEY *pkey; EVP_MD_CTX_init(&mdc_tmp); if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); goto err; } md_type=OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; for (;;) { if ((btmp == NULL) || ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } BIO_get_md_ctx(btmp,&mdc); if (mdc == NULL) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_INTERNAL_ERROR); goto err; } if (EVP_MD_CTX_type(mdc) == md_type) break; /* Workaround for some broken clients that put the signature * OID instead of the digest OID in digest_alg->algorithm */ if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type) break; btmp=BIO_next(btmp); } /* mdc is the digest ctx that we want, unless there are attributes, * in which case the digest is the signed attributes */ EVP_MD_CTX_copy_ex(&mdc_tmp,mdc); sk=si->auth_attr; if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL; unsigned int md_len, alen; ASN1_OCTET_STRING *message_digest; EVP_DigestFinal_ex(&mdc_tmp,md_dat,&md_len); message_digest=PKCS7_digest_from_attributes(sk); if (!message_digest) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } if ((message_digest->length != (int)md_len) || (memcmp(message_digest->data,md_dat,md_len))) { #if 0 { int ii; for (ii=0; iilength; ii++) printf("%02X",message_digest->data[ii]); printf(" sent\n"); for (ii=0; iienc_digest; pkey = X509_get_pubkey(x509); if (!pkey) { ret = -1; goto err; } #ifndef OPENSSL_NO_DSA if(pkey->type == EVP_PKEY_DSA) mdc_tmp.digest=EVP_dss1(); #endif #ifndef OPENSSL_NO_ECDSA if (pkey->type == EVP_PKEY_EC) mdc_tmp.digest=EVP_ecdsa(); #endif i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey); EVP_PKEY_free(pkey); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE); ret= -1; goto err; } else ret=1; err: EVP_MD_CTX_cleanup(&mdc_tmp); return(ret); } PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx) { STACK_OF(PKCS7_RECIP_INFO) *rsk; PKCS7_RECIP_INFO *ri; int i; i=OBJ_obj2nid(p7->type); if (i != NID_pkcs7_signedAndEnveloped) return NULL; if (p7->d.signed_and_enveloped == NULL) return NULL; rsk=p7->d.signed_and_enveloped->recipientinfo; if (rsk == NULL) return NULL; ri=sk_PKCS7_RECIP_INFO_value(rsk,0); if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) return(NULL); ri=sk_PKCS7_RECIP_INFO_value(rsk,idx); return(ri->issuer_and_serial); } ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid) { return(get_attribute(si->auth_attr,nid)); } ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid) { return(get_attribute(si->unauth_attr,nid)); } static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid) { int i; X509_ATTRIBUTE *xa; ASN1_OBJECT *o; o=OBJ_nid2obj(nid); if (!o || !sk) return(NULL); for (i=0; iobject,o) == 0) { if (!xa->single && sk_ASN1_TYPE_num(xa->value.set)) return(sk_ASN1_TYPE_value(xa->value.set,0)); else return(NULL); } } return(NULL); } ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk) { ASN1_TYPE *astype; if(!(astype = get_attribute(sk, NID_pkcs9_messageDigest))) return NULL; return astype->value.octet_string; } int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk) { int i; if (p7si->auth_attr != NULL) sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr,X509_ATTRIBUTE_free); p7si->auth_attr=sk_X509_ATTRIBUTE_dup(sk); if (p7si->auth_attr == NULL) return 0; for (i=0; iauth_attr,i, X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) == NULL) return(0); } return(1); } int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk) { int i; if (p7si->unauth_attr != NULL) sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr, X509_ATTRIBUTE_free); p7si->unauth_attr=sk_X509_ATTRIBUTE_dup(sk); if (p7si->unauth_attr == NULL) return 0; for (i=0; iunauth_attr,i, X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) == NULL) return(0); } return(1); } int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, void *value) { return(add_attribute(&(p7si->auth_attr),nid,atrtype,value)); } int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, void *value) { return(add_attribute(&(p7si->unauth_attr),nid,atrtype,value)); } static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, void *value) { X509_ATTRIBUTE *attr=NULL; if (*sk == NULL) { if (!(*sk = sk_X509_ATTRIBUTE_new_null())) return 0; new_attrib: if (!(attr=X509_ATTRIBUTE_create(nid,atrtype,value))) return 0; if (!sk_X509_ATTRIBUTE_push(*sk,attr)) { X509_ATTRIBUTE_free(attr); return 0; } } else { int i; for (i=0; iobject) == nid) { X509_ATTRIBUTE_free(attr); attr=X509_ATTRIBUTE_create(nid,atrtype,value); if (attr == NULL) return 0; if (!sk_X509_ATTRIBUTE_set(*sk,i,attr)) { X509_ATTRIBUTE_free(attr); return 0; } goto end; } } goto new_attrib; } end: return(1); } Index: releng/9.3/crypto/openssl/crypto/pkcs7/pk7_lib.c =================================================================== --- releng/9.3/crypto/openssl/crypto/pkcs7/pk7_lib.c (revision 280267) +++ releng/9.3/crypto/openssl/crypto/pkcs7/pk7_lib.c (revision 280268) @@ -1,587 +1,590 @@ /* crypto/pkcs7/pk7_lib.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include "cryptlib.h" #include #include long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg) { int nid; long ret; nid=OBJ_obj2nid(p7->type); switch (cmd) { + /* NOTE(emilia): does not support detached digested data. */ case PKCS7_OP_SET_DETACHED_SIGNATURE: if (nid == NID_pkcs7_signed) { ret=p7->detached=(int)larg; if (ret && PKCS7_type_is_data(p7->d.sign->contents)) { ASN1_OCTET_STRING *os; os=p7->d.sign->contents->d.data; ASN1_OCTET_STRING_free(os); p7->d.sign->contents->d.data = NULL; } } else { PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); ret=0; } break; case PKCS7_OP_GET_DETACHED_SIGNATURE: if (nid == NID_pkcs7_signed) { if(!p7->d.sign || !p7->d.sign->contents->d.ptr) ret = 1; else ret = 0; p7->detached = ret; } else { PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); ret=0; } break; default: PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_UNKNOWN_OPERATION); ret=0; } return(ret); } int PKCS7_content_new(PKCS7 *p7, int type) { PKCS7 *ret=NULL; if ((ret=PKCS7_new()) == NULL) goto err; if (!PKCS7_set_type(ret,type)) goto err; if (!PKCS7_set_content(p7,ret)) goto err; return(1); err: if (ret != NULL) PKCS7_free(ret); return(0); } int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data) { int i; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: if (p7->d.sign->contents != NULL) PKCS7_free(p7->d.sign->contents); p7->d.sign->contents=p7_data; break; case NID_pkcs7_digest: if (p7->d.digest->contents != NULL) PKCS7_free(p7->d.digest->contents); p7->d.digest->contents=p7_data; break; case NID_pkcs7_data: case NID_pkcs7_enveloped: case NID_pkcs7_signedAndEnveloped: case NID_pkcs7_encrypted: default: PKCS7err(PKCS7_F_PKCS7_SET_CONTENT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } return(1); err: return(0); } int PKCS7_set_type(PKCS7 *p7, int type) { ASN1_OBJECT *obj; /*PKCS7_content_free(p7);*/ obj=OBJ_nid2obj(type); /* will not fail */ switch (type) { case NID_pkcs7_signed: p7->type=obj; if ((p7->d.sign=PKCS7_SIGNED_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.sign->version,1)) { PKCS7_SIGNED_free(p7->d.sign); p7->d.sign=NULL; goto err; } break; case NID_pkcs7_data: p7->type=obj; if ((p7->d.data=M_ASN1_OCTET_STRING_new()) == NULL) goto err; break; case NID_pkcs7_signedAndEnveloped: p7->type=obj; if ((p7->d.signed_and_enveloped=PKCS7_SIGN_ENVELOPE_new()) == NULL) goto err; ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1); if (!ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1)) goto err; p7->d.signed_and_enveloped->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data); break; case NID_pkcs7_enveloped: p7->type=obj; if ((p7->d.enveloped=PKCS7_ENVELOPE_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.enveloped->version,0)) goto err; p7->d.enveloped->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data); break; case NID_pkcs7_encrypted: p7->type=obj; if ((p7->d.encrypted=PKCS7_ENCRYPT_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.encrypted->version,0)) goto err; p7->d.encrypted->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data); break; case NID_pkcs7_digest: p7->type=obj; if ((p7->d.digest=PKCS7_DIGEST_new()) == NULL) goto err; if (!ASN1_INTEGER_set(p7->d.digest->version,0)) goto err; break; default: PKCS7err(PKCS7_F_PKCS7_SET_TYPE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } return(1); err: return(0); } int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other) { p7->type = OBJ_nid2obj(type); p7->d.other = other; return 1; } int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *psi) { int i,j,nid; X509_ALGOR *alg; STACK_OF(PKCS7_SIGNER_INFO) *signer_sk; STACK_OF(X509_ALGOR) *md_sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: signer_sk= p7->d.sign->signer_info; md_sk= p7->d.sign->md_algs; break; case NID_pkcs7_signedAndEnveloped: signer_sk= p7->d.signed_and_enveloped->signer_info; md_sk= p7->d.signed_and_enveloped->md_algs; break; default: PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } nid=OBJ_obj2nid(psi->digest_alg->algorithm); /* If the digest is not currently listed, add it */ j=0; for (i=0; ialgorithm) == nid) { j=1; break; } } if (!j) /* we need to add another algorithm */ { if(!(alg=X509_ALGOR_new()) || !(alg->parameter = ASN1_TYPE_new())) { X509_ALGOR_free(alg); PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,ERR_R_MALLOC_FAILURE); return(0); } alg->algorithm=OBJ_nid2obj(nid); alg->parameter->type = V_ASN1_NULL; if (!sk_X509_ALGOR_push(md_sk,alg)) { X509_ALGOR_free(alg); return 0; } } if (!sk_PKCS7_SIGNER_INFO_push(signer_sk,psi)) return 0; return(1); } int PKCS7_add_certificate(PKCS7 *p7, X509 *x509) { int i; STACK_OF(X509) **sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: sk= &(p7->d.sign->cert); break; case NID_pkcs7_signedAndEnveloped: sk= &(p7->d.signed_and_enveloped->cert); break; default: PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } if (*sk == NULL) *sk=sk_X509_new_null(); if (*sk == NULL) { PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,ERR_R_MALLOC_FAILURE); return 0; } CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); if (!sk_X509_push(*sk,x509)) { X509_free(x509); return 0; } return(1); } int PKCS7_add_crl(PKCS7 *p7, X509_CRL *crl) { int i; STACK_OF(X509_CRL) **sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: sk= &(p7->d.sign->crl); break; case NID_pkcs7_signedAndEnveloped: sk= &(p7->d.signed_and_enveloped->crl); break; default: PKCS7err(PKCS7_F_PKCS7_ADD_CRL,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } if (*sk == NULL) *sk=sk_X509_CRL_new_null(); if (*sk == NULL) { PKCS7err(PKCS7_F_PKCS7_ADD_CRL,ERR_R_MALLOC_FAILURE); return 0; } CRYPTO_add(&crl->references,1,CRYPTO_LOCK_X509_CRL); if (!sk_X509_CRL_push(*sk,crl)) { X509_CRL_free(crl); return 0; } return(1); } int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, const EVP_MD *dgst) { int nid; char is_dsa; if (pkey->type == EVP_PKEY_DSA || pkey->type == EVP_PKEY_EC) is_dsa = 1; else is_dsa = 0; /* We now need to add another PKCS7_SIGNER_INFO entry */ if (!ASN1_INTEGER_set(p7i->version,1)) goto err; if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, X509_get_issuer_name(x509))) goto err; /* because ASN1_INTEGER_set is used to set a 'long' we will do * things the ugly way. */ M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); if (!(p7i->issuer_and_serial->serial= M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) goto err; /* lets keep the pkey around for a while */ CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY); p7i->pkey=pkey; /* Set the algorithms */ if (is_dsa) p7i->digest_alg->algorithm=OBJ_nid2obj(NID_sha1); else p7i->digest_alg->algorithm=OBJ_nid2obj(EVP_MD_type(dgst)); if (p7i->digest_alg->parameter != NULL) ASN1_TYPE_free(p7i->digest_alg->parameter); if ((p7i->digest_alg->parameter=ASN1_TYPE_new()) == NULL) goto err; p7i->digest_alg->parameter->type=V_ASN1_NULL; if (p7i->digest_enc_alg->parameter != NULL) ASN1_TYPE_free(p7i->digest_enc_alg->parameter); nid = EVP_PKEY_type(pkey->type); if (nid == EVP_PKEY_RSA) { p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_rsaEncryption); if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) goto err; p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; } else if (nid == EVP_PKEY_DSA) { #if 1 /* use 'dsaEncryption' OID for compatibility with other software * (PKCS #7 v1.5 does specify how to handle DSA) ... */ p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_dsa); #else /* ... although the 'dsaWithSHA1' OID (as required by RFC 2630 for CMS) * would make more sense. */ p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_dsaWithSHA1); #endif p7i->digest_enc_alg->parameter = NULL; /* special case for DSA: omit 'parameter'! */ } else if (nid == EVP_PKEY_EC) { p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_ecdsa_with_SHA1); if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) goto err; p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; } else return(0); return(1); err: return(0); } PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey, const EVP_MD *dgst) { PKCS7_SIGNER_INFO *si; if ((si=PKCS7_SIGNER_INFO_new()) == NULL) goto err; if (!PKCS7_SIGNER_INFO_set(si,x509,pkey,dgst)) goto err; if (!PKCS7_add_signer(p7,si)) goto err; return(si); err: PKCS7_SIGNER_INFO_free(si); return(NULL); } int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) { if (PKCS7_type_is_digest(p7)) { if(!(p7->d.digest->md->parameter = ASN1_TYPE_new())) { PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,ERR_R_MALLOC_FAILURE); return 0; } p7->d.digest->md->parameter->type = V_ASN1_NULL; p7->d.digest->md->algorithm = OBJ_nid2obj(EVP_MD_nid(md)); return 1; } PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,PKCS7_R_WRONG_CONTENT_TYPE); return 1; } STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7) { + if (p7 == NULL || p7->d.ptr == NULL) + return NULL; if (PKCS7_type_is_signed(p7)) { return(p7->d.sign->signer_info); } else if (PKCS7_type_is_signedAndEnveloped(p7)) { return(p7->d.signed_and_enveloped->signer_info); } else return(NULL); } PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509) { PKCS7_RECIP_INFO *ri; if ((ri=PKCS7_RECIP_INFO_new()) == NULL) goto err; if (!PKCS7_RECIP_INFO_set(ri,x509)) goto err; if (!PKCS7_add_recipient_info(p7,ri)) goto err; return(ri); err: PKCS7_RECIP_INFO_free(ri); return(NULL); } int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri) { int i; STACK_OF(PKCS7_RECIP_INFO) *sk; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signedAndEnveloped: sk= p7->d.signed_and_enveloped->recipientinfo; break; case NID_pkcs7_enveloped: sk= p7->d.enveloped->recipientinfo; break; default: PKCS7err(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } if (!sk_PKCS7_RECIP_INFO_push(sk,ri)) return 0; return(1); } int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509) { if (!ASN1_INTEGER_set(p7i->version,0)) return 0; if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, X509_get_issuer_name(x509))) return 0; M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); if (!(p7i->issuer_and_serial->serial= M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) return 0; X509_ALGOR_free(p7i->key_enc_algor); if (!(p7i->key_enc_algor= X509_ALGOR_dup(x509->cert_info->key->algor))) return 0; CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); p7i->cert=x509; return(1); } X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si) { if (PKCS7_type_is_signed(p7)) return(X509_find_by_issuer_and_serial(p7->d.sign->cert, si->issuer_and_serial->issuer, si->issuer_and_serial->serial)); else return(NULL); } int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher) { int i; PKCS7_ENC_CONTENT *ec; i=OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signedAndEnveloped: ec=p7->d.signed_and_enveloped->enc_data; break; case NID_pkcs7_enveloped: ec=p7->d.enveloped->enc_data; break; default: PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_WRONG_CONTENT_TYPE); return(0); } /* Check cipher OID exists and has data in it*/ i = EVP_CIPHER_type(cipher); if(i == NID_undef) { PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); return(0); } ec->cipher = cipher; return 1; } Index: releng/9.3/crypto/openssl/doc/crypto/d2i_X509.pod =================================================================== --- releng/9.3/crypto/openssl/doc/crypto/d2i_X509.pod (revision 280267) +++ releng/9.3/crypto/openssl/doc/crypto/d2i_X509.pod (revision 280268) @@ -1,231 +1,239 @@ =pod =head1 NAME d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio, i2d_X509_fp - X509 encode and decode functions =head1 SYNOPSIS #include X509 *d2i_X509(X509 **px, const unsigned char **in, int len); int i2d_X509(X509 *x, unsigned char **out); X509 *d2i_X509_bio(BIO *bp, X509 **x); X509 *d2i_X509_fp(FILE *fp, X509 **x); int i2d_X509_bio(BIO *bp, X509 *x); int i2d_X509_fp(FILE *fp, X509 *x); =head1 DESCRIPTION The X509 encode and decode routines encode and parse an B structure, which represents an X509 certificate. d2i_X509() attempts to decode B bytes at B<*in>. If successful a pointer to the B structure is returned. If an error occurred then B is returned. If B is not B then the returned structure is written to B<*px>. If B<*px> is not B then it is assumed that B<*px> contains a valid B structure and an attempt is made to reuse it. If the call is successful B<*in> is incremented to the byte following the parsed data. i2d_X509() encodes the structure pointed to by B into DER format. If B is not B is writes the DER encoded data to the buffer at B<*out>, and increments it to point after the data just written. If the return value is negative an error occurred, otherwise it returns the length of the encoded data. For OpenSSL 0.9.7 and later if B<*out> is B memory will be allocated for a buffer and the encoded data written to it. In this case B<*out> is not incremented and it points to the start of the data just written. d2i_X509_bio() is similar to d2i_X509() except it attempts to parse data from BIO B. d2i_X509_fp() is similar to d2i_X509() except it attempts to parse data from FILE pointer B. i2d_X509_bio() is similar to i2d_X509() except it writes the encoding of the structure B to BIO B and it returns 1 for success and 0 for failure. i2d_X509_fp() is similar to i2d_X509() except it writes the encoding of the structure B to BIO B and it returns 1 for success and 0 for failure. =head1 NOTES The letters B and B in for example B stand for "internal" (that is an internal C structure) and "DER". So that B converts from internal to DER. The functions can also understand B forms. The actual X509 structure passed to i2d_X509() must be a valid populated B structure it can B simply be fed with an empty structure such as that returned by X509_new(). The encoded data is in binary form and may contain embedded zeroes. Therefore any FILE pointers or BIOs should be opened in binary mode. Functions such as B will B return the correct length of the encoded structure. The ways that B<*in> and B<*out> are incremented after the operation can trap the unwary. See the B section for some common errors. The reason for the auto increment behaviour is to reflect a typical usage of ASN1 functions: after one structure is encoded or decoded another will processed after it. =head1 EXAMPLES Allocate and encode the DER encoding of an X509 structure: int len; unsigned char *buf, *p; len = i2d_X509(x, NULL); buf = OPENSSL_malloc(len); if (buf == NULL) /* error */ p = buf; i2d_X509(x, &p); If you are using OpenSSL 0.9.7 or later then this can be simplified to: int len; unsigned char *buf; buf = NULL; len = i2d_X509(x, &buf); if (len < 0) /* error */ Attempt to decode a buffer: X509 *x; unsigned char *buf, *p; int len; /* Something to setup buf and len */ p = buf; x = d2i_X509(NULL, &p, len); if (x == NULL) /* Some error */ Alternative technique: X509 *x; unsigned char *buf, *p; int len; /* Something to setup buf and len */ p = buf; x = NULL; if(!d2i_X509(&x, &p, len)) /* Some error */ =head1 WARNINGS The use of temporary variable is mandatory. A common mistake is to attempt to use a buffer directly as follows: int len; unsigned char *buf; len = i2d_X509(x, NULL); buf = OPENSSL_malloc(len); if (buf == NULL) /* error */ i2d_X509(x, &buf); /* Other stuff ... */ OPENSSL_free(buf); This code will result in B apparently containing garbage because it was incremented after the call to point after the data just written. Also B will no longer contain the pointer allocated by B and the subsequent call to B may well crash. The auto allocation feature (setting buf to NULL) only works on OpenSSL 0.9.7 and later. Attempts to use it on earlier versions will typically cause a segmentation violation. Another trap to avoid is misuse of the B argument to B: X509 *x; if (!d2i_X509(&x, &p, len)) /* Some error */ This will probably crash somewhere in B. The reason for this is that the variable B is uninitialized and an attempt will be made to interpret its (invalid) value as an B structure, typically causing a segmentation violation. If B is set to NULL first then this will not happen. =head1 BUGS In some versions of OpenSSL the "reuse" behaviour of d2i_X509() when B<*px> is valid is broken and some parts of the reused structure may persist if they are not present in the new one. As a result the use of this "reuse" behaviour is strongly discouraged. +Current versions of OpenSSL will not modify B<*px> if an error occurs. +If parsing succeeds then B<*px> is freed (if it is not NULL) and then +set to the value of the newly decoded structure. As a result B<*px> +B be allocated on the stack or an attempt will be made to +free an invalid pointer. + i2d_X509() will not return an error in many versions of OpenSSL, if mandatory fields are not initialized due to a programming error then the encoded structure may contain invalid data or omit the fields entirely and will not be parsed by d2i_X509(). This may be fixed in future so code should not assume that i2d_X509() will always succeed. =head1 RETURN VALUES d2i_X509(), d2i_X509_bio() and d2i_X509_fp() return a valid B structure or B if an error occurs. The error code that can be obtained by -L. +L. If the "reuse" capability has been used +with a valid X509 structure being passed in via B then the object is not +modified in the event of error. i2d_X509() returns the number of bytes successfully encoded or a negative value if an error occurs. The error code can be obtained by L. i2d_X509_bio() and i2d_X509_fp() return 1 for success and 0 if an error occurs The error code can be obtained by L. =head1 SEE ALSO L =head1 HISTORY d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio and i2d_X509_fp are available in all versions of SSLeay and OpenSSL. =cut Index: releng/9.3/crypto/openssl/ssl/s2_lib.c =================================================================== --- releng/9.3/crypto/openssl/ssl/s2_lib.c (revision 280267) +++ releng/9.3/crypto/openssl/ssl/s2_lib.c (revision 280268) @@ -1,480 +1,480 @@ /* ssl/s2_lib.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include "ssl_locl.h" #ifndef OPENSSL_NO_SSL2 #include #include #include #include const char ssl2_version_str[]="SSLv2" OPENSSL_VERSION_PTEXT; #define SSL2_NUM_CIPHERS (sizeof(ssl2_ciphers)/sizeof(SSL_CIPHER)) /* list of available SSLv2 ciphers (sorted by id) */ OPENSSL_GLOBAL SSL_CIPHER ssl2_ciphers[]={ /* NULL_WITH_MD5 v3 */ #if 0 { 1, SSL2_TXT_NULL_WITH_MD5, SSL2_CK_NULL_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_MD5|SSL_SSLV2, SSL_EXPORT|SSL_EXP40|SSL_STRONG_NONE, 0, 0, 0, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, #endif /* RC4_128_WITH_MD5 */ { 1, SSL2_TXT_RC4_128_WITH_MD5, SSL2_CK_RC4_128_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_MEDIUM, 0, 128, 128, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* RC4_128_EXPORT40_WITH_MD5 */ { 1, SSL2_TXT_RC4_128_EXPORT40_WITH_MD5, SSL2_CK_RC4_128_EXPORT40_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5|SSL_SSLV2, SSL_EXPORT|SSL_EXP40, SSL2_CF_5_BYTE_ENC, 40, 128, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* RC2_128_CBC_WITH_MD5 */ { 1, SSL2_TXT_RC2_128_CBC_WITH_MD5, SSL2_CK_RC2_128_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_MEDIUM, 0, 128, 128, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* RC2_128_CBC_EXPORT40_WITH_MD5 */ { 1, SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5, SSL2_CK_RC2_128_CBC_EXPORT40_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5|SSL_SSLV2, SSL_EXPORT|SSL_EXP40, SSL2_CF_5_BYTE_ENC, 40, 128, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* IDEA_128_CBC_WITH_MD5 */ #ifndef OPENSSL_NO_IDEA { 1, SSL2_TXT_IDEA_128_CBC_WITH_MD5, SSL2_CK_IDEA_128_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_IDEA|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_MEDIUM, 0, 128, 128, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, #endif /* DES_64_CBC_WITH_MD5 */ { 1, SSL2_TXT_DES_64_CBC_WITH_MD5, SSL2_CK_DES_64_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_DES|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_LOW, 0, 56, 56, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* DES_192_EDE3_CBC_WITH_MD5 */ { 1, SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5, SSL2_CK_DES_192_EDE3_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_HIGH, 0, 168, 168, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, /* RC4_64_WITH_MD5 */ #if 0 { 1, SSL2_TXT_RC4_64_WITH_MD5, SSL2_CK_RC4_64_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5|SSL_SSLV2, SSL_NOT_EXP|SSL_LOW, SSL2_CF_8_BYTE_ENC, 64, 64, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, #endif /* NULL SSLeay (testing) */ #if 0 { 0, SSL2_TXT_NULL, SSL2_CK_NULL, 0, SSL_STRONG_NONE, 0, 0, 0, SSL_ALL_CIPHERS, SSL_ALL_STRENGTHS, }, #endif /* end of list :-) */ }; long ssl2_default_timeout(void) { return(300); } IMPLEMENT_ssl2_meth_func(sslv2_base_method, ssl_undefined_function, ssl_undefined_function, ssl_bad_method) int ssl2_num_ciphers(void) { return(SSL2_NUM_CIPHERS); } SSL_CIPHER *ssl2_get_cipher(unsigned int u) { if (u < SSL2_NUM_CIPHERS) return(&(ssl2_ciphers[SSL2_NUM_CIPHERS-1-u])); else return(NULL); } int ssl2_pending(const SSL *s) { return SSL_in_init(s) ? 0 : s->s2->ract_data_length; } int ssl2_new(SSL *s) { SSL2_STATE *s2; if ((s2=OPENSSL_malloc(sizeof *s2)) == NULL) goto err; memset(s2,0,sizeof *s2); #if SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER + 3 > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2 # error "assertion failed" #endif if ((s2->rbuf=OPENSSL_malloc( SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2)) == NULL) goto err; /* wbuf needs one byte more because when using two-byte headers, * we leave the first byte unused in do_ssl_write (s2_pkt.c) */ if ((s2->wbuf=OPENSSL_malloc( SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+3)) == NULL) goto err; s->s2=s2; ssl2_clear(s); return(1); err: if (s2 != NULL) { if (s2->wbuf != NULL) OPENSSL_free(s2->wbuf); if (s2->rbuf != NULL) OPENSSL_free(s2->rbuf); OPENSSL_free(s2); } return(0); } void ssl2_free(SSL *s) { SSL2_STATE *s2; if(s == NULL) return; s2=s->s2; if (s2->rbuf != NULL) OPENSSL_free(s2->rbuf); if (s2->wbuf != NULL) OPENSSL_free(s2->wbuf); OPENSSL_cleanse(s2,sizeof *s2); OPENSSL_free(s2); s->s2=NULL; } void ssl2_clear(SSL *s) { SSL2_STATE *s2; unsigned char *rbuf,*wbuf; s2=s->s2; rbuf=s2->rbuf; wbuf=s2->wbuf; memset(s2,0,sizeof *s2); s2->rbuf=rbuf; s2->wbuf=wbuf; s2->clear_text=1; s->packet=s2->rbuf; s->version=SSL2_VERSION; s->packet_length=0; } long ssl2_ctrl(SSL *s, int cmd, long larg, void *parg) { int ret=0; switch(cmd) { case SSL_CTRL_GET_SESSION_REUSED: ret=s->hit; break; case SSL_CTRL_CHECK_PROTO_VERSION: return ssl3_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, larg, parg); default: break; } return(ret); } long ssl2_callback_ctrl(SSL *s, int cmd, void (*fp)(void)) { return(0); } long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { return(0); } long ssl2_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) { return(0); } /* This function needs to check if the ciphers required are actually * available */ SSL_CIPHER *ssl2_get_cipher_by_char(const unsigned char *p) { SSL_CIPHER c,*cp; unsigned long id; id=0x02000000L|((unsigned long)p[0]<<16L)| ((unsigned long)p[1]<<8L)|(unsigned long)p[2]; c.id=id; cp = (SSL_CIPHER *)OBJ_bsearch((char *)&c, (char *)ssl2_ciphers, SSL2_NUM_CIPHERS,sizeof(SSL_CIPHER), FP_ICC ssl_cipher_id_cmp); if ((cp == NULL) || (cp->valid == 0)) return NULL; else return cp; } int ssl2_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p) { long l; if (p != NULL) { l=c->id; if ((l & 0xff000000) != 0x02000000 && l != SSL3_CK_FALLBACK_SCSV) return(0); p[0]=((unsigned char)(l>>16L))&0xFF; p[1]=((unsigned char)(l>> 8L))&0xFF; p[2]=((unsigned char)(l ))&0xFF; } return(3); } int ssl2_generate_key_material(SSL *s) { unsigned int i; EVP_MD_CTX ctx; unsigned char *km; unsigned char c='0'; const EVP_MD *md5; md5 = EVP_md5(); #ifdef CHARSET_EBCDIC c = os_toascii['0']; /* Must be an ASCII '0', not EBCDIC '0', see SSLv2 docu */ #endif EVP_MD_CTX_init(&ctx); km=s->s2->key_material; if (s->session->master_key_length < 0 || s->session->master_key_length > (int)sizeof(s->session->master_key)) { SSLerr(SSL_F_SSL2_GENERATE_KEY_MATERIAL, ERR_R_INTERNAL_ERROR); return 0; } for (i=0; is2->key_material_length; i += EVP_MD_size(md5)) { if (((km - s->s2->key_material) + EVP_MD_size(md5)) > (int)sizeof(s->s2->key_material)) { /* EVP_DigestFinal_ex() below would write beyond buffer */ SSLerr(SSL_F_SSL2_GENERATE_KEY_MATERIAL, ERR_R_INTERNAL_ERROR); return 0; } EVP_DigestInit_ex(&ctx, md5, NULL); OPENSSL_assert(s->session->master_key_length >= 0 && s->session->master_key_length - < (int)sizeof(s->session->master_key)); + <= (int)sizeof(s->session->master_key)); EVP_DigestUpdate(&ctx,s->session->master_key,s->session->master_key_length); EVP_DigestUpdate(&ctx,&c,1); c++; EVP_DigestUpdate(&ctx,s->s2->challenge,s->s2->challenge_length); EVP_DigestUpdate(&ctx,s->s2->conn_id,s->s2->conn_id_length); EVP_DigestFinal_ex(&ctx,km,NULL); km += EVP_MD_size(md5); } EVP_MD_CTX_cleanup(&ctx); return 1; } void ssl2_return_error(SSL *s, int err) { if (!s->error) { s->error=3; s->error_code=err; ssl2_write_error(s); } } void ssl2_write_error(SSL *s) { unsigned char buf[3]; int i,error; buf[0]=SSL2_MT_ERROR; buf[1]=(s->error_code>>8)&0xff; buf[2]=(s->error_code)&0xff; /* state=s->rwstate;*/ error=s->error; /* number of bytes left to write */ s->error=0; OPENSSL_assert(error >= 0 && error <= (int)sizeof(buf)); i=ssl2_write(s,&(buf[3-error]),error); /* if (i == error) s->rwstate=state; */ if (i < 0) s->error=error; else { s->error=error-i; if (s->error == 0) if (s->msg_callback) s->msg_callback(1, s->version, 0, buf, 3, s, s->msg_callback_arg); /* ERROR */ } } int ssl2_shutdown(SSL *s) { s->shutdown=(SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); return(1); } #else /* !OPENSSL_NO_SSL2 */ # if PEDANTIC static void *dummy=&dummy; # endif #endif Index: releng/9.3/crypto/openssl/ssl/s2_srvr.c =================================================================== --- releng/9.3/crypto/openssl/ssl/s2_srvr.c (revision 280267) +++ releng/9.3/crypto/openssl/ssl/s2_srvr.c (revision 280268) @@ -1,1142 +1,1178 @@ /* ssl/s2_srvr.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* ==================================================================== * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ #include "ssl_locl.h" #ifndef OPENSSL_NO_SSL2 #include #include #include #include #include static SSL_METHOD *ssl2_get_server_method(int ver); static int get_client_master_key(SSL *s); static int get_client_hello(SSL *s); static int server_hello(SSL *s); static int get_client_finished(SSL *s); static int server_verify(SSL *s); static int server_finish(SSL *s); static int request_certificate(SSL *s); static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from, unsigned char *to,int padding); #define BREAK break static SSL_METHOD *ssl2_get_server_method(int ver) { if (ver == SSL2_VERSION) return(SSLv2_server_method()); else return(NULL); } IMPLEMENT_ssl2_meth_func(SSLv2_server_method, ssl2_accept, ssl_undefined_function, ssl2_get_server_method) int ssl2_accept(SSL *s) { unsigned long l=(unsigned long)time(NULL); BUF_MEM *buf=NULL; int ret= -1; long num1; void (*cb)(const SSL *ssl,int type,int val)=NULL; int new_state,state; RAND_add(&l,sizeof(l),0); ERR_clear_error(); clear_sys_error(); if (s->info_callback != NULL) cb=s->info_callback; else if (s->ctx->info_callback != NULL) cb=s->ctx->info_callback; /* init things to blank */ s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); if (s->cert == NULL) { SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_NO_CERTIFICATE_SET); return(-1); } clear_sys_error(); for (;;) { state=s->state; switch (s->state) { case SSL_ST_BEFORE: case SSL_ST_ACCEPT: case SSL_ST_BEFORE|SSL_ST_ACCEPT: case SSL_ST_OK|SSL_ST_ACCEPT: s->server=1; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1); s->version=SSL2_VERSION; s->type=SSL_ST_ACCEPT; buf=s->init_buf; if ((buf == NULL) && ((buf=BUF_MEM_new()) == NULL)) { ret= -1; goto end; } if (!BUF_MEM_grow(buf,(int) SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)) { ret= -1; goto end; } s->init_buf=buf; s->init_num=0; s->ctx->stats.sess_accept++; s->handshake_func=ssl2_accept; s->state=SSL2_ST_GET_CLIENT_HELLO_A; BREAK; case SSL2_ST_GET_CLIENT_HELLO_A: case SSL2_ST_GET_CLIENT_HELLO_B: case SSL2_ST_GET_CLIENT_HELLO_C: s->shutdown=0; ret=get_client_hello(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SEND_SERVER_HELLO_A; BREAK; case SSL2_ST_SEND_SERVER_HELLO_A: case SSL2_ST_SEND_SERVER_HELLO_B: ret=server_hello(s); if (ret <= 0) goto end; s->init_num=0; if (!s->hit) { s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_A; BREAK; } else { s->state=SSL2_ST_SERVER_START_ENCRYPTION; BREAK; } case SSL2_ST_GET_CLIENT_MASTER_KEY_A: case SSL2_ST_GET_CLIENT_MASTER_KEY_B: ret=get_client_master_key(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SERVER_START_ENCRYPTION; BREAK; case SSL2_ST_SERVER_START_ENCRYPTION: /* Ok we how have sent all the stuff needed to * start encrypting, the next packet back will * be encrypted. */ if (!ssl2_enc_init(s,0)) { ret= -1; goto end; } s->s2->clear_text=0; s->state=SSL2_ST_SEND_SERVER_VERIFY_A; BREAK; case SSL2_ST_SEND_SERVER_VERIFY_A: case SSL2_ST_SEND_SERVER_VERIFY_B: ret=server_verify(s); if (ret <= 0) goto end; s->init_num=0; if (s->hit) { /* If we are in here, we have been * buffering the output, so we need to * flush it and remove buffering from * future traffic */ s->state=SSL2_ST_SEND_SERVER_VERIFY_C; BREAK; } else { s->state=SSL2_ST_GET_CLIENT_FINISHED_A; break; } case SSL2_ST_SEND_SERVER_VERIFY_C: /* get the number of bytes to write */ num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL); if (num1 > 0) { s->rwstate=SSL_WRITING; num1=BIO_flush(s->wbio); if (num1 <= 0) { ret= -1; goto end; } s->rwstate=SSL_NOTHING; } /* flushed and now remove buffering */ s->wbio=BIO_pop(s->wbio); s->state=SSL2_ST_GET_CLIENT_FINISHED_A; BREAK; case SSL2_ST_GET_CLIENT_FINISHED_A: case SSL2_ST_GET_CLIENT_FINISHED_B: ret=get_client_finished(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_A; BREAK; case SSL2_ST_SEND_REQUEST_CERTIFICATE_A: case SSL2_ST_SEND_REQUEST_CERTIFICATE_B: case SSL2_ST_SEND_REQUEST_CERTIFICATE_C: case SSL2_ST_SEND_REQUEST_CERTIFICATE_D: /* don't do a 'request certificate' if we * don't want to, or we already have one, and * we only want to do it once. */ if (!(s->verify_mode & SSL_VERIFY_PEER) || ((s->session->peer != NULL) && (s->verify_mode & SSL_VERIFY_CLIENT_ONCE))) { s->state=SSL2_ST_SEND_SERVER_FINISHED_A; break; } else { ret=request_certificate(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL2_ST_SEND_SERVER_FINISHED_A; } BREAK; case SSL2_ST_SEND_SERVER_FINISHED_A: case SSL2_ST_SEND_SERVER_FINISHED_B: ret=server_finish(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL_ST_OK; break; case SSL_ST_OK: BUF_MEM_free(s->init_buf); ssl_free_wbio_buffer(s); s->init_buf=NULL; s->init_num=0; /* ERR_clear_error();*/ ssl_update_cache(s,SSL_SESS_CACHE_SERVER); s->ctx->stats.sess_accept_good++; /* s->server=1; */ ret=1; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1); goto end; /* BREAK; */ default: SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_UNKNOWN_STATE); ret= -1; goto end; /* BREAK; */ } if ((cb != NULL) && (s->state != state)) { new_state=s->state; s->state=state; cb(s,SSL_CB_ACCEPT_LOOP,1); s->state=new_state; } } end: s->in_handshake--; if (cb != NULL) cb(s,SSL_CB_ACCEPT_EXIT,ret); return(ret); } static int get_client_master_key(SSL *s) { int is_export,i,n,keya,ek; unsigned long len; unsigned char *p; SSL_CIPHER *cp; const EVP_CIPHER *c; const EVP_MD *md; p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_GET_CLIENT_MASTER_KEY_A) { i=ssl2_read(s,(char *)&(p[s->init_num]),10-s->init_num); if (i < (10-s->init_num)) return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i)); s->init_num = 10; if (*(p++) != SSL2_MT_CLIENT_MASTER_KEY) { if (p[-1] != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_READ_WRONG_PACKET_TYPE); } else SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_PEER_ERROR); return(-1); } cp=ssl2_get_cipher_by_char(p); if (cp == NULL) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_NO_CIPHER_MATCH); return(-1); } s->session->cipher= cp; p+=3; n2s(p,i); s->s2->tmp.clear=i; n2s(p,i); s->s2->tmp.enc=i; n2s(p,i); if(i > SSL_MAX_KEY_ARG_LENGTH) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_KEY_ARG_TOO_LONG); return -1; } s->session->key_arg_length=i; s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_B; } /* SSL2_ST_GET_CLIENT_MASTER_KEY_B */ p=(unsigned char *)s->init_buf->data; if (s->init_buf->length < SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); return -1; } keya=s->session->key_arg_length; len = 10 + (unsigned long)s->s2->tmp.clear + (unsigned long)s->s2->tmp.enc + (unsigned long)keya; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_MESSAGE_TOO_LONG); return -1; } n = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),n); if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i)); if (s->msg_callback) s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-MASTER-KEY */ p += 10; memcpy(s->session->key_arg,&(p[s->s2->tmp.clear+s->s2->tmp.enc]), (unsigned int)keya); if (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_NO_PRIVATEKEY); return(-1); } - i=ssl_rsa_private_decrypt(s->cert,s->s2->tmp.enc, - &(p[s->s2->tmp.clear]),&(p[s->s2->tmp.clear]), - (s->s2->ssl2_rollback)?RSA_SSLV23_PADDING:RSA_PKCS1_PADDING); is_export=SSL_C_IS_EXPORT(s->session->cipher); if (!ssl_cipher_get_evp(s->session,&c,&md,NULL)) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS); return(0); } if (s->session->cipher->algorithm2 & SSL2_CF_8_BYTE_ENC) { is_export=1; ek=8; } else ek=5; + /* + * The format of the CLIENT-MASTER-KEY message is + * 1 byte message type + * 3 bytes cipher + * 2-byte clear key length (stored in s->s2->tmp.clear) + * 2-byte encrypted key length (stored in s->s2->tmp.enc) + * 2-byte key args length (IV etc) + * clear key + * encrypted key + * key args + * + * If the cipher is an export cipher, then the encrypted key bytes + * are a fixed portion of the total key (5 or 8 bytes). The size of + * this portion is in |ek|. If the cipher is not an export cipher, + * then the entire key material is encrypted (i.e., clear key length + * must be zero). + */ + if ((!is_export && s->s2->tmp.clear != 0) || + (is_export && s->s2->tmp.clear + ek != EVP_CIPHER_key_length(c))) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_LENGTH); + return -1; + } + /* + * The encrypted blob must decrypt to the encrypted portion of the key. + * Decryption can't be expanding, so if we don't have enough encrypted + * bytes to fit the key in the buffer, stop now. + */ + if ((is_export && s->s2->tmp.enc < ek) || + (!is_export && s->s2->tmp.enc < EVP_CIPHER_key_length(c))) { + ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_LENGTH_TOO_SHORT); + return -1; + } + + i = ssl_rsa_private_decrypt(s->cert, s->s2->tmp.enc, + &(p[s->s2->tmp.clear]), + &(p[s->s2->tmp.clear]), + (s->s2->ssl2_rollback) ? RSA_SSLV23_PADDING : + RSA_PKCS1_PADDING); + /* bad decrypt */ #if 1 /* If a bad decrypt, continue with protocol but with a * random master secret (Bleichenbacher attack) */ - if ((i < 0) || - ((!is_export && (i != EVP_CIPHER_key_length(c))) - || (is_export && ((i != ek) || (s->s2->tmp.clear+(unsigned int)i != - (unsigned int)EVP_CIPHER_key_length(c)))))) - { + if ((i < 0) || ((!is_export && i != EVP_CIPHER_key_length(c)) + || (is_export && i != ek))) { ERR_clear_error(); if (is_export) i=ek; else i=EVP_CIPHER_key_length(c); - if (RAND_pseudo_bytes(p,i) <= 0) + if (RAND_pseudo_bytes(&p[s->s2->tmp.clear], i) <= 0) return 0; - } + } #else if (i < 0) { error=1; SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_RSA_DECRYPT); } /* incorrect number of key bytes for non export cipher */ else if ((!is_export && (i != EVP_CIPHER_key_length(c))) || (is_export && ((i != ek) || (s->s2->tmp.clear+i != EVP_CIPHER_key_length(c))))) { error=1; SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_WRONG_NUMBER_OF_KEY_BITS); } if (error) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } #endif - if (is_export) i+=s->s2->tmp.clear; + if (is_export) + i = EVP_CIPHER_key_length(c); if (i > SSL_MAX_MASTER_KEY_LENGTH) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); return -1; } s->session->master_key_length=i; memcpy(s->session->master_key,p,(unsigned int)i); return(1); } static int get_client_hello(SSL *s) { int i,n; unsigned long len; unsigned char *p; STACK_OF(SSL_CIPHER) *cs; /* a stack of SSL_CIPHERS */ STACK_OF(SSL_CIPHER) *cl; /* the ones we want to use */ STACK_OF(SSL_CIPHER) *prio, *allow; int z; /* This is a bit of a hack to check for the correct packet * type the first time round. */ if (s->state == SSL2_ST_GET_CLIENT_HELLO_A) { s->first_packet=1; s->state=SSL2_ST_GET_CLIENT_HELLO_B; } p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_GET_CLIENT_HELLO_B) { i=ssl2_read(s,(char *)&(p[s->init_num]),9-s->init_num); if (i < (9-s->init_num)) return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i)); s->init_num = 9; if (*(p++) != SSL2_MT_CLIENT_HELLO) { if (p[-1] != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_READ_WRONG_PACKET_TYPE); } else SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_PEER_ERROR); return(-1); } n2s(p,i); if (i < s->version) s->version=i; n2s(p,i); s->s2->tmp.cipher_spec_length=i; n2s(p,i); s->s2->tmp.session_id_length=i; n2s(p,i); s->s2->challenge_length=i; if ( (i < SSL2_MIN_CHALLENGE_LENGTH) || (i > SSL2_MAX_CHALLENGE_LENGTH)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_INVALID_CHALLENGE_LENGTH); return(-1); } s->state=SSL2_ST_GET_CLIENT_HELLO_C; } /* SSL2_ST_GET_CLIENT_HELLO_C */ p=(unsigned char *)s->init_buf->data; len = 9 + (unsigned long)s->s2->tmp.cipher_spec_length + (unsigned long)s->s2->challenge_length + (unsigned long)s->s2->tmp.session_id_length; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_MESSAGE_TOO_LONG); return -1; } n = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),n); if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i)); if (s->msg_callback) s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-HELLO */ p += 9; /* get session-id before cipher stuff so we can get out session * structure if it is cached */ /* session-id */ if ((s->s2->tmp.session_id_length != 0) && (s->s2->tmp.session_id_length != SSL2_SSL_SESSION_ID_LENGTH)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_BAD_SSL_SESSION_ID_LENGTH); return(-1); } if (s->s2->tmp.session_id_length == 0) { if (!ssl_get_new_session(s,1)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } } else { i=ssl_get_prev_session(s,&(p[s->s2->tmp.cipher_spec_length]), s->s2->tmp.session_id_length, NULL); if (i == 1) { /* previous session */ s->hit=1; } else if (i == -1) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } else { if (s->cert == NULL) { ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE); SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_NO_CERTIFICATE_SET); return(-1); } if (!ssl_get_new_session(s,1)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } } } if (!s->hit) { cs=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.cipher_spec_length, &s->session->ciphers); if (cs == NULL) goto mem_err; cl=SSL_get_ciphers(s); if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { prio=sk_SSL_CIPHER_dup(cl); if (prio == NULL) goto mem_err; allow = cs; } else { prio = cs; allow = cl; } for (z=0; zoptions & SSL_OP_CIPHER_SERVER_PREFERENCE) { sk_SSL_CIPHER_free(s->session->ciphers); s->session->ciphers = prio; } /* s->session->ciphers should now have a list of * ciphers that are on both the client and server. * This list is ordered by the order the client sent * the ciphers or in the order of the server's preference * if SSL_OP_CIPHER_SERVER_PREFERENCE was set. */ } p+=s->s2->tmp.cipher_spec_length; /* done cipher selection */ /* session id extracted already */ p+=s->s2->tmp.session_id_length; /* challenge */ if (s->s2->challenge_length > sizeof s->s2->challenge) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); return -1; } memcpy(s->s2->challenge,p,(unsigned int)s->s2->challenge_length); return(1); mem_err: SSLerr(SSL_F_GET_CLIENT_HELLO,ERR_R_MALLOC_FAILURE); return(0); } static int server_hello(SSL *s) { unsigned char *p,*d; int n,hit; p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_SEND_SERVER_HELLO_A) { d=p+11; *(p++)=SSL2_MT_SERVER_HELLO; /* type */ hit=s->hit; *(p++)=(unsigned char)hit; #if 1 if (!hit) { if (s->session->sess_cert != NULL) /* This can't really happen because get_client_hello * has called ssl_get_new_session, which does not set * sess_cert. */ ssl_sess_cert_free(s->session->sess_cert); s->session->sess_cert = ssl_sess_cert_new(); if (s->session->sess_cert == NULL) { SSLerr(SSL_F_SERVER_HELLO, ERR_R_MALLOC_FAILURE); return(-1); } } /* If 'hit' is set, then s->sess_cert may be non-NULL or NULL, * depending on whether it survived in the internal cache * or was retrieved from an external cache. * If it is NULL, we cannot put any useful data in it anyway, * so we don't touch it. */ #else /* That's what used to be done when cert_st and sess_cert_st were * the same. */ if (!hit) { /* else add cert to session */ CRYPTO_add(&s->cert->references,1,CRYPTO_LOCK_SSL_CERT); if (s->session->sess_cert != NULL) ssl_cert_free(s->session->sess_cert); s->session->sess_cert=s->cert; } else /* We have a session id-cache hit, if the * session-id has no certificate listed against * the 'cert' structure, grab the 'old' one * listed against the SSL connection */ { if (s->session->sess_cert == NULL) { CRYPTO_add(&s->cert->references,1, CRYPTO_LOCK_SSL_CERT); s->session->sess_cert=s->cert; } } #endif if (s->cert == NULL) { ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE); SSLerr(SSL_F_SERVER_HELLO,SSL_R_NO_CERTIFICATE_SPECIFIED); return(-1); } if (hit) { *(p++)=0; /* no certificate type */ s2n(s->version,p); /* version */ s2n(0,p); /* cert len */ s2n(0,p); /* ciphers len */ } else { /* EAY EAY */ /* put certificate type */ *(p++)=SSL2_CT_X509_CERTIFICATE; s2n(s->version,p); /* version */ n=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL); s2n(n,p); /* certificate length */ i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&d); n=0; /* lets send out the ciphers we like in the * prefered order */ n=ssl_cipher_list_to_bytes(s,s->session->ciphers,d,0); d+=n; s2n(n,p); /* add cipher length */ } /* make and send conn_id */ s2n(SSL2_CONNECTION_ID_LENGTH,p); /* add conn_id length */ s->s2->conn_id_length=SSL2_CONNECTION_ID_LENGTH; if (RAND_pseudo_bytes(s->s2->conn_id,(int)s->s2->conn_id_length) <= 0) return -1; memcpy(d,s->s2->conn_id,SSL2_CONNECTION_ID_LENGTH); d+=SSL2_CONNECTION_ID_LENGTH; s->state=SSL2_ST_SEND_SERVER_HELLO_B; s->init_num=d-(unsigned char *)s->init_buf->data; s->init_off=0; } /* SSL2_ST_SEND_SERVER_HELLO_B */ /* If we are using TCP/IP, the performance is bad if we do 2 * writes without a read between them. This occurs when * Session-id reuse is used, so I will put in a buffering module */ if (s->hit) { if (!ssl_init_wbio_buffer(s,1)) return(-1); } return(ssl2_do_write(s)); } static int get_client_finished(SSL *s) { unsigned char *p; int i, n; unsigned long len; p=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_GET_CLIENT_FINISHED_A) { i=ssl2_read(s,(char *)&(p[s->init_num]),1-s->init_num); if (i < 1-s->init_num) return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i)); s->init_num += i; if (*p != SSL2_MT_CLIENT_FINISHED) { if (*p != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_READ_WRONG_PACKET_TYPE); } else { SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_PEER_ERROR); /* try to read the error message */ i=ssl2_read(s,(char *)&(p[s->init_num]),3-s->init_num); return ssl2_part_read(s,SSL_F_GET_SERVER_VERIFY,i); } return(-1); } s->state=SSL2_ST_GET_CLIENT_FINISHED_B; } /* SSL2_ST_GET_CLIENT_FINISHED_B */ if (s->s2->conn_id_length > sizeof s->s2->conn_id) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_FINISHED, ERR_R_INTERNAL_ERROR); return -1; } len = 1 + (unsigned long)s->s2->conn_id_length; n = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),n); if (i < n) { return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i)); } if (s->msg_callback) s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-FINISHED */ p += 1; if (memcmp(p,s->s2->conn_id,s->s2->conn_id_length) != 0) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_CONNECTION_ID_IS_DIFFERENT); return(-1); } return(1); } static int server_verify(SSL *s) { unsigned char *p; if (s->state == SSL2_ST_SEND_SERVER_VERIFY_A) { p=(unsigned char *)s->init_buf->data; *(p++)=SSL2_MT_SERVER_VERIFY; if (s->s2->challenge_length > sizeof s->s2->challenge) { SSLerr(SSL_F_SERVER_VERIFY, ERR_R_INTERNAL_ERROR); return -1; } memcpy(p,s->s2->challenge,(unsigned int)s->s2->challenge_length); /* p+=s->s2->challenge_length; */ s->state=SSL2_ST_SEND_SERVER_VERIFY_B; s->init_num=s->s2->challenge_length+1; s->init_off=0; } return(ssl2_do_write(s)); } static int server_finish(SSL *s) { unsigned char *p; if (s->state == SSL2_ST_SEND_SERVER_FINISHED_A) { p=(unsigned char *)s->init_buf->data; *(p++)=SSL2_MT_SERVER_FINISHED; if (s->session->session_id_length > sizeof s->session->session_id) { SSLerr(SSL_F_SERVER_FINISH, ERR_R_INTERNAL_ERROR); return -1; } memcpy(p,s->session->session_id, (unsigned int)s->session->session_id_length); /* p+=s->session->session_id_length; */ s->state=SSL2_ST_SEND_SERVER_FINISHED_B; s->init_num=s->session->session_id_length+1; s->init_off=0; } /* SSL2_ST_SEND_SERVER_FINISHED_B */ return(ssl2_do_write(s)); } /* send the request and check the response */ static int request_certificate(SSL *s) { const unsigned char *cp; unsigned char *p,*p2,*buf2; unsigned char *ccd; int i,j,ctype,ret= -1; unsigned long len; X509 *x509=NULL; STACK_OF(X509) *sk=NULL; ccd=s->s2->tmp.ccl; if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_A) { p=(unsigned char *)s->init_buf->data; *(p++)=SSL2_MT_REQUEST_CERTIFICATE; *(p++)=SSL2_AT_MD5_WITH_RSA_ENCRYPTION; if (RAND_pseudo_bytes(ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH) <= 0) return -1; memcpy(p,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH); s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_B; s->init_num=SSL2_MIN_CERT_CHALLENGE_LENGTH+2; s->init_off=0; } if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_B) { i=ssl2_do_write(s); if (i <= 0) { ret=i; goto end; } s->init_num=0; s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_C; } if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_C) { p=(unsigned char *)s->init_buf->data; i=ssl2_read(s,(char *)&(p[s->init_num]),6-s->init_num); /* try to read 6 octets ... */ if (i < 3-s->init_num) /* ... but don't call ssl2_part_read now if we got at least 3 * (probably NO-CERTIFICATE-ERROR) */ { ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i); goto end; } s->init_num += i; if ((s->init_num >= 3) && (p[0] == SSL2_MT_ERROR)) { n2s(p,i); if (i != SSL2_PE_NO_CERTIFICATE) { /* not the error message we expected -- let ssl2_part_read handle it */ s->init_num -= 3; ret = ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE, 3); goto end; } if (s->msg_callback) s->msg_callback(0, s->version, 0, p, 3, s, s->msg_callback_arg); /* ERROR */ /* this is the one place where we can recover from an SSL 2.0 error */ if (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE); SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); goto end; } ret=1; goto end; } if ((*(p++) != SSL2_MT_CLIENT_CERTIFICATE) || (s->init_num < 6)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_SHORT_READ); goto end; } if (s->init_num != 6) { SSLerr(SSL_F_REQUEST_CERTIFICATE, ERR_R_INTERNAL_ERROR); goto end; } /* ok we have a response */ /* certificate type, there is only one right now. */ ctype= *(p++); if (ctype != SSL2_AT_MD5_WITH_RSA_ENCRYPTION) { ssl2_return_error(s,SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE); SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_RESPONSE_ARGUMENT); goto end; } n2s(p,i); s->s2->tmp.clen=i; n2s(p,i); s->s2->tmp.rlen=i; s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_D; } /* SSL2_ST_SEND_REQUEST_CERTIFICATE_D */ p=(unsigned char *)s->init_buf->data; len = 6 + (unsigned long)s->s2->tmp.clen + (unsigned long)s->s2->tmp.rlen; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_MESSAGE_TOO_LONG); goto end; } j = (int)len - s->init_num; i = ssl2_read(s,(char *)&(p[s->init_num]),j); if (i < j) { ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i); goto end; } if (s->msg_callback) s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-CERTIFICATE */ p += 6; cp = p; x509=(X509 *)d2i_X509(NULL,&cp,(long)s->s2->tmp.clen); if (x509 == NULL) { SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_X509_LIB); goto msg_end; } if (((sk=sk_X509_new_null()) == NULL) || (!sk_X509_push(sk,x509))) { SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE); goto msg_end; } i=ssl_verify_cert_chain(s,sk); if (i > 0) /* we like the packet, now check the chksum */ { EVP_MD_CTX ctx; EVP_PKEY *pkey=NULL; EVP_MD_CTX_init(&ctx); EVP_VerifyInit_ex(&ctx,s->ctx->rsa_md5, NULL); EVP_VerifyUpdate(&ctx,s->s2->key_material, s->s2->key_material_length); EVP_VerifyUpdate(&ctx,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH); i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL); buf2=OPENSSL_malloc((unsigned int)i); if (buf2 == NULL) { SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE); goto msg_end; } p2=buf2; i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&p2); EVP_VerifyUpdate(&ctx,buf2,(unsigned int)i); OPENSSL_free(buf2); pkey=X509_get_pubkey(x509); if (pkey == NULL) goto end; i=EVP_VerifyFinal(&ctx,cp,s->s2->tmp.rlen,pkey); EVP_PKEY_free(pkey); EVP_MD_CTX_cleanup(&ctx); if (i > 0) { if (s->session->peer != NULL) X509_free(s->session->peer); s->session->peer=x509; CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); s->session->verify_result = s->verify_result; ret=1; goto end; } else { SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_CHECKSUM); goto msg_end; } } else { msg_end: ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE); } end: sk_X509_free(sk); X509_free(x509); return(ret); } static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from, unsigned char *to, int padding) { RSA *rsa; int i; if ((c == NULL) || (c->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL)) { SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_NO_PRIVATEKEY); return(-1); } if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey->type != EVP_PKEY_RSA) { SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_PUBLIC_KEY_IS_NOT_RSA); return(-1); } rsa=c->pkeys[SSL_PKEY_RSA_ENC].privatekey->pkey.rsa; /* we have the public key */ i=RSA_private_decrypt(len,from,to,rsa,padding); if (i < 0) SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,ERR_R_RSA_LIB); return(i); } #else /* !OPENSSL_NO_SSL2 */ # if PEDANTIC static void *dummy=&dummy; # endif #endif Index: releng/9.3/secure/lib/libcrypto/man/d2i_X509.3 =================================================================== --- releng/9.3/secure/lib/libcrypto/man/d2i_X509.3 (revision 280267) +++ releng/9.3/secure/lib/libcrypto/man/d2i_X509.3 (revision 280268) @@ -1,369 +1,377 @@ .\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "d2i_X509 3" .TH d2i_X509 3 "2015-01-08" "0.9.8zd" "OpenSSL" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio, i2d_X509_fp \- X509 encode and decode functions .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& #include \& \& X509 *d2i_X509(X509 **px, const unsigned char **in, int len); \& int i2d_X509(X509 *x, unsigned char **out); \& \& X509 *d2i_X509_bio(BIO *bp, X509 **x); \& X509 *d2i_X509_fp(FILE *fp, X509 **x); \& \& int i2d_X509_bio(BIO *bp, X509 *x); \& int i2d_X509_fp(FILE *fp, X509 *x); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" The X509 encode and decode routines encode and parse an \&\fBX509\fR structure, which represents an X509 certificate. .PP \&\fId2i_X509()\fR attempts to decode \fBlen\fR bytes at \fB*in\fR. If successful a pointer to the \fBX509\fR structure is returned. If an error occurred then \fB\s-1NULL\s0\fR is returned. If \fBpx\fR is not \fB\s-1NULL\s0\fR then the returned structure is written to \fB*px\fR. If \fB*px\fR is not \fB\s-1NULL\s0\fR then it is assumed that \fB*px\fR contains a valid \fBX509\fR structure and an attempt is made to reuse it. If the call is successful \fB*in\fR is incremented to the byte following the parsed data. .PP \&\fIi2d_X509()\fR encodes the structure pointed to by \fBx\fR into \s-1DER\s0 format. If \fBout\fR is not \fB\s-1NULL\s0\fR is writes the \s-1DER\s0 encoded data to the buffer at \fB*out\fR, and increments it to point after the data just written. If the return value is negative an error occurred, otherwise it returns the length of the encoded data. .PP For OpenSSL 0.9.7 and later if \fB*out\fR is \fB\s-1NULL\s0\fR memory will be allocated for a buffer and the encoded data written to it. In this case \fB*out\fR is not incremented and it points to the start of the data just written. .PP \&\fId2i_X509_bio()\fR is similar to \fId2i_X509()\fR except it attempts to parse data from \s-1BIO \s0\fBbp\fR. .PP \&\fId2i_X509_fp()\fR is similar to \fId2i_X509()\fR except it attempts to parse data from \s-1FILE\s0 pointer \fBfp\fR. .PP \&\fIi2d_X509_bio()\fR is similar to \fIi2d_X509()\fR except it writes the encoding of the structure \fBx\fR to \s-1BIO \s0\fBbp\fR and it returns 1 for success and 0 for failure. .PP \&\fIi2d_X509_fp()\fR is similar to \fIi2d_X509()\fR except it writes the encoding of the structure \fBx\fR to \s-1BIO \s0\fBbp\fR and it returns 1 for success and 0 for failure. .SH "NOTES" .IX Header "NOTES" The letters \fBi\fR and \fBd\fR in for example \fBi2d_X509\fR stand for \&\*(L"internal\*(R" (that is an internal C structure) and \*(L"\s-1DER\*(R".\s0 So that \&\fBi2d_X509\fR converts from internal to \s-1DER.\s0 .PP The functions can also understand \fB\s-1BER\s0\fR forms. .PP The actual X509 structure passed to \fIi2d_X509()\fR must be a valid populated \fBX509\fR structure it can \fBnot\fR simply be fed with an empty structure such as that returned by \fIX509_new()\fR. .PP The encoded data is in binary form and may contain embedded zeroes. Therefore any \s-1FILE\s0 pointers or BIOs should be opened in binary mode. Functions such as \fB\f(BIstrlen()\fB\fR will \fBnot\fR return the correct length of the encoded structure. .PP The ways that \fB*in\fR and \fB*out\fR are incremented after the operation can trap the unwary. See the \fB\s-1WARNINGS\s0\fR section for some common errors. .PP The reason for the auto increment behaviour is to reflect a typical usage of \s-1ASN1\s0 functions: after one structure is encoded or decoded another will processed after it. .SH "EXAMPLES" .IX Header "EXAMPLES" Allocate and encode the \s-1DER\s0 encoding of an X509 structure: .PP .Vb 2 \& int len; \& unsigned char *buf, *p; \& \& len = i2d_X509(x, NULL); \& \& buf = OPENSSL_malloc(len); \& \& if (buf == NULL) \& /* error */ \& \& p = buf; \& \& i2d_X509(x, &p); .Ve .PP If you are using OpenSSL 0.9.7 or later then this can be simplified to: .PP .Vb 2 \& int len; \& unsigned char *buf; \& \& buf = NULL; \& \& len = i2d_X509(x, &buf); \& \& if (len < 0) \& /* error */ .Ve .PP Attempt to decode a buffer: .PP .Vb 1 \& X509 *x; \& \& unsigned char *buf, *p; \& \& int len; \& \& /* Something to setup buf and len */ \& \& p = buf; \& \& x = d2i_X509(NULL, &p, len); \& \& if (x == NULL) \& /* Some error */ .Ve .PP Alternative technique: .PP .Vb 1 \& X509 *x; \& \& unsigned char *buf, *p; \& \& int len; \& \& /* Something to setup buf and len */ \& \& p = buf; \& \& x = NULL; \& \& if(!d2i_X509(&x, &p, len)) \& /* Some error */ .Ve .SH "WARNINGS" .IX Header "WARNINGS" The use of temporary variable is mandatory. A common mistake is to attempt to use a buffer directly as follows: .PP .Vb 2 \& int len; \& unsigned char *buf; \& \& len = i2d_X509(x, NULL); \& \& buf = OPENSSL_malloc(len); \& \& if (buf == NULL) \& /* error */ \& \& i2d_X509(x, &buf); \& \& /* Other stuff ... */ \& \& OPENSSL_free(buf); .Ve .PP This code will result in \fBbuf\fR apparently containing garbage because it was incremented after the call to point after the data just written. Also \fBbuf\fR will no longer contain the pointer allocated by \fB\f(BIOPENSSL_malloc()\fB\fR and the subsequent call to \fB\f(BIOPENSSL_free()\fB\fR may well crash. .PP The auto allocation feature (setting buf to \s-1NULL\s0) only works on OpenSSL 0.9.7 and later. Attempts to use it on earlier versions will typically cause a segmentation violation. .PP Another trap to avoid is misuse of the \fBxp\fR argument to \fB\f(BId2i_X509()\fB\fR: .PP .Vb 1 \& X509 *x; \& \& if (!d2i_X509(&x, &p, len)) \& /* Some error */ .Ve .PP This will probably crash somewhere in \fB\f(BId2i_X509()\fB\fR. The reason for this is that the variable \fBx\fR is uninitialized and an attempt will be made to interpret its (invalid) value as an \fBX509\fR structure, typically causing a segmentation violation. If \fBx\fR is set to \s-1NULL\s0 first then this will not happen. .SH "BUGS" .IX Header "BUGS" In some versions of OpenSSL the \*(L"reuse\*(R" behaviour of \fId2i_X509()\fR when \&\fB*px\fR is valid is broken and some parts of the reused structure may persist if they are not present in the new one. As a result the use of this \*(L"reuse\*(R" behaviour is strongly discouraged. .PP +Current versions of OpenSSL will not modify \fB*px\fR if an error occurs. +If parsing succeeds then \fB*px\fR is freed (if it is not \s-1NULL\s0) and then +set to the value of the newly decoded structure. As a result \fB*px\fR +\&\fBmust not\fR be allocated on the stack or an attempt will be made to +free an invalid pointer. +.PP \&\fIi2d_X509()\fR will not return an error in many versions of OpenSSL, if mandatory fields are not initialized due to a programming error then the encoded structure may contain invalid data or omit the fields entirely and will not be parsed by \fId2i_X509()\fR. This may be fixed in future so code should not assume that \fIi2d_X509()\fR will always succeed. .SH "RETURN VALUES" .IX Header "RETURN VALUES" \&\fId2i_X509()\fR, \fId2i_X509_bio()\fR and \fId2i_X509_fp()\fR return a valid \fBX509\fR structure or \fB\s-1NULL\s0\fR if an error occurs. The error code that can be obtained by -\&\fIERR_get_error\fR\|(3). +\&\fIERR_get_error\fR\|(3). If the \*(L"reuse\*(R" capability has been used +with a valid X509 structure being passed in via \fBpx\fR then the object is not +modified in the event of error. .PP \&\fIi2d_X509()\fR returns the number of bytes successfully encoded or a negative value if an error occurs. The error code can be obtained by \&\fIERR_get_error\fR\|(3). .PP \&\fIi2d_X509_bio()\fR and \fIi2d_X509_fp()\fR return 1 for success and 0 if an error occurs The error code can be obtained by \fIERR_get_error\fR\|(3). .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIERR_get_error\fR\|(3) .SH "HISTORY" .IX Header "HISTORY" d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio and i2d_X509_fp are available in all versions of SSLeay and OpenSSL.