diff --git a/crypto/openssl/crypto/asn1/asn1_lib.c b/crypto/openssl/crypto/asn1/asn1_lib.c index 366afc5f6c6b..8e62f3307443 100644 --- a/crypto/openssl/crypto/asn1/asn1_lib.c +++ b/crypto/openssl/crypto/asn1/asn1_lib.c @@ -1,402 +1,412 @@ /* * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include #include #include "internal/cryptlib.h" #include #include "asn1_local.h" static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, long max); static void asn1_put_length(unsigned char **pp, int length); static int _asn1_check_infinite_end(const unsigned char **p, long len) { /* * If there is 0 or 1 byte left, the length check should pick things up */ if (len <= 0) return 1; else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) { (*p) += 2; return 1; } return 0; } int ASN1_check_infinite_end(unsigned char **p, long len) { return _asn1_check_infinite_end((const unsigned char **)p, len); } int ASN1_const_check_infinite_end(const unsigned char **p, long len) { return _asn1_check_infinite_end(p, len); } int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, int *pclass, long omax) { int i, ret; long l; const unsigned char *p = *pp; int tag, xclass, inf; long max = omax; if (!max) goto err; ret = (*p & V_ASN1_CONSTRUCTED); xclass = (*p & V_ASN1_PRIVATE); i = *p & V_ASN1_PRIMITIVE_TAG; if (i == V_ASN1_PRIMITIVE_TAG) { /* high-tag */ p++; if (--max == 0) goto err; l = 0; while (*p & 0x80) { l <<= 7L; l |= *(p++) & 0x7f; if (--max == 0) goto err; if (l > (INT_MAX >> 7L)) goto err; } l <<= 7L; l |= *(p++) & 0x7f; tag = (int)l; if (--max == 0) goto err; } else { tag = i; p++; if (--max == 0) goto err; } *ptag = tag; *pclass = xclass; if (!asn1_get_length(&p, &inf, plength, max)) goto err; if (inf && !(ret & V_ASN1_CONSTRUCTED)) goto err; if (*plength > (omax - (p - *pp))) { ASN1err(ASN1_F_ASN1_GET_OBJECT, ASN1_R_TOO_LONG); /* * Set this so that even if things are not long enough the values are * set correctly */ ret |= 0x80; } *pp = p; return ret | inf; err: ASN1err(ASN1_F_ASN1_GET_OBJECT, ASN1_R_HEADER_TOO_LONG); return 0x80; } /* * Decode a length field. * The short form is a single byte defining a length 0 - 127. * The long form is a byte 0 - 127 with the top bit set and this indicates * the number of following octets that contain the length. These octets * are stored most significant digit first. */ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, long max) { const unsigned char *p = *pp; unsigned long ret = 0; int i; if (max-- < 1) return 0; if (*p == 0x80) { *inf = 1; p++; } else { *inf = 0; i = *p & 0x7f; if (*p++ & 0x80) { if (max < i + 1) return 0; /* Skip leading zeroes */ while (i > 0 && *p == 0) { p++; i--; } if (i > (int)sizeof(long)) return 0; while (i > 0) { ret <<= 8; ret |= *p++; i--; } if (ret > LONG_MAX) return 0; } else ret = i; } *pp = p; *rl = (long)ret; return 1; } /* * class 0 is constructed constructed == 2 for indefinite length constructed */ void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag, int xclass) { unsigned char *p = *pp; int i, ttag; i = (constructed) ? V_ASN1_CONSTRUCTED : 0; i |= (xclass & V_ASN1_PRIVATE); if (tag < 31) *(p++) = i | (tag & V_ASN1_PRIMITIVE_TAG); else { *(p++) = i | V_ASN1_PRIMITIVE_TAG; for (i = 0, ttag = tag; ttag > 0; i++) ttag >>= 7; ttag = i; while (i-- > 0) { p[i] = tag & 0x7f; if (i != (ttag - 1)) p[i] |= 0x80; tag >>= 7; } p += ttag; } if (constructed == 2) *(p++) = 0x80; else asn1_put_length(&p, length); *pp = p; } int ASN1_put_eoc(unsigned char **pp) { unsigned char *p = *pp; *p++ = 0; *p++ = 0; *pp = p; return 2; } static void asn1_put_length(unsigned char **pp, int length) { unsigned char *p = *pp; int i, l; if (length <= 127) *(p++) = (unsigned char)length; else { l = length; for (i = 0; l > 0; i++) l >>= 8; *(p++) = i | 0x80; l = i; while (i-- > 0) { p[i] = length & 0xff; length >>= 8; } p += l; } *pp = p; } int ASN1_object_size(int constructed, int length, int tag) { int ret = 1; if (length < 0) return -1; if (tag >= 31) { while (tag > 0) { tag >>= 7; ret++; } } if (constructed == 2) { ret += 3; } else { ret++; if (length > 127) { int tmplen = length; while (tmplen > 0) { tmplen >>= 8; ret++; } } } if (ret >= INT_MAX - length) return -1; return ret + length; } int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str) { if (str == NULL) return 0; dst->type = str->type; if (!ASN1_STRING_set(dst, str->data, str->length)) return 0; /* Copy flags but preserve embed value */ dst->flags &= ASN1_STRING_FLAG_EMBED; dst->flags |= str->flags & ~ASN1_STRING_FLAG_EMBED; return 1; } ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *str) { ASN1_STRING *ret; if (!str) return NULL; ret = ASN1_STRING_new(); if (ret == NULL) return NULL; if (!ASN1_STRING_copy(ret, str)) { ASN1_STRING_free(ret); return NULL; } return ret; } int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len_in) { unsigned char *c; const char *data = _data; size_t len; if (len_in < 0) { if (data == NULL) return 0; len = strlen(data); } else { len = (size_t)len_in; } /* * Verify that the length fits within an integer for assignment to * str->length below. The additional 1 is subtracted to allow for the * '\0' terminator even though this isn't strictly necessary. */ if (len > INT_MAX - 1) { ASN1err(0, ASN1_R_TOO_LARGE); return 0; } if ((size_t)str->length <= len || str->data == NULL) { c = str->data; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* No NUL terminator in fuzzing builds */ + str->data = OPENSSL_realloc(c, len); +#else str->data = OPENSSL_realloc(c, len + 1); +#endif if (str->data == NULL) { ASN1err(ASN1_F_ASN1_STRING_SET, ERR_R_MALLOC_FAILURE); str->data = c; return 0; } } str->length = len; if (data != NULL) { memcpy(str->data, data, len); - /* an allowance for strings :-) */ +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* + * Add a NUL terminator. This should not be necessary - but we add it as + * a safety precaution + */ str->data[len] = '\0'; +#endif } return 1; } void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len) { OPENSSL_free(str->data); str->data = data; str->length = len; } ASN1_STRING *ASN1_STRING_new(void) { return ASN1_STRING_type_new(V_ASN1_OCTET_STRING); } ASN1_STRING *ASN1_STRING_type_new(int type) { ASN1_STRING *ret; ret = OPENSSL_zalloc(sizeof(*ret)); if (ret == NULL) { ASN1err(ASN1_F_ASN1_STRING_TYPE_NEW, ERR_R_MALLOC_FAILURE); return NULL; } ret->type = type; return ret; } void asn1_string_embed_free(ASN1_STRING *a, int embed) { if (a == NULL) return; if (!(a->flags & ASN1_STRING_FLAG_NDEF)) OPENSSL_free(a->data); if (embed == 0) OPENSSL_free(a); } void ASN1_STRING_free(ASN1_STRING *a) { if (a == NULL) return; asn1_string_embed_free(a, a->flags & ASN1_STRING_FLAG_EMBED); } void ASN1_STRING_clear_free(ASN1_STRING *a) { if (a == NULL) return; if (a->data && !(a->flags & ASN1_STRING_FLAG_NDEF)) OPENSSL_cleanse(a->data, a->length); ASN1_STRING_free(a); } int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b) { int i; i = (a->length - b->length); if (i == 0) { i = memcmp(a->data, b->data, a->length); if (i == 0) return a->type - b->type; else return i; } else return i; } int ASN1_STRING_length(const ASN1_STRING *x) { return x->length; } void ASN1_STRING_length_set(ASN1_STRING *x, int len) { x->length = len; } int ASN1_STRING_type(const ASN1_STRING *x) { return x->type; } const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x) { return x->data; } # if OPENSSL_API_COMPAT < 0x10100000L unsigned char *ASN1_STRING_data(ASN1_STRING *x) { return x->data; } #endif diff --git a/crypto/openssl/crypto/asn1/t_spki.c b/crypto/openssl/crypto/asn1/t_spki.c index 51b56d0aa9f7..64ee77eeecba 100644 --- a/crypto/openssl/crypto/asn1/t_spki.c +++ b/crypto/openssl/crypto/asn1/t_spki.c @@ -1,56 +1,56 @@ /* * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include #include "internal/cryptlib.h" #include #include #include #include #include /* Print out an SPKI */ int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki) { EVP_PKEY *pkey; ASN1_IA5STRING *chal; ASN1_OBJECT *spkioid; int i, n; char *s; BIO_printf(out, "Netscape SPKI:\n"); X509_PUBKEY_get0_param(&spkioid, NULL, NULL, NULL, spki->spkac->pubkey); i = OBJ_obj2nid(spkioid); BIO_printf(out, " Public Key Algorithm: %s\n", (i == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(i)); pkey = X509_PUBKEY_get(spki->spkac->pubkey); if (!pkey) BIO_printf(out, " Unable to load public key\n"); else { EVP_PKEY_print_public(out, pkey, 4, NULL); EVP_PKEY_free(pkey); } chal = spki->spkac->challenge; if (chal->length) - BIO_printf(out, " Challenge String: %s\n", chal->data); + BIO_printf(out, " Challenge String: %.*s\n", chal->length, chal->data); i = OBJ_obj2nid(spki->sig_algor.algorithm); BIO_printf(out, " Signature Algorithm: %s", (i == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(i)); n = spki->signature->length; s = (char *)spki->signature->data; for (i = 0; i < n; i++) { if ((i % 18) == 0) BIO_write(out, "\n ", 7); BIO_printf(out, "%02x%s", (unsigned char)s[i], ((i + 1) == n) ? "" : ":"); } BIO_write(out, "\n", 1); return 1; } diff --git a/crypto/openssl/crypto/ec/ec_asn1.c b/crypto/openssl/crypto/ec/ec_asn1.c index 7b7c75ce8443..e497a259095d 100644 --- a/crypto/openssl/crypto/ec/ec_asn1.c +++ b/crypto/openssl/crypto/ec/ec_asn1.c @@ -1,1325 +1,1328 @@ /* * Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include #include "ec_local.h" #include #include #include #include "internal/nelem.h" int EC_GROUP_get_basis_type(const EC_GROUP *group) { int i; if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != NID_X9_62_characteristic_two_field) /* everything else is currently not supported */ return 0; /* Find the last non-zero element of group->poly[] */ for (i = 0; i < (int)OSSL_NELEM(group->poly) && group->poly[i] != 0; i++) continue; if (i == 4) return NID_X9_62_ppBasis; else if (i == 2) return NID_X9_62_tpBasis; else /* everything else is currently not supported */ return 0; } #ifndef OPENSSL_NO_EC2M int EC_GROUP_get_trinomial_basis(const EC_GROUP *group, unsigned int *k) { if (group == NULL) return 0; if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != NID_X9_62_characteristic_two_field || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] == 0))) { ECerr(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } if (k) *k = group->poly[1]; return 1; } int EC_GROUP_get_pentanomial_basis(const EC_GROUP *group, unsigned int *k1, unsigned int *k2, unsigned int *k3) { if (group == NULL) return 0; if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != NID_X9_62_characteristic_two_field || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] != 0) && (group->poly[3] != 0) && (group->poly[4] == 0))) { ECerr(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } if (k1) *k1 = group->poly[3]; if (k2) *k2 = group->poly[2]; if (k3) *k3 = group->poly[1]; return 1; } #endif /* some structures needed for the asn1 encoding */ typedef struct x9_62_pentanomial_st { int32_t k1; int32_t k2; int32_t k3; } X9_62_PENTANOMIAL; typedef struct x9_62_characteristic_two_st { int32_t m; ASN1_OBJECT *type; union { char *ptr; /* NID_X9_62_onBasis */ ASN1_NULL *onBasis; /* NID_X9_62_tpBasis */ ASN1_INTEGER *tpBasis; /* NID_X9_62_ppBasis */ X9_62_PENTANOMIAL *ppBasis; /* anything else */ ASN1_TYPE *other; } p; } X9_62_CHARACTERISTIC_TWO; typedef struct x9_62_fieldid_st { ASN1_OBJECT *fieldType; union { char *ptr; /* NID_X9_62_prime_field */ ASN1_INTEGER *prime; /* NID_X9_62_characteristic_two_field */ X9_62_CHARACTERISTIC_TWO *char_two; /* anything else */ ASN1_TYPE *other; } p; } X9_62_FIELDID; typedef struct x9_62_curve_st { ASN1_OCTET_STRING *a; ASN1_OCTET_STRING *b; ASN1_BIT_STRING *seed; } X9_62_CURVE; struct ec_parameters_st { int32_t version; X9_62_FIELDID *fieldID; X9_62_CURVE *curve; ASN1_OCTET_STRING *base; ASN1_INTEGER *order; ASN1_INTEGER *cofactor; } /* ECPARAMETERS */ ; typedef enum { ECPKPARAMETERS_TYPE_NAMED = 0, ECPKPARAMETERS_TYPE_EXPLICIT, ECPKPARAMETERS_TYPE_IMPLICIT } ecpk_parameters_type_t; struct ecpk_parameters_st { int type; union { ASN1_OBJECT *named_curve; ECPARAMETERS *parameters; ASN1_NULL *implicitlyCA; } value; } /* ECPKPARAMETERS */ ; /* SEC1 ECPrivateKey */ typedef struct ec_privatekey_st { int32_t version; ASN1_OCTET_STRING *privateKey; ECPKPARAMETERS *parameters; ASN1_BIT_STRING *publicKey; } EC_PRIVATEKEY; /* the OpenSSL ASN.1 definitions */ ASN1_SEQUENCE(X9_62_PENTANOMIAL) = { ASN1_EMBED(X9_62_PENTANOMIAL, k1, INT32), ASN1_EMBED(X9_62_PENTANOMIAL, k2, INT32), ASN1_EMBED(X9_62_PENTANOMIAL, k3, INT32) } static_ASN1_SEQUENCE_END(X9_62_PENTANOMIAL) DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL) IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL) ASN1_ADB_TEMPLATE(char_two_def) = ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.other, ASN1_ANY); ASN1_ADB(X9_62_CHARACTERISTIC_TWO) = { ADB_ENTRY(NID_X9_62_onBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.onBasis, ASN1_NULL)), ADB_ENTRY(NID_X9_62_tpBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.tpBasis, ASN1_INTEGER)), ADB_ENTRY(NID_X9_62_ppBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.ppBasis, X9_62_PENTANOMIAL)) } ASN1_ADB_END(X9_62_CHARACTERISTIC_TWO, 0, type, 0, &char_two_def_tt, NULL); ASN1_SEQUENCE(X9_62_CHARACTERISTIC_TWO) = { ASN1_EMBED(X9_62_CHARACTERISTIC_TWO, m, INT32), ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, type, ASN1_OBJECT), ASN1_ADB_OBJECT(X9_62_CHARACTERISTIC_TWO) } static_ASN1_SEQUENCE_END(X9_62_CHARACTERISTIC_TWO) DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO) IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO) ASN1_ADB_TEMPLATE(fieldID_def) = ASN1_SIMPLE(X9_62_FIELDID, p.other, ASN1_ANY); ASN1_ADB(X9_62_FIELDID) = { ADB_ENTRY(NID_X9_62_prime_field, ASN1_SIMPLE(X9_62_FIELDID, p.prime, ASN1_INTEGER)), ADB_ENTRY(NID_X9_62_characteristic_two_field, ASN1_SIMPLE(X9_62_FIELDID, p.char_two, X9_62_CHARACTERISTIC_TWO)) } ASN1_ADB_END(X9_62_FIELDID, 0, fieldType, 0, &fieldID_def_tt, NULL); ASN1_SEQUENCE(X9_62_FIELDID) = { ASN1_SIMPLE(X9_62_FIELDID, fieldType, ASN1_OBJECT), ASN1_ADB_OBJECT(X9_62_FIELDID) } static_ASN1_SEQUENCE_END(X9_62_FIELDID) ASN1_SEQUENCE(X9_62_CURVE) = { ASN1_SIMPLE(X9_62_CURVE, a, ASN1_OCTET_STRING), ASN1_SIMPLE(X9_62_CURVE, b, ASN1_OCTET_STRING), ASN1_OPT(X9_62_CURVE, seed, ASN1_BIT_STRING) } static_ASN1_SEQUENCE_END(X9_62_CURVE) ASN1_SEQUENCE(ECPARAMETERS) = { ASN1_EMBED(ECPARAMETERS, version, INT32), ASN1_SIMPLE(ECPARAMETERS, fieldID, X9_62_FIELDID), ASN1_SIMPLE(ECPARAMETERS, curve, X9_62_CURVE), ASN1_SIMPLE(ECPARAMETERS, base, ASN1_OCTET_STRING), ASN1_SIMPLE(ECPARAMETERS, order, ASN1_INTEGER), ASN1_OPT(ECPARAMETERS, cofactor, ASN1_INTEGER) } ASN1_SEQUENCE_END(ECPARAMETERS) DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS) IMPLEMENT_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS) ASN1_CHOICE(ECPKPARAMETERS) = { ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT), ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS), ASN1_SIMPLE(ECPKPARAMETERS, value.implicitlyCA, ASN1_NULL) } ASN1_CHOICE_END(ECPKPARAMETERS) DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS) DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS) IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS) ASN1_SEQUENCE(EC_PRIVATEKEY) = { ASN1_EMBED(EC_PRIVATEKEY, version, INT32), ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING), ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0), ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1) } static_ASN1_SEQUENCE_END(EC_PRIVATEKEY) DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY) DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, EC_PRIVATEKEY) IMPLEMENT_ASN1_FUNCTIONS_const(EC_PRIVATEKEY) /* some declarations of internal function */ /* ec_asn1_group2field() sets the values in a X9_62_FIELDID object */ static int ec_asn1_group2fieldid(const EC_GROUP *, X9_62_FIELDID *); /* ec_asn1_group2curve() sets the values in a X9_62_CURVE object */ static int ec_asn1_group2curve(const EC_GROUP *, X9_62_CURVE *); /* the function definitions */ static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field) { int ok = 0, nid; BIGNUM *tmp = NULL; if (group == NULL || field == NULL) return 0; /* clear the old values (if necessary) */ ASN1_OBJECT_free(field->fieldType); ASN1_TYPE_free(field->p.other); nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group)); /* set OID for the field */ if ((field->fieldType = OBJ_nid2obj(nid)) == NULL) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB); goto err; } if (nid == NID_X9_62_prime_field) { if ((tmp = BN_new()) == NULL) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE); goto err; } /* the parameters are specified by the prime number p */ if (!EC_GROUP_get_curve(group, tmp, NULL, NULL, NULL)) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB); goto err; } /* set the prime number */ field->p.prime = BN_to_ASN1_INTEGER(tmp, NULL); if (field->p.prime == NULL) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB); goto err; } } else if (nid == NID_X9_62_characteristic_two_field) #ifdef OPENSSL_NO_EC2M { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_GF2M_NOT_SUPPORTED); goto err; } #else { int field_type; X9_62_CHARACTERISTIC_TWO *char_two; field->p.char_two = X9_62_CHARACTERISTIC_TWO_new(); char_two = field->p.char_two; if (char_two == NULL) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE); goto err; } char_two->m = (long)EC_GROUP_get_degree(group); field_type = EC_GROUP_get_basis_type(group); if (field_type == 0) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB); goto err; } /* set base type OID */ if ((char_two->type = OBJ_nid2obj(field_type)) == NULL) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB); goto err; } if (field_type == NID_X9_62_tpBasis) { unsigned int k; if (!EC_GROUP_get_trinomial_basis(group, &k)) goto err; char_two->p.tpBasis = ASN1_INTEGER_new(); if (char_two->p.tpBasis == NULL) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE); goto err; } if (!ASN1_INTEGER_set(char_two->p.tpBasis, (long)k)) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB); goto err; } } else if (field_type == NID_X9_62_ppBasis) { unsigned int k1, k2, k3; if (!EC_GROUP_get_pentanomial_basis(group, &k1, &k2, &k3)) goto err; char_two->p.ppBasis = X9_62_PENTANOMIAL_new(); if (char_two->p.ppBasis == NULL) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE); goto err; } /* set k? values */ char_two->p.ppBasis->k1 = (long)k1; char_two->p.ppBasis->k2 = (long)k2; char_two->p.ppBasis->k3 = (long)k3; } else { /* field_type == NID_X9_62_onBasis */ /* for ONB the parameters are (asn1) NULL */ char_two->p.onBasis = ASN1_NULL_new(); if (char_two->p.onBasis == NULL) { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE); goto err; } } } #endif else { ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_UNSUPPORTED_FIELD); goto err; } ok = 1; err: BN_free(tmp); return ok; } static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve) { int ok = 0; BIGNUM *tmp_1 = NULL, *tmp_2 = NULL; unsigned char *a_buf = NULL, *b_buf = NULL; size_t len; if (!group || !curve || !curve->a || !curve->b) return 0; if ((tmp_1 = BN_new()) == NULL || (tmp_2 = BN_new()) == NULL) { ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE); goto err; } /* get a and b */ if (!EC_GROUP_get_curve(group, NULL, tmp_1, tmp_2, NULL)) { ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB); goto err; } /* * Per SEC 1, the curve coefficients must be padded up to size. See C.2's * definition of Curve, C.1's definition of FieldElement, and 2.3.5's * definition of how to encode the field elements. */ len = ((size_t)EC_GROUP_get_degree(group) + 7) / 8; if ((a_buf = OPENSSL_malloc(len)) == NULL || (b_buf = OPENSSL_malloc(len)) == NULL) { ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE); goto err; } if (BN_bn2binpad(tmp_1, a_buf, len) < 0 || BN_bn2binpad(tmp_2, b_buf, len) < 0) { ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB); goto err; } /* set a and b */ if (!ASN1_OCTET_STRING_set(curve->a, a_buf, len) || !ASN1_OCTET_STRING_set(curve->b, b_buf, len)) { ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB); goto err; } /* set the seed (optional) */ if (group->seed) { if (!curve->seed) if ((curve->seed = ASN1_BIT_STRING_new()) == NULL) { ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE); goto err; } curve->seed->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); curve->seed->flags |= ASN1_STRING_FLAG_BITS_LEFT; if (!ASN1_BIT_STRING_set(curve->seed, group->seed, (int)group->seed_len)) { ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB); goto err; } } else { ASN1_BIT_STRING_free(curve->seed); curve->seed = NULL; } ok = 1; err: OPENSSL_free(a_buf); OPENSSL_free(b_buf); BN_free(tmp_1); BN_free(tmp_2); return ok; } ECPARAMETERS *EC_GROUP_get_ecparameters(const EC_GROUP *group, ECPARAMETERS *params) { size_t len = 0; ECPARAMETERS *ret = NULL; const BIGNUM *tmp; unsigned char *buffer = NULL; const EC_POINT *point = NULL; point_conversion_form_t form; ASN1_INTEGER *orig; if (params == NULL) { if ((ret = ECPARAMETERS_new()) == NULL) { ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_MALLOC_FAILURE); goto err; } } else ret = params; /* set the version (always one) */ ret->version = (long)0x1; /* set the fieldID */ if (!ec_asn1_group2fieldid(group, ret->fieldID)) { ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_EC_LIB); goto err; } /* set the curve */ if (!ec_asn1_group2curve(group, ret->curve)) { ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_EC_LIB); goto err; } /* set the base point */ if ((point = EC_GROUP_get0_generator(group)) == NULL) { ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, EC_R_UNDEFINED_GENERATOR); goto err; } form = EC_GROUP_get_point_conversion_form(group); len = EC_POINT_point2buf(group, point, form, &buffer, NULL); if (len == 0) { ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_EC_LIB); goto err; } if (ret->base == NULL && (ret->base = ASN1_OCTET_STRING_new()) == NULL) { OPENSSL_free(buffer); ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_MALLOC_FAILURE); goto err; } ASN1_STRING_set0(ret->base, buffer, len); /* set the order */ tmp = EC_GROUP_get0_order(group); if (tmp == NULL) { ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_EC_LIB); goto err; } ret->order = BN_to_ASN1_INTEGER(tmp, orig = ret->order); if (ret->order == NULL) { ret->order = orig; ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_ASN1_LIB); goto err; } /* set the cofactor (optional) */ tmp = EC_GROUP_get0_cofactor(group); if (tmp != NULL) { ret->cofactor = BN_to_ASN1_INTEGER(tmp, orig = ret->cofactor); if (ret->cofactor == NULL) { ret->cofactor = orig; ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_ASN1_LIB); goto err; } } return ret; err: if (params == NULL) ECPARAMETERS_free(ret); return NULL; } ECPKPARAMETERS *EC_GROUP_get_ecpkparameters(const EC_GROUP *group, ECPKPARAMETERS *params) { int ok = 1, tmp; ECPKPARAMETERS *ret = params; if (ret == NULL) { if ((ret = ECPKPARAMETERS_new()) == NULL) { ECerr(EC_F_EC_GROUP_GET_ECPKPARAMETERS, ERR_R_MALLOC_FAILURE); return NULL; } } else { if (ret->type == ECPKPARAMETERS_TYPE_NAMED) ASN1_OBJECT_free(ret->value.named_curve); else if (ret->type == ECPKPARAMETERS_TYPE_EXPLICIT && ret->value.parameters != NULL) ECPARAMETERS_free(ret->value.parameters); } if (EC_GROUP_get_asn1_flag(group)) { /* * use the asn1 OID to describe the elliptic curve parameters */ tmp = EC_GROUP_get_curve_name(group); if (tmp) { ASN1_OBJECT *asn1obj = OBJ_nid2obj(tmp); if (asn1obj == NULL || OBJ_length(asn1obj) == 0) { ASN1_OBJECT_free(asn1obj); ECerr(EC_F_EC_GROUP_GET_ECPKPARAMETERS, EC_R_MISSING_OID); ok = 0; } else { ret->type = ECPKPARAMETERS_TYPE_NAMED; ret->value.named_curve = asn1obj; } } else /* we don't know the nid => ERROR */ ok = 0; } else { /* use the ECPARAMETERS structure */ ret->type = ECPKPARAMETERS_TYPE_EXPLICIT; if ((ret->value.parameters = EC_GROUP_get_ecparameters(group, NULL)) == NULL) ok = 0; } if (!ok) { ECPKPARAMETERS_free(ret); return NULL; } return ret; } EC_GROUP *EC_GROUP_new_from_ecparameters(const ECPARAMETERS *params) { int ok = 0, tmp; EC_GROUP *ret = NULL, *dup = NULL; BIGNUM *p = NULL, *a = NULL, *b = NULL; EC_POINT *point = NULL; long field_bits; int curve_name = NID_undef; BN_CTX *ctx = NULL; if (!params->fieldID || !params->fieldID->fieldType || !params->fieldID->p.ptr) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR); goto err; } /* * Now extract the curve parameters a and b. Note that, although SEC 1 * specifies the length of their encodings, historical versions of OpenSSL * encoded them incorrectly, so we must accept any length for backwards * compatibility. */ if (!params->curve || !params->curve->a || !params->curve->a->data || !params->curve->b || !params->curve->b->data) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR); goto err; } a = BN_bin2bn(params->curve->a->data, params->curve->a->length, NULL); if (a == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_BN_LIB); goto err; } b = BN_bin2bn(params->curve->b->data, params->curve->b->length, NULL); if (b == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_BN_LIB); goto err; } /* get the field parameters */ tmp = OBJ_obj2nid(params->fieldID->fieldType); if (tmp == NID_X9_62_characteristic_two_field) #ifdef OPENSSL_NO_EC2M { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_GF2M_NOT_SUPPORTED); goto err; } #else { X9_62_CHARACTERISTIC_TWO *char_two; char_two = params->fieldID->p.char_two; field_bits = char_two->m; if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_FIELD_TOO_LARGE); goto err; } if ((p = BN_new()) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_MALLOC_FAILURE); goto err; } /* get the base type */ tmp = OBJ_obj2nid(char_two->type); if (tmp == NID_X9_62_tpBasis) { long tmp_long; if (!char_two->p.tpBasis) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR); goto err; } tmp_long = ASN1_INTEGER_get(char_two->p.tpBasis); if (!(char_two->m > tmp_long && tmp_long > 0)) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_INVALID_TRINOMIAL_BASIS); goto err; } /* create the polynomial */ if (!BN_set_bit(p, (int)char_two->m)) goto err; if (!BN_set_bit(p, (int)tmp_long)) goto err; if (!BN_set_bit(p, 0)) goto err; } else if (tmp == NID_X9_62_ppBasis) { X9_62_PENTANOMIAL *penta; penta = char_two->p.ppBasis; if (!penta) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR); goto err; } if (! (char_two->m > penta->k3 && penta->k3 > penta->k2 && penta->k2 > penta->k1 && penta->k1 > 0)) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_INVALID_PENTANOMIAL_BASIS); goto err; } /* create the polynomial */ if (!BN_set_bit(p, (int)char_two->m)) goto err; if (!BN_set_bit(p, (int)penta->k1)) goto err; if (!BN_set_bit(p, (int)penta->k2)) goto err; if (!BN_set_bit(p, (int)penta->k3)) goto err; if (!BN_set_bit(p, 0)) goto err; } else if (tmp == NID_X9_62_onBasis) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_NOT_IMPLEMENTED); goto err; } else { /* error */ ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR); goto err; } /* create the EC_GROUP structure */ ret = EC_GROUP_new_curve_GF2m(p, a, b, NULL); } #endif else if (tmp == NID_X9_62_prime_field) { /* we have a curve over a prime field */ /* extract the prime number */ if (!params->fieldID->p.prime) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR); goto err; } p = ASN1_INTEGER_to_BN(params->fieldID->p.prime, NULL); if (p == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_ASN1_LIB); goto err; } if (BN_is_negative(p) || BN_is_zero(p)) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_INVALID_FIELD); goto err; } field_bits = BN_num_bits(p); if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_FIELD_TOO_LARGE); goto err; } /* create the EC_GROUP structure */ ret = EC_GROUP_new_curve_GFp(p, a, b, NULL); } else { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_INVALID_FIELD); goto err; } if (ret == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_EC_LIB); goto err; } /* extract seed (optional) */ if (params->curve->seed != NULL) { OPENSSL_free(ret->seed); if ((ret->seed = OPENSSL_malloc(params->curve->seed->length)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_MALLOC_FAILURE); goto err; } memcpy(ret->seed, params->curve->seed->data, params->curve->seed->length); ret->seed_len = params->curve->seed->length; } - if (!params->order || !params->base || !params->base->data) { + if (params->order == NULL + || params->base == NULL + || params->base->data == NULL + || params->base->length == 0) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR); goto err; } if ((point = EC_POINT_new(ret)) == NULL) goto err; /* set the point conversion form */ EC_GROUP_set_point_conversion_form(ret, (point_conversion_form_t) (params->base->data[0] & ~0x01)); /* extract the ec point */ if (!EC_POINT_oct2point(ret, point, params->base->data, params->base->length, NULL)) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_EC_LIB); goto err; } /* extract the order */ if ((a = ASN1_INTEGER_to_BN(params->order, a)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_ASN1_LIB); goto err; } if (BN_is_negative(a) || BN_is_zero(a)) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_INVALID_GROUP_ORDER); goto err; } if (BN_num_bits(a) > (int)field_bits + 1) { /* Hasse bound */ ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_INVALID_GROUP_ORDER); goto err; } /* extract the cofactor (optional) */ if (params->cofactor == NULL) { BN_free(b); b = NULL; } else if ((b = ASN1_INTEGER_to_BN(params->cofactor, b)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_ASN1_LIB); goto err; } /* set the generator, order and cofactor (if present) */ if (!EC_GROUP_set_generator(ret, point, a, b)) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_EC_LIB); goto err; } /* * Check if the explicit parameters group just created matches one of the * built-in curves. * * We create a copy of the group just built, so that we can remove optional * fields for the lookup: we do this to avoid the possibility that one of * the optional parameters is used to force the library into using a less * performant and less secure EC_METHOD instead of the specialized one. * In any case, `seed` is not really used in any computation, while a * cofactor different from the one in the built-in table is just * mathematically wrong anyway and should not be used. */ if ((ctx = BN_CTX_new()) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_BN_LIB); goto err; } if ((dup = EC_GROUP_dup(ret)) == NULL || EC_GROUP_set_seed(dup, NULL, 0) != 1 || !EC_GROUP_set_generator(dup, point, a, NULL)) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_EC_LIB); goto err; } if ((curve_name = ec_curve_nid_from_params(dup, ctx)) != NID_undef) { /* * The input explicit parameters successfully matched one of the * built-in curves: often for built-in curves we have specialized * methods with better performance and hardening. * * In this case we replace the `EC_GROUP` created through explicit * parameters with one created from a named group. */ EC_GROUP *named_group = NULL; #ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 /* * NID_wap_wsg_idm_ecid_wtls12 and NID_secp224r1 are both aliases for * the same curve, we prefer the SECP nid when matching explicit * parameters as that is associated with a specialized EC_METHOD. */ if (curve_name == NID_wap_wsg_idm_ecid_wtls12) curve_name = NID_secp224r1; #endif /* !def(OPENSSL_NO_EC_NISTP_64_GCC_128) */ if ((named_group = EC_GROUP_new_by_curve_name(curve_name)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_EC_LIB); goto err; } EC_GROUP_free(ret); ret = named_group; /* * Set the flag so that EC_GROUPs created from explicit parameters are * serialized using explicit parameters by default. */ EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_EXPLICIT_CURVE); /* * If the input params do not contain the optional seed field we make * sure it is not added to the returned group. * * The seed field is not really used inside libcrypto anyway, and * adding it to parsed explicit parameter keys would alter their DER * encoding output (because of the extra field) which could impact * applications fingerprinting keys by their DER encoding. */ if (params->curve->seed == NULL) { if (EC_GROUP_set_seed(ret, NULL, 0) != 1) goto err; } } ok = 1; err: if (!ok) { EC_GROUP_free(ret); ret = NULL; } EC_GROUP_free(dup); BN_free(p); BN_free(a); BN_free(b); EC_POINT_free(point); BN_CTX_free(ctx); return ret; } EC_GROUP *EC_GROUP_new_from_ecpkparameters(const ECPKPARAMETERS *params) { EC_GROUP *ret = NULL; int tmp = 0; if (params == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, EC_R_MISSING_PARAMETERS); return NULL; } if (params->type == ECPKPARAMETERS_TYPE_NAMED) { /* the curve is given by an OID */ tmp = OBJ_obj2nid(params->value.named_curve); if ((ret = EC_GROUP_new_by_curve_name(tmp)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, EC_R_EC_GROUP_NEW_BY_NAME_FAILURE); return NULL; } EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_NAMED_CURVE); } else if (params->type == ECPKPARAMETERS_TYPE_EXPLICIT) { /* the parameters are given by an ECPARAMETERS structure */ ret = EC_GROUP_new_from_ecparameters(params->value.parameters); if (!ret) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, ERR_R_EC_LIB); return NULL; } EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_EXPLICIT_CURVE); } else if (params->type == ECPKPARAMETERS_TYPE_IMPLICIT) { /* implicit parameters inherited from CA - unsupported */ return NULL; } else { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, EC_R_ASN1_ERROR); return NULL; } return ret; } /* EC_GROUP <-> DER encoding of ECPKPARAMETERS */ EC_GROUP *d2i_ECPKParameters(EC_GROUP **a, const unsigned char **in, long len) { EC_GROUP *group = NULL; ECPKPARAMETERS *params = NULL; const unsigned char *p = *in; if ((params = d2i_ECPKPARAMETERS(NULL, &p, len)) == NULL) { ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_D2I_ECPKPARAMETERS_FAILURE); ECPKPARAMETERS_free(params); return NULL; } if ((group = EC_GROUP_new_from_ecpkparameters(params)) == NULL) { ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_PKPARAMETERS2GROUP_FAILURE); ECPKPARAMETERS_free(params); return NULL; } if (params->type == ECPKPARAMETERS_TYPE_EXPLICIT) group->decoded_from_explicit_params = 1; if (a) { EC_GROUP_free(*a); *a = group; } ECPKPARAMETERS_free(params); *in = p; return group; } int i2d_ECPKParameters(const EC_GROUP *a, unsigned char **out) { int ret = 0; ECPKPARAMETERS *tmp = EC_GROUP_get_ecpkparameters(a, NULL); if (tmp == NULL) { ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_GROUP2PKPARAMETERS_FAILURE); return 0; } if ((ret = i2d_ECPKPARAMETERS(tmp, out)) == 0) { ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_I2D_ECPKPARAMETERS_FAILURE); ECPKPARAMETERS_free(tmp); return 0; } ECPKPARAMETERS_free(tmp); return ret; } /* some EC_KEY functions */ EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len) { EC_KEY *ret = NULL; EC_PRIVATEKEY *priv_key = NULL; const unsigned char *p = *in; if ((priv_key = d2i_EC_PRIVATEKEY(NULL, &p, len)) == NULL) { ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB); return NULL; } if (a == NULL || *a == NULL) { if ((ret = EC_KEY_new()) == NULL) { ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE); goto err; } } else ret = *a; if (priv_key->parameters) { EC_GROUP_free(ret->group); ret->group = EC_GROUP_new_from_ecpkparameters(priv_key->parameters); if (ret->group != NULL && priv_key->parameters->type == ECPKPARAMETERS_TYPE_EXPLICIT) ret->group->decoded_from_explicit_params = 1; } if (ret->group == NULL) { ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB); goto err; } ret->version = priv_key->version; if (priv_key->privateKey) { ASN1_OCTET_STRING *pkey = priv_key->privateKey; if (EC_KEY_oct2priv(ret, ASN1_STRING_get0_data(pkey), ASN1_STRING_length(pkey)) == 0) goto err; } else { ECerr(EC_F_D2I_ECPRIVATEKEY, EC_R_MISSING_PRIVATE_KEY); goto err; } EC_POINT_clear_free(ret->pub_key); ret->pub_key = EC_POINT_new(ret->group); if (ret->pub_key == NULL) { ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB); goto err; } if (priv_key->publicKey) { const unsigned char *pub_oct; int pub_oct_len; pub_oct = ASN1_STRING_get0_data(priv_key->publicKey); pub_oct_len = ASN1_STRING_length(priv_key->publicKey); if (!EC_KEY_oct2key(ret, pub_oct, pub_oct_len, NULL)) { ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB); goto err; } } else { if (ret->group->meth->keygenpub == NULL || ret->group->meth->keygenpub(ret) == 0) goto err; /* Remember the original private-key-only encoding. */ ret->enc_flag |= EC_PKEY_NO_PUBKEY; } if (a) *a = ret; EC_PRIVATEKEY_free(priv_key); *in = p; return ret; err: if (a == NULL || *a != ret) EC_KEY_free(ret); EC_PRIVATEKEY_free(priv_key); return NULL; } int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out) { int ret = 0, ok = 0; unsigned char *priv= NULL, *pub= NULL; size_t privlen = 0, publen = 0; EC_PRIVATEKEY *priv_key = NULL; if (a == NULL || a->group == NULL || (!(a->enc_flag & EC_PKEY_NO_PUBKEY) && a->pub_key == NULL)) { ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER); goto err; } if ((priv_key = EC_PRIVATEKEY_new()) == NULL) { ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE); goto err; } priv_key->version = a->version; privlen = EC_KEY_priv2buf(a, &priv); if (privlen == 0) { ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB); goto err; } ASN1_STRING_set0(priv_key->privateKey, priv, privlen); priv = NULL; if (!(a->enc_flag & EC_PKEY_NO_PARAMETERS)) { if ((priv_key->parameters = EC_GROUP_get_ecpkparameters(a->group, priv_key->parameters)) == NULL) { ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB); goto err; } } if (!(a->enc_flag & EC_PKEY_NO_PUBKEY)) { priv_key->publicKey = ASN1_BIT_STRING_new(); if (priv_key->publicKey == NULL) { ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE); goto err; } publen = EC_KEY_key2buf(a, a->conv_form, &pub, NULL); if (publen == 0) { ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB); goto err; } priv_key->publicKey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); priv_key->publicKey->flags |= ASN1_STRING_FLAG_BITS_LEFT; ASN1_STRING_set0(priv_key->publicKey, pub, publen); pub = NULL; } if ((ret = i2d_EC_PRIVATEKEY(priv_key, out)) == 0) { ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB); goto err; } ok = 1; err: OPENSSL_clear_free(priv, privlen); OPENSSL_free(pub); EC_PRIVATEKEY_free(priv_key); return (ok ? ret : 0); } int i2d_ECParameters(EC_KEY *a, unsigned char **out) { if (a == NULL) { ECerr(EC_F_I2D_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER); return 0; } return i2d_ECPKParameters(a->group, out); } EC_KEY *d2i_ECParameters(EC_KEY **a, const unsigned char **in, long len) { EC_KEY *ret; if (in == NULL || *in == NULL) { ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER); return NULL; } if (a == NULL || *a == NULL) { if ((ret = EC_KEY_new()) == NULL) { ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_MALLOC_FAILURE); return NULL; } } else ret = *a; if (!d2i_ECPKParameters(&ret->group, in, len)) { ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_EC_LIB); if (a == NULL || *a != ret) EC_KEY_free(ret); return NULL; } if (a) *a = ret; return ret; } EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len) { EC_KEY *ret = NULL; if (a == NULL || (*a) == NULL || (*a)->group == NULL) { /* * sorry, but a EC_GROUP-structure is necessary to set the public key */ ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER); return 0; } ret = *a; if (!EC_KEY_oct2key(ret, *in, len, NULL)) { ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_EC_LIB); return 0; } *in += len; return ret; } int i2o_ECPublicKey(const EC_KEY *a, unsigned char **out) { size_t buf_len = 0; int new_buffer = 0; if (a == NULL) { ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER); return 0; } buf_len = EC_POINT_point2oct(a->group, a->pub_key, a->conv_form, NULL, 0, NULL); if (out == NULL || buf_len == 0) /* out == NULL => just return the length of the octet string */ return buf_len; if (*out == NULL) { if ((*out = OPENSSL_malloc(buf_len)) == NULL) { ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_MALLOC_FAILURE); return 0; } new_buffer = 1; } if (!EC_POINT_point2oct(a->group, a->pub_key, a->conv_form, *out, buf_len, NULL)) { ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_EC_LIB); if (new_buffer) { OPENSSL_free(*out); *out = NULL; } return 0; } if (!new_buffer) *out += buf_len; return buf_len; } ASN1_SEQUENCE(ECDSA_SIG) = { ASN1_SIMPLE(ECDSA_SIG, r, CBIGNUM), ASN1_SIMPLE(ECDSA_SIG, s, CBIGNUM) } static_ASN1_SEQUENCE_END(ECDSA_SIG) DECLARE_ASN1_FUNCTIONS_const(ECDSA_SIG) DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECDSA_SIG, ECDSA_SIG) IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ECDSA_SIG, ECDSA_SIG, ECDSA_SIG) ECDSA_SIG *ECDSA_SIG_new(void) { ECDSA_SIG *sig = OPENSSL_zalloc(sizeof(*sig)); if (sig == NULL) ECerr(EC_F_ECDSA_SIG_NEW, ERR_R_MALLOC_FAILURE); return sig; } void ECDSA_SIG_free(ECDSA_SIG *sig) { if (sig == NULL) return; BN_clear_free(sig->r); BN_clear_free(sig->s); OPENSSL_free(sig); } void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) { if (pr != NULL) *pr = sig->r; if (ps != NULL) *ps = sig->s; } const BIGNUM *ECDSA_SIG_get0_r(const ECDSA_SIG *sig) { return sig->r; } const BIGNUM *ECDSA_SIG_get0_s(const ECDSA_SIG *sig) { return sig->s; } int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) { if (r == NULL || s == NULL) return 0; BN_clear_free(sig->r); BN_clear_free(sig->s); sig->r = r; sig->s = s; return 1; } int ECDSA_size(const EC_KEY *r) { int ret, i; ASN1_INTEGER bs; unsigned char buf[4]; const EC_GROUP *group; if (r == NULL) return 0; group = EC_KEY_get0_group(r); if (group == NULL) return 0; i = EC_GROUP_order_bits(group); if (i == 0) return 0; bs.length = (i + 7) / 8; bs.data = buf; bs.type = V_ASN1_INTEGER; /* If the top bit is set the asn1 encoding is 1 larger. */ buf[0] = 0xff; i = i2d_ASN1_INTEGER(&bs, NULL); i += i; /* r and s */ ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE); if (ret < 0) return 0; return ret; } diff --git a/crypto/openssl/crypto/sm2/sm2_crypt.c b/crypto/openssl/crypto/sm2/sm2_crypt.c index ef505f64412b..00055a4e510e 100644 --- a/crypto/openssl/crypto/sm2/sm2_crypt.c +++ b/crypto/openssl/crypto/sm2/sm2_crypt.c @@ -1,393 +1,388 @@ /* * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2017 Ribose Inc. All Rights Reserved. * Ported from Ribose contributions from Botan. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include "crypto/sm2.h" #include "crypto/sm2err.h" #include "crypto/ec.h" /* ecdh_KDF_X9_63() */ #include #include #include #include #include #include typedef struct SM2_Ciphertext_st SM2_Ciphertext; DECLARE_ASN1_FUNCTIONS(SM2_Ciphertext) struct SM2_Ciphertext_st { BIGNUM *C1x; BIGNUM *C1y; ASN1_OCTET_STRING *C3; ASN1_OCTET_STRING *C2; }; ASN1_SEQUENCE(SM2_Ciphertext) = { ASN1_SIMPLE(SM2_Ciphertext, C1x, BIGNUM), ASN1_SIMPLE(SM2_Ciphertext, C1y, BIGNUM), ASN1_SIMPLE(SM2_Ciphertext, C3, ASN1_OCTET_STRING), ASN1_SIMPLE(SM2_Ciphertext, C2, ASN1_OCTET_STRING), } ASN1_SEQUENCE_END(SM2_Ciphertext) IMPLEMENT_ASN1_FUNCTIONS(SM2_Ciphertext) static size_t ec_field_size(const EC_GROUP *group) { /* Is there some simpler way to do this? */ BIGNUM *p = BN_new(); BIGNUM *a = BN_new(); BIGNUM *b = BN_new(); size_t field_size = 0; if (p == NULL || a == NULL || b == NULL) goto done; if (!EC_GROUP_get_curve(group, p, a, b, NULL)) goto done; field_size = (BN_num_bits(p) + 7) / 8; done: BN_free(p); BN_free(a); BN_free(b); return field_size; } -int sm2_plaintext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len, - size_t *pt_size) +int sm2_plaintext_size(const unsigned char *ct, size_t ct_size, size_t *pt_size) { - const size_t field_size = ec_field_size(EC_KEY_get0_group(key)); - const int md_size = EVP_MD_size(digest); - size_t overhead; + struct SM2_Ciphertext_st *sm2_ctext = NULL; - if (md_size < 0) { - SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_DIGEST); - return 0; - } - if (field_size == 0) { - SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_FIELD); - return 0; - } + sm2_ctext = d2i_SM2_Ciphertext(NULL, &ct, ct_size); - overhead = 10 + 2 * field_size + (size_t)md_size; - if (msg_len <= overhead) { + if (sm2_ctext == NULL) { SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_ENCODING); return 0; } - *pt_size = msg_len - overhead; + *pt_size = sm2_ctext->C2->length; + SM2_Ciphertext_free(sm2_ctext); + return 1; } int sm2_ciphertext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len, size_t *ct_size) { const size_t field_size = ec_field_size(EC_KEY_get0_group(key)); const int md_size = EVP_MD_size(digest); size_t sz; if (field_size == 0 || md_size < 0) return 0; /* Integer and string are simple type; set constructed = 0, means primitive and definite length encoding. */ sz = 2 * ASN1_object_size(0, field_size + 1, V_ASN1_INTEGER) + ASN1_object_size(0, md_size, V_ASN1_OCTET_STRING) + ASN1_object_size(0, msg_len, V_ASN1_OCTET_STRING); /* Sequence is structured type; set constructed = 1, means constructed and definite length encoding. */ *ct_size = ASN1_object_size(1, sz, V_ASN1_SEQUENCE); return 1; } int sm2_encrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *msg, size_t msg_len, uint8_t *ciphertext_buf, size_t *ciphertext_len) { int rc = 0, ciphertext_leni; size_t i; BN_CTX *ctx = NULL; BIGNUM *k = NULL; BIGNUM *x1 = NULL; BIGNUM *y1 = NULL; BIGNUM *x2 = NULL; BIGNUM *y2 = NULL; EVP_MD_CTX *hash = EVP_MD_CTX_new(); struct SM2_Ciphertext_st ctext_struct; const EC_GROUP *group = EC_KEY_get0_group(key); const BIGNUM *order = EC_GROUP_get0_order(group); const EC_POINT *P = EC_KEY_get0_public_key(key); EC_POINT *kG = NULL; EC_POINT *kP = NULL; uint8_t *msg_mask = NULL; uint8_t *x2y2 = NULL; uint8_t *C3 = NULL; size_t field_size; const int C3_size = EVP_MD_size(digest); /* NULL these before any "goto done" */ ctext_struct.C2 = NULL; ctext_struct.C3 = NULL; if (hash == NULL || C3_size <= 0) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_INTERNAL_ERROR); goto done; } field_size = ec_field_size(group); if (field_size == 0) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_INTERNAL_ERROR); goto done; } kG = EC_POINT_new(group); kP = EC_POINT_new(group); ctx = BN_CTX_new(); if (kG == NULL || kP == NULL || ctx == NULL) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_MALLOC_FAILURE); goto done; } BN_CTX_start(ctx); k = BN_CTX_get(ctx); x1 = BN_CTX_get(ctx); x2 = BN_CTX_get(ctx); y1 = BN_CTX_get(ctx); y2 = BN_CTX_get(ctx); if (y2 == NULL) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_BN_LIB); goto done; } x2y2 = OPENSSL_zalloc(2 * field_size); C3 = OPENSSL_zalloc(C3_size); if (x2y2 == NULL || C3 == NULL) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_MALLOC_FAILURE); goto done; } memset(ciphertext_buf, 0, *ciphertext_len); if (!BN_priv_rand_range(k, order)) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_INTERNAL_ERROR); goto done; } if (!EC_POINT_mul(group, kG, k, NULL, NULL, ctx) || !EC_POINT_get_affine_coordinates(group, kG, x1, y1, ctx) || !EC_POINT_mul(group, kP, NULL, P, k, ctx) || !EC_POINT_get_affine_coordinates(group, kP, x2, y2, ctx)) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_EC_LIB); goto done; } if (BN_bn2binpad(x2, x2y2, field_size) < 0 || BN_bn2binpad(y2, x2y2 + field_size, field_size) < 0) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_INTERNAL_ERROR); goto done; } msg_mask = OPENSSL_zalloc(msg_len); if (msg_mask == NULL) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_MALLOC_FAILURE); goto done; } /* X9.63 with no salt happens to match the KDF used in SM2 */ if (!ecdh_KDF_X9_63(msg_mask, msg_len, x2y2, 2 * field_size, NULL, 0, digest)) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_EVP_LIB); goto done; } for (i = 0; i != msg_len; ++i) msg_mask[i] ^= msg[i]; if (EVP_DigestInit(hash, digest) == 0 || EVP_DigestUpdate(hash, x2y2, field_size) == 0 || EVP_DigestUpdate(hash, msg, msg_len) == 0 || EVP_DigestUpdate(hash, x2y2 + field_size, field_size) == 0 || EVP_DigestFinal(hash, C3, NULL) == 0) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_EVP_LIB); goto done; } ctext_struct.C1x = x1; ctext_struct.C1y = y1; ctext_struct.C3 = ASN1_OCTET_STRING_new(); ctext_struct.C2 = ASN1_OCTET_STRING_new(); if (ctext_struct.C3 == NULL || ctext_struct.C2 == NULL) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_MALLOC_FAILURE); goto done; } if (!ASN1_OCTET_STRING_set(ctext_struct.C3, C3, C3_size) || !ASN1_OCTET_STRING_set(ctext_struct.C2, msg_mask, msg_len)) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_INTERNAL_ERROR); goto done; } ciphertext_leni = i2d_SM2_Ciphertext(&ctext_struct, &ciphertext_buf); /* Ensure cast to size_t is safe */ if (ciphertext_leni < 0) { SM2err(SM2_F_SM2_ENCRYPT, ERR_R_INTERNAL_ERROR); goto done; } *ciphertext_len = (size_t)ciphertext_leni; rc = 1; done: ASN1_OCTET_STRING_free(ctext_struct.C2); ASN1_OCTET_STRING_free(ctext_struct.C3); OPENSSL_free(msg_mask); OPENSSL_free(x2y2); OPENSSL_free(C3); EVP_MD_CTX_free(hash); BN_CTX_free(ctx); EC_POINT_free(kG); EC_POINT_free(kP); return rc; } int sm2_decrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *ptext_buf, size_t *ptext_len) { int rc = 0; int i; BN_CTX *ctx = NULL; const EC_GROUP *group = EC_KEY_get0_group(key); EC_POINT *C1 = NULL; struct SM2_Ciphertext_st *sm2_ctext = NULL; BIGNUM *x2 = NULL; BIGNUM *y2 = NULL; uint8_t *x2y2 = NULL; uint8_t *computed_C3 = NULL; const size_t field_size = ec_field_size(group); const int hash_size = EVP_MD_size(digest); uint8_t *msg_mask = NULL; const uint8_t *C2 = NULL; const uint8_t *C3 = NULL; int msg_len = 0; EVP_MD_CTX *hash = NULL; if (field_size == 0 || hash_size <= 0) goto done; memset(ptext_buf, 0xFF, *ptext_len); sm2_ctext = d2i_SM2_Ciphertext(NULL, &ciphertext, ciphertext_len); if (sm2_ctext == NULL) { SM2err(SM2_F_SM2_DECRYPT, SM2_R_ASN1_ERROR); goto done; } if (sm2_ctext->C3->length != hash_size) { SM2err(SM2_F_SM2_DECRYPT, SM2_R_INVALID_ENCODING); goto done; } C2 = sm2_ctext->C2->data; C3 = sm2_ctext->C3->data; msg_len = sm2_ctext->C2->length; + if (*ptext_len < (size_t)msg_len) { + SM2err(SM2_F_SM2_DECRYPT, SM2_R_BUFFER_TOO_SMALL); + goto done; + } ctx = BN_CTX_new(); if (ctx == NULL) { SM2err(SM2_F_SM2_DECRYPT, ERR_R_MALLOC_FAILURE); goto done; } BN_CTX_start(ctx); x2 = BN_CTX_get(ctx); y2 = BN_CTX_get(ctx); if (y2 == NULL) { SM2err(SM2_F_SM2_DECRYPT, ERR_R_BN_LIB); goto done; } msg_mask = OPENSSL_zalloc(msg_len); x2y2 = OPENSSL_zalloc(2 * field_size); computed_C3 = OPENSSL_zalloc(hash_size); if (msg_mask == NULL || x2y2 == NULL || computed_C3 == NULL) { SM2err(SM2_F_SM2_DECRYPT, ERR_R_MALLOC_FAILURE); goto done; } C1 = EC_POINT_new(group); if (C1 == NULL) { SM2err(SM2_F_SM2_DECRYPT, ERR_R_MALLOC_FAILURE); goto done; } if (!EC_POINT_set_affine_coordinates(group, C1, sm2_ctext->C1x, sm2_ctext->C1y, ctx) || !EC_POINT_mul(group, C1, NULL, C1, EC_KEY_get0_private_key(key), ctx) || !EC_POINT_get_affine_coordinates(group, C1, x2, y2, ctx)) { SM2err(SM2_F_SM2_DECRYPT, ERR_R_EC_LIB); goto done; } if (BN_bn2binpad(x2, x2y2, field_size) < 0 || BN_bn2binpad(y2, x2y2 + field_size, field_size) < 0 || !ecdh_KDF_X9_63(msg_mask, msg_len, x2y2, 2 * field_size, NULL, 0, digest)) { SM2err(SM2_F_SM2_DECRYPT, ERR_R_INTERNAL_ERROR); goto done; } for (i = 0; i != msg_len; ++i) ptext_buf[i] = C2[i] ^ msg_mask[i]; hash = EVP_MD_CTX_new(); if (hash == NULL) { SM2err(SM2_F_SM2_DECRYPT, ERR_R_MALLOC_FAILURE); goto done; } if (!EVP_DigestInit(hash, digest) || !EVP_DigestUpdate(hash, x2y2, field_size) || !EVP_DigestUpdate(hash, ptext_buf, msg_len) || !EVP_DigestUpdate(hash, x2y2 + field_size, field_size) || !EVP_DigestFinal(hash, computed_C3, NULL)) { SM2err(SM2_F_SM2_DECRYPT, ERR_R_EVP_LIB); goto done; } if (CRYPTO_memcmp(computed_C3, C3, hash_size) != 0) { SM2err(SM2_F_SM2_DECRYPT, SM2_R_INVALID_DIGEST); goto done; } rc = 1; *ptext_len = msg_len; done: if (rc == 0) memset(ptext_buf, 0, *ptext_len); OPENSSL_free(msg_mask); OPENSSL_free(x2y2); OPENSSL_free(computed_C3); EC_POINT_free(C1); BN_CTX_free(ctx); SM2_Ciphertext_free(sm2_ctext); EVP_MD_CTX_free(hash); return rc; } diff --git a/crypto/openssl/crypto/sm2/sm2_pmeth.c b/crypto/openssl/crypto/sm2/sm2_pmeth.c index b42a14c32f26..27025fbf3a2c 100644 --- a/crypto/openssl/crypto/sm2/sm2_pmeth.c +++ b/crypto/openssl/crypto/sm2/sm2_pmeth.c @@ -1,329 +1,329 @@ /* * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include "internal/cryptlib.h" #include #include #include #include "crypto/evp.h" #include "crypto/sm2.h" #include "crypto/sm2err.h" /* EC pkey context structure */ typedef struct { /* Key and paramgen group */ EC_GROUP *gen_group; /* message digest */ const EVP_MD *md; /* Distinguishing Identifier, ISO/IEC 15946-3 */ uint8_t *id; size_t id_len; /* id_set indicates if the 'id' field is set (1) or not (0) */ int id_set; } SM2_PKEY_CTX; static int pkey_sm2_init(EVP_PKEY_CTX *ctx) { SM2_PKEY_CTX *smctx; if ((smctx = OPENSSL_zalloc(sizeof(*smctx))) == NULL) { SM2err(SM2_F_PKEY_SM2_INIT, ERR_R_MALLOC_FAILURE); return 0; } ctx->data = smctx; return 1; } static void pkey_sm2_cleanup(EVP_PKEY_CTX *ctx) { SM2_PKEY_CTX *smctx = ctx->data; if (smctx != NULL) { EC_GROUP_free(smctx->gen_group); OPENSSL_free(smctx->id); OPENSSL_free(smctx); ctx->data = NULL; } } static int pkey_sm2_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { SM2_PKEY_CTX *dctx, *sctx; if (!pkey_sm2_init(dst)) return 0; sctx = src->data; dctx = dst->data; if (sctx->gen_group != NULL) { dctx->gen_group = EC_GROUP_dup(sctx->gen_group); if (dctx->gen_group == NULL) { pkey_sm2_cleanup(dst); return 0; } } if (sctx->id != NULL) { dctx->id = OPENSSL_malloc(sctx->id_len); if (dctx->id == NULL) { SM2err(SM2_F_PKEY_SM2_COPY, ERR_R_MALLOC_FAILURE); pkey_sm2_cleanup(dst); return 0; } memcpy(dctx->id, sctx->id, sctx->id_len); } dctx->id_len = sctx->id_len; dctx->id_set = sctx->id_set; dctx->md = sctx->md; return 1; } static int pkey_sm2_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen) { int ret; unsigned int sltmp; EC_KEY *ec = ctx->pkey->pkey.ec; const int sig_sz = ECDSA_size(ctx->pkey->pkey.ec); if (sig_sz <= 0) { return 0; } if (sig == NULL) { *siglen = (size_t)sig_sz; return 1; } if (*siglen < (size_t)sig_sz) { SM2err(SM2_F_PKEY_SM2_SIGN, SM2_R_BUFFER_TOO_SMALL); return 0; } ret = sm2_sign(tbs, tbslen, sig, &sltmp, ec); if (ret <= 0) return ret; *siglen = (size_t)sltmp; return 1; } static int pkey_sm2_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen) { EC_KEY *ec = ctx->pkey->pkey.ec; return sm2_verify(tbs, tbslen, sig, siglen, ec); } static int pkey_sm2_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) { EC_KEY *ec = ctx->pkey->pkey.ec; SM2_PKEY_CTX *dctx = ctx->data; const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md; if (out == NULL) { if (!sm2_ciphertext_size(ec, md, inlen, outlen)) return -1; else return 1; } return sm2_encrypt(ec, md, in, inlen, out, outlen); } static int pkey_sm2_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) { EC_KEY *ec = ctx->pkey->pkey.ec; SM2_PKEY_CTX *dctx = ctx->data; const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md; if (out == NULL) { - if (!sm2_plaintext_size(ec, md, inlen, outlen)) + if (!sm2_plaintext_size(in, inlen, outlen)) return -1; else return 1; } return sm2_decrypt(ec, md, in, inlen, out, outlen); } static int pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { SM2_PKEY_CTX *smctx = ctx->data; EC_GROUP *group; uint8_t *tmp_id; switch (type) { case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID: group = EC_GROUP_new_by_curve_name(p1); if (group == NULL) { SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_INVALID_CURVE); return 0; } EC_GROUP_free(smctx->gen_group); smctx->gen_group = group; return 1; case EVP_PKEY_CTRL_EC_PARAM_ENC: if (smctx->gen_group == NULL) { SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_NO_PARAMETERS_SET); return 0; } EC_GROUP_set_asn1_flag(smctx->gen_group, p1); return 1; case EVP_PKEY_CTRL_MD: smctx->md = p2; return 1; case EVP_PKEY_CTRL_GET_MD: *(const EVP_MD **)p2 = smctx->md; return 1; case EVP_PKEY_CTRL_SET1_ID: if (p1 > 0) { tmp_id = OPENSSL_malloc(p1); if (tmp_id == NULL) { SM2err(SM2_F_PKEY_SM2_CTRL, ERR_R_MALLOC_FAILURE); return 0; } memcpy(tmp_id, p2, p1); OPENSSL_free(smctx->id); smctx->id = tmp_id; } else { /* set null-ID */ OPENSSL_free(smctx->id); smctx->id = NULL; } smctx->id_len = (size_t)p1; smctx->id_set = 1; return 1; case EVP_PKEY_CTRL_GET1_ID: memcpy(p2, smctx->id, smctx->id_len); return 1; case EVP_PKEY_CTRL_GET1_ID_LEN: *(size_t *)p2 = smctx->id_len; return 1; case EVP_PKEY_CTRL_DIGESTINIT: /* nothing to be inited, this is to suppress the error... */ return 1; default: return -2; } } static int pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value) { if (strcmp(type, "ec_paramgen_curve") == 0) { int nid = NID_undef; if (((nid = EC_curve_nist2nid(value)) == NID_undef) && ((nid = OBJ_sn2nid(value)) == NID_undef) && ((nid = OBJ_ln2nid(value)) == NID_undef)) { SM2err(SM2_F_PKEY_SM2_CTRL_STR, SM2_R_INVALID_CURVE); return 0; } return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid); } else if (strcmp(type, "ec_param_enc") == 0) { int param_enc; if (strcmp(value, "explicit") == 0) param_enc = 0; else if (strcmp(value, "named_curve") == 0) param_enc = OPENSSL_EC_NAMED_CURVE; else return -2; return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc); } return -2; } static int pkey_sm2_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) { uint8_t z[EVP_MAX_MD_SIZE]; SM2_PKEY_CTX *smctx = ctx->data; EC_KEY *ec = ctx->pkey->pkey.ec; const EVP_MD *md = EVP_MD_CTX_md(mctx); int mdlen = EVP_MD_size(md); if (!smctx->id_set) { /* * An ID value must be set. The specifications are not clear whether a * NULL is allowed. We only allow it if set explicitly for maximum * flexibility. */ SM2err(SM2_F_PKEY_SM2_DIGEST_CUSTOM, SM2_R_ID_NOT_SET); return 0; } if (mdlen < 0) { SM2err(SM2_F_PKEY_SM2_DIGEST_CUSTOM, SM2_R_INVALID_DIGEST); return 0; } /* get hashed prefix 'z' of tbs message */ if (!sm2_compute_z_digest(z, md, smctx->id, smctx->id_len, ec)) return 0; return EVP_DigestUpdate(mctx, z, (size_t)mdlen); } const EVP_PKEY_METHOD sm2_pkey_meth = { EVP_PKEY_SM2, 0, pkey_sm2_init, pkey_sm2_copy, pkey_sm2_cleanup, 0, 0, 0, 0, 0, pkey_sm2_sign, 0, pkey_sm2_verify, 0, 0, 0, 0, 0, 0, 0, pkey_sm2_encrypt, 0, pkey_sm2_decrypt, 0, 0, pkey_sm2_ctrl, pkey_sm2_ctrl_str, 0, 0, 0, 0, 0, pkey_sm2_digest_custom }; diff --git a/crypto/openssl/crypto/x509v3/v3_akey.c b/crypto/openssl/crypto/x509v3/v3_akey.c index d9f770433cfb..f917142223b7 100644 --- a/crypto/openssl/crypto/x509v3/v3_akey.c +++ b/crypto/openssl/crypto/x509v3/v3_akey.c @@ -1,160 +1,188 @@ /* * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include #include "internal/cryptlib.h" #include #include #include #include #include "ext_dat.h" static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, AUTHORITY_KEYID *akeyid, STACK_OF(CONF_VALUE) *extlist); static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values); const X509V3_EXT_METHOD v3_akey_id = { NID_authority_key_identifier, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_KEYID), 0, 0, 0, 0, 0, 0, (X509V3_EXT_I2V) i2v_AUTHORITY_KEYID, (X509V3_EXT_V2I)v2i_AUTHORITY_KEYID, 0, 0, NULL }; static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, AUTHORITY_KEYID *akeyid, STACK_OF(CONF_VALUE) *extlist) { - char *tmp; + char *tmp = NULL; + STACK_OF(CONF_VALUE) *origextlist = extlist, *tmpextlist; + if (akeyid->keyid) { tmp = OPENSSL_buf2hexstr(akeyid->keyid->data, akeyid->keyid->length); - X509V3_add_value("keyid", tmp, &extlist); + if (tmp == NULL) { + X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ERR_R_MALLOC_FAILURE); + return NULL; + } + if (!X509V3_add_value("keyid", tmp, &extlist)) { + OPENSSL_free(tmp); + X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ERR_R_X509_LIB); + goto err; + } OPENSSL_free(tmp); } - if (akeyid->issuer) - extlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist); + if (akeyid->issuer) { + tmpextlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist); + if (tmpextlist == NULL) { + X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ERR_R_X509_LIB); + goto err; + } + extlist = tmpextlist; + } if (akeyid->serial) { tmp = OPENSSL_buf2hexstr(akeyid->serial->data, akeyid->serial->length); - X509V3_add_value("serial", tmp, &extlist); + if (tmp == NULL) { + X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!X509V3_add_value("serial", tmp, &extlist)) { + OPENSSL_free(tmp); + X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ERR_R_X509_LIB); + goto err; + } OPENSSL_free(tmp); } return extlist; + err: + if (origextlist == NULL) + sk_CONF_VALUE_pop_free(extlist, X509V3_conf_free); + return NULL; } /*- * Currently two options: * keyid: use the issuers subject keyid, the value 'always' means its is * an error if the issuer certificate doesn't have a key id. * issuer: use the issuers cert issuer and serial number. The default is * to only use this if keyid is not present. With the option 'always' * this is always included. */ static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values) { char keyid = 0, issuer = 0; int i; CONF_VALUE *cnf; ASN1_OCTET_STRING *ikeyid = NULL; X509_NAME *isname = NULL; GENERAL_NAMES *gens = NULL; GENERAL_NAME *gen = NULL; ASN1_INTEGER *serial = NULL; X509_EXTENSION *ext; X509 *cert; AUTHORITY_KEYID *akeyid; for (i = 0; i < sk_CONF_VALUE_num(values); i++) { cnf = sk_CONF_VALUE_value(values, i); if (strcmp(cnf->name, "keyid") == 0) { keyid = 1; if (cnf->value && strcmp(cnf->value, "always") == 0) keyid = 2; } else if (strcmp(cnf->name, "issuer") == 0) { issuer = 1; if (cnf->value && strcmp(cnf->value, "always") == 0) issuer = 2; } else { X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, X509V3_R_UNKNOWN_OPTION); ERR_add_error_data(2, "name=", cnf->name); return NULL; } } if (!ctx || !ctx->issuer_cert) { if (ctx && (ctx->flags == CTX_TEST)) return AUTHORITY_KEYID_new(); X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, X509V3_R_NO_ISSUER_CERTIFICATE); return NULL; } cert = ctx->issuer_cert; if (keyid) { i = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1); if ((i >= 0) && (ext = X509_get_ext(cert, i))) ikeyid = X509V3_EXT_d2i(ext); if (keyid == 2 && !ikeyid) { X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID); return NULL; } } if ((issuer && !ikeyid) || (issuer == 2)) { isname = X509_NAME_dup(X509_get_issuer_name(cert)); serial = ASN1_INTEGER_dup(X509_get_serialNumber(cert)); if (!isname || !serial) { X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS); goto err; } } if ((akeyid = AUTHORITY_KEYID_new()) == NULL) goto err; if (isname) { if ((gens = sk_GENERAL_NAME_new_null()) == NULL || (gen = GENERAL_NAME_new()) == NULL || !sk_GENERAL_NAME_push(gens, gen)) { X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ERR_R_MALLOC_FAILURE); goto err; } gen->type = GEN_DIRNAME; gen->d.dirn = isname; } akeyid->issuer = gens; gen = NULL; gens = NULL; akeyid->serial = serial; akeyid->keyid = ikeyid; return akeyid; err: sk_GENERAL_NAME_free(gens); GENERAL_NAME_free(gen); X509_NAME_free(isname); ASN1_INTEGER_free(serial); ASN1_OCTET_STRING_free(ikeyid); return NULL; } diff --git a/crypto/openssl/crypto/x509v3/v3_alt.c b/crypto/openssl/crypto/x509v3/v3_alt.c index 4dce0041012e..6e5f9f8b0eac 100644 --- a/crypto/openssl/crypto/x509v3/v3_alt.c +++ b/crypto/openssl/crypto/x509v3/v3_alt.c @@ -1,609 +1,613 @@ /* * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include #include "internal/cryptlib.h" +#include "crypto/x509.h" #include #include #include "ext_dat.h" static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p); static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens); static int do_othername(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx); static int do_dirname(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx); const X509V3_EXT_METHOD v3_alt[3] = { {NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), 0, 0, 0, 0, 0, 0, (X509V3_EXT_I2V) i2v_GENERAL_NAMES, (X509V3_EXT_V2I)v2i_subject_alt, NULL, NULL, NULL}, {NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), 0, 0, 0, 0, 0, 0, (X509V3_EXT_I2V) i2v_GENERAL_NAMES, (X509V3_EXT_V2I)v2i_issuer_alt, NULL, NULL, NULL}, {NID_certificate_issuer, 0, ASN1_ITEM_ref(GENERAL_NAMES), 0, 0, 0, 0, 0, 0, (X509V3_EXT_I2V) i2v_GENERAL_NAMES, NULL, NULL, NULL, NULL}, }; STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, GENERAL_NAMES *gens, STACK_OF(CONF_VALUE) *ret) { int i; GENERAL_NAME *gen; STACK_OF(CONF_VALUE) *tmpret = NULL, *origret = ret; for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { gen = sk_GENERAL_NAME_value(gens, i); /* * i2v_GENERAL_NAME allocates ret if it is NULL. If something goes * wrong we need to free the stack - but only if it was empty when we * originally entered this function. */ tmpret = i2v_GENERAL_NAME(method, gen, ret); if (tmpret == NULL) { if (origret == NULL) sk_CONF_VALUE_pop_free(ret, X509V3_conf_free); return NULL; } ret = tmpret; } if (ret == NULL) return sk_CONF_VALUE_new_null(); return ret; } STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret) { unsigned char *p; char oline[256], htmp[5]; int i; switch (gen->type) { case GEN_OTHERNAME: if (!X509V3_add_value("othername", "", &ret)) return NULL; break; case GEN_X400: if (!X509V3_add_value("X400Name", "", &ret)) return NULL; break; case GEN_EDIPARTY: if (!X509V3_add_value("EdiPartyName", "", &ret)) return NULL; break; case GEN_EMAIL: - if (!X509V3_add_value_uchar("email", gen->d.ia5->data, &ret)) + if (!x509v3_add_len_value_uchar("email", gen->d.ia5->data, + gen->d.ia5->length, &ret)) return NULL; break; case GEN_DNS: - if (!X509V3_add_value_uchar("DNS", gen->d.ia5->data, &ret)) + if (!x509v3_add_len_value_uchar("DNS", gen->d.ia5->data, + gen->d.ia5->length, &ret)) return NULL; break; case GEN_URI: - if (!X509V3_add_value_uchar("URI", gen->d.ia5->data, &ret)) + if (!x509v3_add_len_value_uchar("URI", gen->d.ia5->data, + gen->d.ia5->length, &ret)) return NULL; break; case GEN_DIRNAME: if (X509_NAME_oneline(gen->d.dirn, oline, sizeof(oline)) == NULL || !X509V3_add_value("DirName", oline, &ret)) return NULL; break; case GEN_IPADD: p = gen->d.ip->data; if (gen->d.ip->length == 4) BIO_snprintf(oline, sizeof(oline), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); else if (gen->d.ip->length == 16) { oline[0] = 0; for (i = 0; i < 8; i++) { BIO_snprintf(htmp, sizeof(htmp), "%X", p[0] << 8 | p[1]); p += 2; strcat(oline, htmp); if (i != 7) strcat(oline, ":"); } } else { if (!X509V3_add_value("IP Address", "", &ret)) return NULL; break; } if (!X509V3_add_value("IP Address", oline, &ret)) return NULL; break; case GEN_RID: i2t_ASN1_OBJECT(oline, 256, gen->d.rid); if (!X509V3_add_value("Registered ID", oline, &ret)) return NULL; break; } return ret; } int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen) { unsigned char *p; int i; switch (gen->type) { case GEN_OTHERNAME: BIO_printf(out, "othername:"); break; case GEN_X400: BIO_printf(out, "X400Name:"); break; case GEN_EDIPARTY: /* Maybe fix this: it is supported now */ BIO_printf(out, "EdiPartyName:"); break; case GEN_EMAIL: BIO_printf(out, "email:"); ASN1_STRING_print(out, gen->d.ia5); break; case GEN_DNS: BIO_printf(out, "DNS:"); ASN1_STRING_print(out, gen->d.ia5); break; case GEN_URI: BIO_printf(out, "URI:"); ASN1_STRING_print(out, gen->d.ia5); break; case GEN_DIRNAME: BIO_printf(out, "DirName:"); X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE); break; case GEN_IPADD: p = gen->d.ip->data; if (gen->d.ip->length == 4) BIO_printf(out, "IP Address:%d.%d.%d.%d", p[0], p[1], p[2], p[3]); else if (gen->d.ip->length == 16) { BIO_printf(out, "IP Address"); for (i = 0; i < 8; i++) { BIO_printf(out, ":%X", p[0] << 8 | p[1]); p += 2; } BIO_puts(out, "\n"); } else { BIO_printf(out, "IP Address:"); break; } break; case GEN_RID: BIO_printf(out, "Registered ID:"); i2a_ASN1_OBJECT(out, gen->d.rid); break; } return 1; } static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) { const int num = sk_CONF_VALUE_num(nval); GENERAL_NAMES *gens = sk_GENERAL_NAME_new_reserve(NULL, num); int i; if (gens == NULL) { X509V3err(X509V3_F_V2I_ISSUER_ALT, ERR_R_MALLOC_FAILURE); sk_GENERAL_NAME_free(gens); return NULL; } for (i = 0; i < num; i++) { CONF_VALUE *cnf = sk_CONF_VALUE_value(nval, i); if (!name_cmp(cnf->name, "issuer") && cnf->value && strcmp(cnf->value, "copy") == 0) { if (!copy_issuer(ctx, gens)) goto err; } else { GENERAL_NAME *gen = v2i_GENERAL_NAME(method, ctx, cnf); if (gen == NULL) goto err; sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */ } } return gens; err: sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); return NULL; } /* Append subject altname of issuer to issuer alt name of subject */ static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens) { GENERAL_NAMES *ialt; GENERAL_NAME *gen; X509_EXTENSION *ext; int i, num; if (ctx && (ctx->flags == CTX_TEST)) return 1; if (!ctx || !ctx->issuer_cert) { X509V3err(X509V3_F_COPY_ISSUER, X509V3_R_NO_ISSUER_DETAILS); goto err; } i = X509_get_ext_by_NID(ctx->issuer_cert, NID_subject_alt_name, -1); if (i < 0) return 1; if ((ext = X509_get_ext(ctx->issuer_cert, i)) == NULL || (ialt = X509V3_EXT_d2i(ext)) == NULL) { X509V3err(X509V3_F_COPY_ISSUER, X509V3_R_ISSUER_DECODE_ERROR); goto err; } num = sk_GENERAL_NAME_num(ialt); if (!sk_GENERAL_NAME_reserve(gens, num)) { X509V3err(X509V3_F_COPY_ISSUER, ERR_R_MALLOC_FAILURE); sk_GENERAL_NAME_free(ialt); goto err; } for (i = 0; i < num; i++) { gen = sk_GENERAL_NAME_value(ialt, i); sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */ } sk_GENERAL_NAME_free(ialt); return 1; err: return 0; } static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) { GENERAL_NAMES *gens; CONF_VALUE *cnf; const int num = sk_CONF_VALUE_num(nval); int i; gens = sk_GENERAL_NAME_new_reserve(NULL, num); if (gens == NULL) { X509V3err(X509V3_F_V2I_SUBJECT_ALT, ERR_R_MALLOC_FAILURE); sk_GENERAL_NAME_free(gens); return NULL; } for (i = 0; i < num; i++) { cnf = sk_CONF_VALUE_value(nval, i); if (!name_cmp(cnf->name, "email") && cnf->value && strcmp(cnf->value, "copy") == 0) { if (!copy_email(ctx, gens, 0)) goto err; } else if (!name_cmp(cnf->name, "email") && cnf->value && strcmp(cnf->value, "move") == 0) { if (!copy_email(ctx, gens, 1)) goto err; } else { GENERAL_NAME *gen; if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL) goto err; sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */ } } return gens; err: sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); return NULL; } /* * Copy any email addresses in a certificate or request to GENERAL_NAMES */ static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p) { X509_NAME *nm; ASN1_IA5STRING *email = NULL; X509_NAME_ENTRY *ne; GENERAL_NAME *gen = NULL; int i = -1; if (ctx != NULL && ctx->flags == CTX_TEST) return 1; if (ctx == NULL || (ctx->subject_cert == NULL && ctx->subject_req == NULL)) { X509V3err(X509V3_F_COPY_EMAIL, X509V3_R_NO_SUBJECT_DETAILS); goto err; } /* Find the subject name */ if (ctx->subject_cert) nm = X509_get_subject_name(ctx->subject_cert); else nm = X509_REQ_get_subject_name(ctx->subject_req); /* Now add any email address(es) to STACK */ while ((i = X509_NAME_get_index_by_NID(nm, NID_pkcs9_emailAddress, i)) >= 0) { ne = X509_NAME_get_entry(nm, i); email = ASN1_STRING_dup(X509_NAME_ENTRY_get_data(ne)); if (move_p) { X509_NAME_delete_entry(nm, i); X509_NAME_ENTRY_free(ne); i--; } if (email == NULL || (gen = GENERAL_NAME_new()) == NULL) { X509V3err(X509V3_F_COPY_EMAIL, ERR_R_MALLOC_FAILURE); goto err; } gen->d.ia5 = email; email = NULL; gen->type = GEN_EMAIL; if (!sk_GENERAL_NAME_push(gens, gen)) { X509V3err(X509V3_F_COPY_EMAIL, ERR_R_MALLOC_FAILURE); goto err; } gen = NULL; } return 1; err: GENERAL_NAME_free(gen); ASN1_IA5STRING_free(email); return 0; } GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) { GENERAL_NAME *gen; GENERAL_NAMES *gens; CONF_VALUE *cnf; const int num = sk_CONF_VALUE_num(nval); int i; gens = sk_GENERAL_NAME_new_reserve(NULL, num); if (gens == NULL) { X509V3err(X509V3_F_V2I_GENERAL_NAMES, ERR_R_MALLOC_FAILURE); sk_GENERAL_NAME_free(gens); return NULL; } for (i = 0; i < num; i++) { cnf = sk_CONF_VALUE_value(nval, i); if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL) goto err; sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */ } return gens; err: sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); return NULL; } GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, CONF_VALUE *cnf) { return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0); } GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out, const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, int gen_type, const char *value, int is_nc) { char is_string = 0; GENERAL_NAME *gen = NULL; if (!value) { X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_MISSING_VALUE); return NULL; } if (out) gen = out; else { gen = GENERAL_NAME_new(); if (gen == NULL) { X509V3err(X509V3_F_A2I_GENERAL_NAME, ERR_R_MALLOC_FAILURE); return NULL; } } switch (gen_type) { case GEN_URI: case GEN_EMAIL: case GEN_DNS: is_string = 1; break; case GEN_RID: { ASN1_OBJECT *obj; if ((obj = OBJ_txt2obj(value, 0)) == NULL) { X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_BAD_OBJECT); ERR_add_error_data(2, "value=", value); goto err; } gen->d.rid = obj; } break; case GEN_IPADD: if (is_nc) gen->d.ip = a2i_IPADDRESS_NC(value); else gen->d.ip = a2i_IPADDRESS(value); if (gen->d.ip == NULL) { X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_BAD_IP_ADDRESS); ERR_add_error_data(2, "value=", value); goto err; } break; case GEN_DIRNAME: if (!do_dirname(gen, value, ctx)) { X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_DIRNAME_ERROR); goto err; } break; case GEN_OTHERNAME: if (!do_othername(gen, value, ctx)) { X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_OTHERNAME_ERROR); goto err; } break; default: X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_UNSUPPORTED_TYPE); goto err; } if (is_string) { if ((gen->d.ia5 = ASN1_IA5STRING_new()) == NULL || !ASN1_STRING_set(gen->d.ia5, (unsigned char *)value, strlen(value))) { X509V3err(X509V3_F_A2I_GENERAL_NAME, ERR_R_MALLOC_FAILURE); goto err; } } gen->type = gen_type; return gen; err: if (!out) GENERAL_NAME_free(gen); return NULL; } GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc) { int type; char *name, *value; name = cnf->name; value = cnf->value; if (!value) { X509V3err(X509V3_F_V2I_GENERAL_NAME_EX, X509V3_R_MISSING_VALUE); return NULL; } if (!name_cmp(name, "email")) type = GEN_EMAIL; else if (!name_cmp(name, "URI")) type = GEN_URI; else if (!name_cmp(name, "DNS")) type = GEN_DNS; else if (!name_cmp(name, "RID")) type = GEN_RID; else if (!name_cmp(name, "IP")) type = GEN_IPADD; else if (!name_cmp(name, "dirName")) type = GEN_DIRNAME; else if (!name_cmp(name, "otherName")) type = GEN_OTHERNAME; else { X509V3err(X509V3_F_V2I_GENERAL_NAME_EX, X509V3_R_UNSUPPORTED_OPTION); ERR_add_error_data(2, "name=", name); return NULL; } return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc); } static int do_othername(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx) { char *objtmp = NULL, *p; int objlen; if ((p = strchr(value, ';')) == NULL) return 0; if ((gen->d.otherName = OTHERNAME_new()) == NULL) return 0; /* * Free this up because we will overwrite it. no need to free type_id * because it is static */ ASN1_TYPE_free(gen->d.otherName->value); if ((gen->d.otherName->value = ASN1_generate_v3(p + 1, ctx)) == NULL) return 0; objlen = p - value; objtmp = OPENSSL_strndup(value, objlen); if (objtmp == NULL) return 0; gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0); OPENSSL_free(objtmp); if (!gen->d.otherName->type_id) return 0; return 1; } static int do_dirname(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx) { int ret = 0; STACK_OF(CONF_VALUE) *sk = NULL; X509_NAME *nm; if ((nm = X509_NAME_new()) == NULL) goto err; sk = X509V3_get_section(ctx, value); if (!sk) { X509V3err(X509V3_F_DO_DIRNAME, X509V3_R_SECTION_NOT_FOUND); ERR_add_error_data(2, "section=", value); goto err; } /* FIXME: should allow other character types... */ ret = X509V3_NAME_from_section(nm, sk, MBSTRING_ASC); if (!ret) goto err; gen->d.dirn = nm; err: if (ret == 0) X509_NAME_free(nm); X509V3_section_free(ctx, sk); return ret; } diff --git a/crypto/openssl/crypto/x509v3/v3_cpols.c b/crypto/openssl/crypto/x509v3/v3_cpols.c index 1d12c899125c..861e8455dd08 100644 --- a/crypto/openssl/crypto/x509v3/v3_cpols.c +++ b/crypto/openssl/crypto/x509v3/v3_cpols.c @@ -1,491 +1,494 @@ /* * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include #include "internal/cryptlib.h" #include #include #include #include #include "pcy_local.h" #include "ext_dat.h" /* Certificate policies extension support: this one is a bit complex... */ static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol, BIO *out, int indent); static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, const char *value); static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, int indent); static void print_notice(BIO *out, USERNOTICE *notice, int indent); static POLICYINFO *policy_section(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *polstrs, int ia5org); static POLICYQUALINFO *notice_section(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *unot, int ia5org); static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos); static int displaytext_str2tag(const char *tagstr, unsigned int *tag_len); static int displaytext_get_tag_len(const char *tagstr); const X509V3_EXT_METHOD v3_cpols = { NID_certificate_policies, 0, ASN1_ITEM_ref(CERTIFICATEPOLICIES), 0, 0, 0, 0, 0, 0, 0, 0, (X509V3_EXT_I2R)i2r_certpol, (X509V3_EXT_R2I)r2i_certpol, NULL }; ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO) ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES) IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) ASN1_SEQUENCE(POLICYINFO) = { ASN1_SIMPLE(POLICYINFO, policyid, ASN1_OBJECT), ASN1_SEQUENCE_OF_OPT(POLICYINFO, qualifiers, POLICYQUALINFO) } ASN1_SEQUENCE_END(POLICYINFO) IMPLEMENT_ASN1_FUNCTIONS(POLICYINFO) ASN1_ADB_TEMPLATE(policydefault) = ASN1_SIMPLE(POLICYQUALINFO, d.other, ASN1_ANY); ASN1_ADB(POLICYQUALINFO) = { ADB_ENTRY(NID_id_qt_cps, ASN1_SIMPLE(POLICYQUALINFO, d.cpsuri, ASN1_IA5STRING)), ADB_ENTRY(NID_id_qt_unotice, ASN1_SIMPLE(POLICYQUALINFO, d.usernotice, USERNOTICE)) } ASN1_ADB_END(POLICYQUALINFO, 0, pqualid, 0, &policydefault_tt, NULL); ASN1_SEQUENCE(POLICYQUALINFO) = { ASN1_SIMPLE(POLICYQUALINFO, pqualid, ASN1_OBJECT), ASN1_ADB_OBJECT(POLICYQUALINFO) } ASN1_SEQUENCE_END(POLICYQUALINFO) IMPLEMENT_ASN1_FUNCTIONS(POLICYQUALINFO) ASN1_SEQUENCE(USERNOTICE) = { ASN1_OPT(USERNOTICE, noticeref, NOTICEREF), ASN1_OPT(USERNOTICE, exptext, DISPLAYTEXT) } ASN1_SEQUENCE_END(USERNOTICE) IMPLEMENT_ASN1_FUNCTIONS(USERNOTICE) ASN1_SEQUENCE(NOTICEREF) = { ASN1_SIMPLE(NOTICEREF, organization, DISPLAYTEXT), ASN1_SEQUENCE_OF(NOTICEREF, noticenos, ASN1_INTEGER) } ASN1_SEQUENCE_END(NOTICEREF) IMPLEMENT_ASN1_FUNCTIONS(NOTICEREF) static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, const char *value) { STACK_OF(POLICYINFO) *pols; char *pstr; POLICYINFO *pol; ASN1_OBJECT *pobj; STACK_OF(CONF_VALUE) *vals = X509V3_parse_list(value); CONF_VALUE *cnf; const int num = sk_CONF_VALUE_num(vals); int i, ia5org; if (vals == NULL) { X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_X509V3_LIB); return NULL; } pols = sk_POLICYINFO_new_reserve(NULL, num); if (pols == NULL) { X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE); goto err; } ia5org = 0; for (i = 0; i < num; i++) { cnf = sk_CONF_VALUE_value(vals, i); if (cnf->value || !cnf->name) { X509V3err(X509V3_F_R2I_CERTPOL, X509V3_R_INVALID_POLICY_IDENTIFIER); X509V3_conf_err(cnf); goto err; } pstr = cnf->name; if (strcmp(pstr, "ia5org") == 0) { ia5org = 1; continue; } else if (*pstr == '@') { STACK_OF(CONF_VALUE) *polsect; polsect = X509V3_get_section(ctx, pstr + 1); if (!polsect) { X509V3err(X509V3_F_R2I_CERTPOL, X509V3_R_INVALID_SECTION); X509V3_conf_err(cnf); goto err; } pol = policy_section(ctx, polsect, ia5org); X509V3_section_free(ctx, polsect); if (pol == NULL) goto err; } else { if ((pobj = OBJ_txt2obj(cnf->name, 0)) == NULL) { X509V3err(X509V3_F_R2I_CERTPOL, X509V3_R_INVALID_OBJECT_IDENTIFIER); X509V3_conf_err(cnf); goto err; } pol = POLICYINFO_new(); if (pol == NULL) { ASN1_OBJECT_free(pobj); X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE); goto err; } pol->policyid = pobj; } if (!sk_POLICYINFO_push(pols, pol)) { POLICYINFO_free(pol); X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE); goto err; } } sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); return pols; err: sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); sk_POLICYINFO_pop_free(pols, POLICYINFO_free); return NULL; } static POLICYINFO *policy_section(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *polstrs, int ia5org) { int i; CONF_VALUE *cnf; POLICYINFO *pol; POLICYQUALINFO *qual; if ((pol = POLICYINFO_new()) == NULL) goto merr; for (i = 0; i < sk_CONF_VALUE_num(polstrs); i++) { cnf = sk_CONF_VALUE_value(polstrs, i); if (strcmp(cnf->name, "policyIdentifier") == 0) { ASN1_OBJECT *pobj; if ((pobj = OBJ_txt2obj(cnf->value, 0)) == NULL) { X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_INVALID_OBJECT_IDENTIFIER); X509V3_conf_err(cnf); goto err; } pol->policyid = pobj; } else if (!name_cmp(cnf->name, "CPS")) { if (pol->qualifiers == NULL) pol->qualifiers = sk_POLICYQUALINFO_new_null(); if ((qual = POLICYQUALINFO_new()) == NULL) goto merr; if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual)) goto merr; if ((qual->pqualid = OBJ_nid2obj(NID_id_qt_cps)) == NULL) { X509V3err(X509V3_F_POLICY_SECTION, ERR_R_INTERNAL_ERROR); goto err; } if ((qual->d.cpsuri = ASN1_IA5STRING_new()) == NULL) goto merr; if (!ASN1_STRING_set(qual->d.cpsuri, cnf->value, strlen(cnf->value))) goto merr; } else if (!name_cmp(cnf->name, "userNotice")) { STACK_OF(CONF_VALUE) *unot; if (*cnf->value != '@') { X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_EXPECTED_A_SECTION_NAME); X509V3_conf_err(cnf); goto err; } unot = X509V3_get_section(ctx, cnf->value + 1); if (!unot) { X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_INVALID_SECTION); X509V3_conf_err(cnf); goto err; } qual = notice_section(ctx, unot, ia5org); X509V3_section_free(ctx, unot); if (!qual) goto err; if (!pol->qualifiers) pol->qualifiers = sk_POLICYQUALINFO_new_null(); if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual)) goto merr; } else { X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_INVALID_OPTION); X509V3_conf_err(cnf); goto err; } } if (!pol->policyid) { X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_NO_POLICY_IDENTIFIER); goto err; } return pol; merr: X509V3err(X509V3_F_POLICY_SECTION, ERR_R_MALLOC_FAILURE); err: POLICYINFO_free(pol); return NULL; } static int displaytext_get_tag_len(const char *tagstr) { char *colon = strchr(tagstr, ':'); return (colon == NULL) ? -1 : colon - tagstr; } static int displaytext_str2tag(const char *tagstr, unsigned int *tag_len) { int len; *tag_len = 0; len = displaytext_get_tag_len(tagstr); if (len == -1) return V_ASN1_VISIBLESTRING; *tag_len = len; if (len == sizeof("UTF8") - 1 && strncmp(tagstr, "UTF8", len) == 0) return V_ASN1_UTF8STRING; if (len == sizeof("UTF8String") - 1 && strncmp(tagstr, "UTF8String", len) == 0) return V_ASN1_UTF8STRING; if (len == sizeof("BMP") - 1 && strncmp(tagstr, "BMP", len) == 0) return V_ASN1_BMPSTRING; if (len == sizeof("BMPSTRING") - 1 && strncmp(tagstr, "BMPSTRING", len) == 0) return V_ASN1_BMPSTRING; if (len == sizeof("VISIBLE") - 1 && strncmp(tagstr, "VISIBLE", len) == 0) return V_ASN1_VISIBLESTRING; if (len == sizeof("VISIBLESTRING") - 1 && strncmp(tagstr, "VISIBLESTRING", len) == 0) return V_ASN1_VISIBLESTRING; *tag_len = 0; return V_ASN1_VISIBLESTRING; } static POLICYQUALINFO *notice_section(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *unot, int ia5org) { int i, ret, len, tag; unsigned int tag_len; CONF_VALUE *cnf; USERNOTICE *not; POLICYQUALINFO *qual; char *value = NULL; if ((qual = POLICYQUALINFO_new()) == NULL) goto merr; if ((qual->pqualid = OBJ_nid2obj(NID_id_qt_unotice)) == NULL) { X509V3err(X509V3_F_NOTICE_SECTION, ERR_R_INTERNAL_ERROR); goto err; } if ((not = USERNOTICE_new()) == NULL) goto merr; qual->d.usernotice = not; for (i = 0; i < sk_CONF_VALUE_num(unot); i++) { cnf = sk_CONF_VALUE_value(unot, i); value = cnf->value; if (strcmp(cnf->name, "explicitText") == 0) { tag = displaytext_str2tag(value, &tag_len); if ((not->exptext = ASN1_STRING_type_new(tag)) == NULL) goto merr; if (tag_len != 0) value += tag_len + 1; len = strlen(value); if (!ASN1_STRING_set(not->exptext, value, len)) goto merr; } else if (strcmp(cnf->name, "organization") == 0) { NOTICEREF *nref; if (!not->noticeref) { if ((nref = NOTICEREF_new()) == NULL) goto merr; not->noticeref = nref; } else nref = not->noticeref; if (ia5org) nref->organization->type = V_ASN1_IA5STRING; else nref->organization->type = V_ASN1_VISIBLESTRING; if (!ASN1_STRING_set(nref->organization, cnf->value, strlen(cnf->value))) goto merr; } else if (strcmp(cnf->name, "noticeNumbers") == 0) { NOTICEREF *nref; STACK_OF(CONF_VALUE) *nos; if (!not->noticeref) { if ((nref = NOTICEREF_new()) == NULL) goto merr; not->noticeref = nref; } else nref = not->noticeref; nos = X509V3_parse_list(cnf->value); if (!nos || !sk_CONF_VALUE_num(nos)) { X509V3err(X509V3_F_NOTICE_SECTION, X509V3_R_INVALID_NUMBERS); X509V3_conf_err(cnf); sk_CONF_VALUE_pop_free(nos, X509V3_conf_free); goto err; } ret = nref_nos(nref->noticenos, nos); sk_CONF_VALUE_pop_free(nos, X509V3_conf_free); if (!ret) goto err; } else { X509V3err(X509V3_F_NOTICE_SECTION, X509V3_R_INVALID_OPTION); X509V3_conf_err(cnf); goto err; } } if (not->noticeref && (!not->noticeref->noticenos || !not->noticeref->organization)) { X509V3err(X509V3_F_NOTICE_SECTION, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS); goto err; } return qual; merr: X509V3err(X509V3_F_NOTICE_SECTION, ERR_R_MALLOC_FAILURE); err: POLICYQUALINFO_free(qual); return NULL; } static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos) { CONF_VALUE *cnf; ASN1_INTEGER *aint; int i; for (i = 0; i < sk_CONF_VALUE_num(nos); i++) { cnf = sk_CONF_VALUE_value(nos, i); if ((aint = s2i_ASN1_INTEGER(NULL, cnf->name)) == NULL) { X509V3err(X509V3_F_NREF_NOS, X509V3_R_INVALID_NUMBER); goto err; } if (!sk_ASN1_INTEGER_push(nnums, aint)) goto merr; } return 1; merr: ASN1_INTEGER_free(aint); X509V3err(X509V3_F_NREF_NOS, ERR_R_MALLOC_FAILURE); err: return 0; } static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol, BIO *out, int indent) { int i; POLICYINFO *pinfo; /* First print out the policy OIDs */ for (i = 0; i < sk_POLICYINFO_num(pol); i++) { pinfo = sk_POLICYINFO_value(pol, i); BIO_printf(out, "%*sPolicy: ", indent, ""); i2a_ASN1_OBJECT(out, pinfo->policyid); BIO_puts(out, "\n"); if (pinfo->qualifiers) print_qualifiers(out, pinfo->qualifiers, indent + 2); } return 1; } static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, int indent) { POLICYQUALINFO *qualinfo; int i; for (i = 0; i < sk_POLICYQUALINFO_num(quals); i++) { qualinfo = sk_POLICYQUALINFO_value(quals, i); switch (OBJ_obj2nid(qualinfo->pqualid)) { case NID_id_qt_cps: - BIO_printf(out, "%*sCPS: %s\n", indent, "", + BIO_printf(out, "%*sCPS: %.*s\n", indent, "", + qualinfo->d.cpsuri->length, qualinfo->d.cpsuri->data); break; case NID_id_qt_unotice: BIO_printf(out, "%*sUser Notice:\n", indent, ""); print_notice(out, qualinfo->d.usernotice, indent + 2); break; default: BIO_printf(out, "%*sUnknown Qualifier: ", indent + 2, ""); i2a_ASN1_OBJECT(out, qualinfo->pqualid); BIO_puts(out, "\n"); break; } } } static void print_notice(BIO *out, USERNOTICE *notice, int indent) { int i; if (notice->noticeref) { NOTICEREF *ref; ref = notice->noticeref; - BIO_printf(out, "%*sOrganization: %s\n", indent, "", + BIO_printf(out, "%*sOrganization: %.*s\n", indent, "", + ref->organization->length, ref->organization->data); BIO_printf(out, "%*sNumber%s: ", indent, "", sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : ""); for (i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) { ASN1_INTEGER *num; char *tmp; num = sk_ASN1_INTEGER_value(ref->noticenos, i); if (i) BIO_puts(out, ", "); if (num == NULL) BIO_puts(out, "(null)"); else { tmp = i2s_ASN1_INTEGER(NULL, num); if (tmp == NULL) return; BIO_puts(out, tmp); OPENSSL_free(tmp); } } BIO_puts(out, "\n"); } if (notice->exptext) - BIO_printf(out, "%*sExplicit Text: %s\n", indent, "", + BIO_printf(out, "%*sExplicit Text: %.*s\n", indent, "", + notice->exptext->length, notice->exptext->data); } void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent) { const X509_POLICY_DATA *dat = node->data; BIO_printf(out, "%*sPolicy: ", indent, ""); i2a_ASN1_OBJECT(out, dat->valid_policy); BIO_puts(out, "\n"); BIO_printf(out, "%*s%s\n", indent + 2, "", node_data_critical(dat) ? "Critical" : "Non Critical"); if (dat->qualifier_set) print_qualifiers(out, dat->qualifier_set, indent + 2); else BIO_printf(out, "%*sNo Qualifiers\n", indent + 2, ""); } diff --git a/crypto/openssl/crypto/x509v3/v3_ncons.c b/crypto/openssl/crypto/x509v3/v3_ncons.c index 2a7b4f0992a8..cb701c4d844b 100644 --- a/crypto/openssl/crypto/x509v3/v3_ncons.c +++ b/crypto/openssl/crypto/x509v3/v3_ncons.c @@ -1,675 +1,702 @@ /* * Copyright 2003-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include "internal/cryptlib.h" #include "internal/numbers.h" #include #include "crypto/asn1.h" #include #include #include #include "crypto/x509.h" #include "ext_dat.h" static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a, BIO *bp, int ind); static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, STACK_OF(GENERAL_SUBTREE) *trees, BIO *bp, int ind, const char *name); static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip); static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc); static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen); static int nc_dn(X509_NAME *sub, X509_NAME *nm); static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns); static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml); static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base); static int nc_ip(ASN1_OCTET_STRING *ip, ASN1_OCTET_STRING *base); const X509V3_EXT_METHOD v3_name_constraints = { NID_name_constraints, 0, ASN1_ITEM_ref(NAME_CONSTRAINTS), 0, 0, 0, 0, 0, 0, 0, v2i_NAME_CONSTRAINTS, i2r_NAME_CONSTRAINTS, 0, NULL }; ASN1_SEQUENCE(GENERAL_SUBTREE) = { ASN1_SIMPLE(GENERAL_SUBTREE, base, GENERAL_NAME), ASN1_IMP_OPT(GENERAL_SUBTREE, minimum, ASN1_INTEGER, 0), ASN1_IMP_OPT(GENERAL_SUBTREE, maximum, ASN1_INTEGER, 1) } ASN1_SEQUENCE_END(GENERAL_SUBTREE) ASN1_SEQUENCE(NAME_CONSTRAINTS) = { ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, permittedSubtrees, GENERAL_SUBTREE, 0), ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, excludedSubtrees, GENERAL_SUBTREE, 1), } ASN1_SEQUENCE_END(NAME_CONSTRAINTS) IMPLEMENT_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE) IMPLEMENT_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS) + +#define IA5_OFFSET_LEN(ia5base, offset) \ + ((ia5base)->length - ((unsigned char *)(offset) - (ia5base)->data)) + +/* Like memchr but for ASN1_IA5STRING. Additionally you can specify the + * starting point to search from + */ +# define ia5memchr(str, start, c) memchr(start, c, IA5_OFFSET_LEN(str, start)) + +/* Like memrrchr but for ASN1_IA5STRING */ +static char *ia5memrchr(ASN1_IA5STRING *str, int c) +{ + int i; + + for (i = str->length; i > 0 && str->data[i - 1] != c; i--); + + if (i == 0) + return NULL; + + return (char *)&str->data[i - 1]; +} + /* - * We cannot use strncasecmp here because that applies locale specific rules. + * We cannot use strncasecmp here because that applies locale specific rules. It + * also doesn't work with ASN1_STRINGs that may have embedded NUL characters. * For example in Turkish 'I' is not the uppercase character for 'i'. We need to * do a simple ASCII case comparison ignoring the locale (that is why we use * numeric constants below). */ static int ia5ncasecmp(const char *s1, const char *s2, size_t n) { for (; n > 0; n--, s1++, s2++) { if (*s1 != *s2) { unsigned char c1 = (unsigned char)*s1, c2 = (unsigned char)*s2; /* Convert to lower case */ if (c1 >= 0x41 /* A */ && c1 <= 0x5A /* Z */) c1 += 0x20; if (c2 >= 0x41 /* A */ && c2 <= 0x5A /* Z */) c2 += 0x20; if (c1 == c2) continue; if (c1 < c2) return -1; /* c1 > c2 */ return 1; - } else if (*s1 == 0) { - /* If we get here we know that *s2 == 0 too */ - return 0; } } return 0; } -static int ia5casecmp(const char *s1, const char *s2) -{ - return ia5ncasecmp(s1, s2, SIZE_MAX); -} - static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) { int i; CONF_VALUE tval, *val; STACK_OF(GENERAL_SUBTREE) **ptree = NULL; NAME_CONSTRAINTS *ncons = NULL; GENERAL_SUBTREE *sub = NULL; ncons = NAME_CONSTRAINTS_new(); if (ncons == NULL) goto memerr; for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { val = sk_CONF_VALUE_value(nval, i); if (strncmp(val->name, "permitted", 9) == 0 && val->name[9]) { ptree = &ncons->permittedSubtrees; tval.name = val->name + 10; } else if (strncmp(val->name, "excluded", 8) == 0 && val->name[8]) { ptree = &ncons->excludedSubtrees; tval.name = val->name + 9; } else { X509V3err(X509V3_F_V2I_NAME_CONSTRAINTS, X509V3_R_INVALID_SYNTAX); goto err; } tval.value = val->value; sub = GENERAL_SUBTREE_new(); if (sub == NULL) goto memerr; if (!v2i_GENERAL_NAME_ex(sub->base, method, ctx, &tval, 1)) goto err; if (*ptree == NULL) *ptree = sk_GENERAL_SUBTREE_new_null(); if (*ptree == NULL || !sk_GENERAL_SUBTREE_push(*ptree, sub)) goto memerr; sub = NULL; } return ncons; memerr: X509V3err(X509V3_F_V2I_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE); err: NAME_CONSTRAINTS_free(ncons); GENERAL_SUBTREE_free(sub); return NULL; } static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a, BIO *bp, int ind) { NAME_CONSTRAINTS *ncons = a; do_i2r_name_constraints(method, ncons->permittedSubtrees, bp, ind, "Permitted"); do_i2r_name_constraints(method, ncons->excludedSubtrees, bp, ind, "Excluded"); return 1; } static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, STACK_OF(GENERAL_SUBTREE) *trees, BIO *bp, int ind, const char *name) { GENERAL_SUBTREE *tree; int i; if (sk_GENERAL_SUBTREE_num(trees) > 0) BIO_printf(bp, "%*s%s:\n", ind, "", name); for (i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++) { tree = sk_GENERAL_SUBTREE_value(trees, i); BIO_printf(bp, "%*s", ind + 2, ""); if (tree->base->type == GEN_IPADD) print_nc_ipadd(bp, tree->base->d.ip); else GENERAL_NAME_print(bp, tree->base); BIO_puts(bp, "\n"); } return 1; } static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip) { int i, len; unsigned char *p; p = ip->data; len = ip->length; BIO_puts(bp, "IP:"); if (len == 8) { BIO_printf(bp, "%d.%d.%d.%d/%d.%d.%d.%d", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); } else if (len == 32) { for (i = 0; i < 16; i++) { BIO_printf(bp, "%X", p[0] << 8 | p[1]); p += 2; if (i == 7) BIO_puts(bp, "/"); else if (i != 15) BIO_puts(bp, ":"); } } else BIO_printf(bp, "IP Address:"); return 1; } #define NAME_CHECK_MAX (1 << 20) static int add_lengths(int *out, int a, int b) { /* sk_FOO_num(NULL) returns -1 but is effectively 0 when iterating. */ if (a < 0) a = 0; if (b < 0) b = 0; if (a > INT_MAX - b) return 0; *out = a + b; return 1; } /*- * Check a certificate conforms to a specified set of constraints. * Return values: * X509_V_OK: All constraints obeyed. * X509_V_ERR_PERMITTED_VIOLATION: Permitted subtree violation. * X509_V_ERR_EXCLUDED_VIOLATION: Excluded subtree violation. * X509_V_ERR_SUBTREE_MINMAX: Min or max values present and matching type. * X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: Unsupported constraint type. * X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: bad unsupported constraint syntax. * X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: bad or unsupported syntax of name */ int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc) { int r, i, name_count, constraint_count; X509_NAME *nm; nm = X509_get_subject_name(x); /* * Guard against certificates with an excessive number of names or * constraints causing a computationally expensive name constraints check. */ if (!add_lengths(&name_count, X509_NAME_entry_count(nm), sk_GENERAL_NAME_num(x->altname)) || !add_lengths(&constraint_count, sk_GENERAL_SUBTREE_num(nc->permittedSubtrees), sk_GENERAL_SUBTREE_num(nc->excludedSubtrees)) || (name_count > 0 && constraint_count > NAME_CHECK_MAX / name_count)) return X509_V_ERR_UNSPECIFIED; if (X509_NAME_entry_count(nm) > 0) { GENERAL_NAME gntmp; gntmp.type = GEN_DIRNAME; gntmp.d.directoryName = nm; r = nc_match(&gntmp, nc); if (r != X509_V_OK) return r; gntmp.type = GEN_EMAIL; /* Process any email address attributes in subject name */ for (i = -1;;) { const X509_NAME_ENTRY *ne; i = X509_NAME_get_index_by_NID(nm, NID_pkcs9_emailAddress, i); if (i == -1) break; ne = X509_NAME_get_entry(nm, i); gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne); if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING) return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; r = nc_match(&gntmp, nc); if (r != X509_V_OK) return r; } } for (i = 0; i < sk_GENERAL_NAME_num(x->altname); i++) { GENERAL_NAME *gen = sk_GENERAL_NAME_value(x->altname, i); r = nc_match(gen, nc); if (r != X509_V_OK) return r; } return X509_V_OK; } static int cn2dnsid(ASN1_STRING *cn, unsigned char **dnsid, size_t *idlen) { int utf8_length; unsigned char *utf8_value; int i; int isdnsname = 0; /* Don't leave outputs uninitialized */ *dnsid = NULL; *idlen = 0; /*- * Per RFC 6125, DNS-IDs representing internationalized domain names appear * in certificates in A-label encoded form: * * https://tools.ietf.org/html/rfc6125#section-6.4.2 * * The same applies to CNs which are intended to represent DNS names. * However, while in the SAN DNS-IDs are IA5Strings, as CNs they may be * needlessly encoded in 16-bit Unicode. We perform a conversion to UTF-8 * to ensure that we get an ASCII representation of any CNs that are * representable as ASCII, but just not encoded as ASCII. The UTF-8 form * may contain some non-ASCII octets, and that's fine, such CNs are not * valid legacy DNS names. * * Note, 'int' is the return type of ASN1_STRING_to_UTF8() so that's what * we must use for 'utf8_length'. */ if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, cn)) < 0) return X509_V_ERR_OUT_OF_MEM; /* * Some certificates have had names that include a *trailing* NUL byte. * Remove these harmless NUL characters. They would otherwise yield false * alarms with the following embedded NUL check. */ while (utf8_length > 0 && utf8_value[utf8_length - 1] == '\0') --utf8_length; /* Reject *embedded* NULs */ - if ((size_t)utf8_length != strlen((char *)utf8_value)) { + if (memchr(utf8_value, 0, utf8_length) != NULL) { OPENSSL_free(utf8_value); return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; } /* * XXX: Deviation from strict DNS name syntax, also check names with '_' * Check DNS name syntax, any '-' or '.' must be internal, * and on either side of each '.' we can't have a '-' or '.'. * * If the name has just one label, we don't consider it a DNS name. This * means that "CN=sometld" cannot be precluded by DNS name constraints, but * that is not a problem. */ for (i = 0; i < utf8_length; ++i) { unsigned char c = utf8_value[i]; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') continue; /* Dot and hyphen cannot be first or last. */ if (i > 0 && i < utf8_length - 1) { if (c == '-') continue; /* * Next to a dot the preceding and following characters must not be * another dot or a hyphen. Otherwise, record that the name is * plausible, since it has two or more labels. */ if (c == '.' && utf8_value[i + 1] != '.' && utf8_value[i - 1] != '-' && utf8_value[i + 1] != '-') { isdnsname = 1; continue; } } isdnsname = 0; break; } if (isdnsname) { *dnsid = utf8_value; *idlen = (size_t)utf8_length; return X509_V_OK; } OPENSSL_free(utf8_value); return X509_V_OK; } /* * Check CN against DNS-ID name constraints. */ int NAME_CONSTRAINTS_check_CN(X509 *x, NAME_CONSTRAINTS *nc) { int r, i; X509_NAME *nm = X509_get_subject_name(x); ASN1_STRING stmp; GENERAL_NAME gntmp; stmp.flags = 0; stmp.type = V_ASN1_IA5STRING; gntmp.type = GEN_DNS; gntmp.d.dNSName = &stmp; /* Process any commonName attributes in subject name */ for (i = -1;;) { X509_NAME_ENTRY *ne; ASN1_STRING *cn; unsigned char *idval; size_t idlen; i = X509_NAME_get_index_by_NID(nm, NID_commonName, i); if (i == -1) break; ne = X509_NAME_get_entry(nm, i); cn = X509_NAME_ENTRY_get_data(ne); /* Only process attributes that look like host names */ if ((r = cn2dnsid(cn, &idval, &idlen)) != X509_V_OK) return r; if (idlen == 0) continue; stmp.length = idlen; stmp.data = idval; r = nc_match(&gntmp, nc); OPENSSL_free(idval); if (r != X509_V_OK) return r; } return X509_V_OK; } static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc) { GENERAL_SUBTREE *sub; int i, r, match = 0; /* * Permitted subtrees: if any subtrees exist of matching the type at * least one subtree must match. */ for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) { sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i); if (gen->type != sub->base->type) continue; if (sub->minimum || sub->maximum) return X509_V_ERR_SUBTREE_MINMAX; /* If we already have a match don't bother trying any more */ if (match == 2) continue; if (match == 0) match = 1; r = nc_match_single(gen, sub->base); if (r == X509_V_OK) match = 2; else if (r != X509_V_ERR_PERMITTED_VIOLATION) return r; } if (match == 1) return X509_V_ERR_PERMITTED_VIOLATION; /* Excluded subtrees: must not match any of these */ for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) { sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i); if (gen->type != sub->base->type) continue; if (sub->minimum || sub->maximum) return X509_V_ERR_SUBTREE_MINMAX; r = nc_match_single(gen, sub->base); if (r == X509_V_OK) return X509_V_ERR_EXCLUDED_VIOLATION; else if (r != X509_V_ERR_PERMITTED_VIOLATION) return r; } return X509_V_OK; } static int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base) { switch (base->type) { case GEN_DIRNAME: return nc_dn(gen->d.directoryName, base->d.directoryName); case GEN_DNS: return nc_dns(gen->d.dNSName, base->d.dNSName); case GEN_EMAIL: return nc_email(gen->d.rfc822Name, base->d.rfc822Name); case GEN_URI: return nc_uri(gen->d.uniformResourceIdentifier, base->d.uniformResourceIdentifier); case GEN_IPADD: return nc_ip(gen->d.iPAddress, base->d.iPAddress); default: return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE; } } /* * directoryName name constraint matching. The canonical encoding of * X509_NAME makes this comparison easy. It is matched if the subtree is a * subset of the name. */ static int nc_dn(X509_NAME *nm, X509_NAME *base) { /* Ensure canonical encodings are up to date. */ if (nm->modified && i2d_X509_NAME(nm, NULL) < 0) return X509_V_ERR_OUT_OF_MEM; if (base->modified && i2d_X509_NAME(base, NULL) < 0) return X509_V_ERR_OUT_OF_MEM; if (base->canon_enclen > nm->canon_enclen) return X509_V_ERR_PERMITTED_VIOLATION; if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen)) return X509_V_ERR_PERMITTED_VIOLATION; return X509_V_OK; } static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base) { char *baseptr = (char *)base->data; char *dnsptr = (char *)dns->data; + /* Empty matches everything */ - if (!*baseptr) + if (base->length == 0) return X509_V_OK; + + if (dns->length < base->length) + return X509_V_ERR_PERMITTED_VIOLATION; + /* * Otherwise can add zero or more components on the left so compare RHS * and if dns is longer and expect '.' as preceding character. */ if (dns->length > base->length) { dnsptr += dns->length - base->length; if (*baseptr != '.' && dnsptr[-1] != '.') return X509_V_ERR_PERMITTED_VIOLATION; } - if (ia5casecmp(baseptr, dnsptr)) + if (ia5ncasecmp(baseptr, dnsptr, base->length)) return X509_V_ERR_PERMITTED_VIOLATION; return X509_V_OK; } static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base) { const char *baseptr = (char *)base->data; const char *emlptr = (char *)eml->data; + const char *baseat = ia5memrchr(base, '@'); + const char *emlat = ia5memrchr(eml, '@'); + size_t basehostlen, emlhostlen; - const char *baseat = strchr(baseptr, '@'); - const char *emlat = strchr(emlptr, '@'); if (!emlat) return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; /* Special case: initial '.' is RHS match */ - if (!baseat && (*baseptr == '.')) { + if (!baseat && base->length > 0 && (*baseptr == '.')) { if (eml->length > base->length) { emlptr += eml->length - base->length; - if (ia5casecmp(baseptr, emlptr) == 0) + if (ia5ncasecmp(baseptr, emlptr, base->length) == 0) return X509_V_OK; } return X509_V_ERR_PERMITTED_VIOLATION; } /* If we have anything before '@' match local part */ if (baseat) { if (baseat != baseptr) { if ((baseat - baseptr) != (emlat - emlptr)) return X509_V_ERR_PERMITTED_VIOLATION; /* Case sensitive match of local part */ if (strncmp(baseptr, emlptr, emlat - emlptr)) return X509_V_ERR_PERMITTED_VIOLATION; } /* Position base after '@' */ baseptr = baseat + 1; } emlptr = emlat + 1; + basehostlen = IA5_OFFSET_LEN(base, baseptr); + emlhostlen = IA5_OFFSET_LEN(eml, emlptr); /* Just have hostname left to match: case insensitive */ - if (ia5casecmp(baseptr, emlptr)) + if (basehostlen != emlhostlen || ia5ncasecmp(baseptr, emlptr, emlhostlen)) return X509_V_ERR_PERMITTED_VIOLATION; return X509_V_OK; } static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base) { const char *baseptr = (char *)base->data; const char *hostptr = (char *)uri->data; - const char *p = strchr(hostptr, ':'); + const char *p = ia5memchr(uri, (char *)uri->data, ':'); int hostlen; + /* Check for foo:// and skip past it */ - if (!p || (p[1] != '/') || (p[2] != '/')) + if (p == NULL + || IA5_OFFSET_LEN(uri, p) < 3 + || p[1] != '/' + || p[2] != '/') return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; hostptr = p + 3; /* Determine length of hostname part of URI */ /* Look for a port indicator as end of hostname first */ - p = strchr(hostptr, ':'); + p = ia5memchr(uri, hostptr, ':'); /* Otherwise look for trailing slash */ - if (!p) - p = strchr(hostptr, '/'); + if (p == NULL) + p = ia5memchr(uri, hostptr, '/'); - if (!p) - hostlen = strlen(hostptr); + if (p == NULL) + hostlen = IA5_OFFSET_LEN(uri, hostptr); else hostlen = p - hostptr; if (hostlen == 0) return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; /* Special case: initial '.' is RHS match */ - if (*baseptr == '.') { + if (base->length > 0 && *baseptr == '.') { if (hostlen > base->length) { p = hostptr + hostlen - base->length; if (ia5ncasecmp(p, baseptr, base->length) == 0) return X509_V_OK; } return X509_V_ERR_PERMITTED_VIOLATION; } if ((base->length != (int)hostlen) || ia5ncasecmp(hostptr, baseptr, hostlen)) return X509_V_ERR_PERMITTED_VIOLATION; return X509_V_OK; } static int nc_ip(ASN1_OCTET_STRING *ip, ASN1_OCTET_STRING *base) { int hostlen, baselen, i; unsigned char *hostptr, *baseptr, *maskptr; hostptr = ip->data; hostlen = ip->length; baseptr = base->data; baselen = base->length; /* Invalid if not IPv4 or IPv6 */ if (!((hostlen == 4) || (hostlen == 16))) return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; if (!((baselen == 8) || (baselen == 32))) return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; /* Do not match IPv4 with IPv6 */ if (hostlen * 2 != baselen) return X509_V_ERR_PERMITTED_VIOLATION; maskptr = base->data + hostlen; /* Considering possible not aligned base ipAddress */ /* Not checking for wrong mask definition: i.e.: 255.0.255.0 */ for (i = 0; i < hostlen; i++) if ((hostptr[i] & maskptr[i]) != (baseptr[i] & maskptr[i])) return X509_V_ERR_PERMITTED_VIOLATION; return X509_V_OK; } diff --git a/crypto/openssl/crypto/x509v3/v3_pci.c b/crypto/openssl/crypto/x509v3/v3_pci.c index 3d124fa6d95d..98b6ef25e280 100644 --- a/crypto/openssl/crypto/x509v3/v3_pci.c +++ b/crypto/openssl/crypto/x509v3/v3_pci.c @@ -1,325 +1,326 @@ /* * Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ /* * This file is dual-licensed and is also available under the following * terms: * * Copyright (c) 2004 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * 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. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE 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. */ #include #include "internal/cryptlib.h" #include #include #include "ext_dat.h" static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext, BIO *out, int indent); static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str); const X509V3_EXT_METHOD v3_pci = { NID_proxyCertInfo, 0, ASN1_ITEM_ref(PROXY_CERT_INFO_EXTENSION), 0, 0, 0, 0, 0, 0, NULL, NULL, (X509V3_EXT_I2R)i2r_pci, (X509V3_EXT_R2I)r2i_pci, NULL, }; static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci, BIO *out, int indent) { BIO_printf(out, "%*sPath Length Constraint: ", indent, ""); if (pci->pcPathLengthConstraint) i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint); else BIO_printf(out, "infinite"); BIO_puts(out, "\n"); BIO_printf(out, "%*sPolicy Language: ", indent, ""); i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage); BIO_puts(out, "\n"); if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data) - BIO_printf(out, "%*sPolicy Text: %s\n", indent, "", + BIO_printf(out, "%*sPolicy Text: %.*s\n", indent, "", + pci->proxyPolicy->policy->length, pci->proxyPolicy->policy->data); return 1; } static int process_pci_value(CONF_VALUE *val, ASN1_OBJECT **language, ASN1_INTEGER **pathlen, ASN1_OCTET_STRING **policy) { int free_policy = 0; if (strcmp(val->name, "language") == 0) { if (*language) { X509V3err(X509V3_F_PROCESS_PCI_VALUE, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED); X509V3_conf_err(val); return 0; } if ((*language = OBJ_txt2obj(val->value, 0)) == NULL) { X509V3err(X509V3_F_PROCESS_PCI_VALUE, X509V3_R_INVALID_OBJECT_IDENTIFIER); X509V3_conf_err(val); return 0; } } else if (strcmp(val->name, "pathlen") == 0) { if (*pathlen) { X509V3err(X509V3_F_PROCESS_PCI_VALUE, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED); X509V3_conf_err(val); return 0; } if (!X509V3_get_value_int(val, pathlen)) { X509V3err(X509V3_F_PROCESS_PCI_VALUE, X509V3_R_POLICY_PATH_LENGTH); X509V3_conf_err(val); return 0; } } else if (strcmp(val->name, "policy") == 0) { unsigned char *tmp_data = NULL; long val_len; if (!*policy) { *policy = ASN1_OCTET_STRING_new(); if (*policy == NULL) { X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE); X509V3_conf_err(val); return 0; } free_policy = 1; } if (strncmp(val->value, "hex:", 4) == 0) { unsigned char *tmp_data2 = OPENSSL_hexstr2buf(val->value + 4, &val_len); if (!tmp_data2) { X509V3_conf_err(val); goto err; } tmp_data = OPENSSL_realloc((*policy)->data, (*policy)->length + val_len + 1); if (tmp_data) { (*policy)->data = tmp_data; memcpy(&(*policy)->data[(*policy)->length], tmp_data2, val_len); (*policy)->length += val_len; (*policy)->data[(*policy)->length] = '\0'; } else { OPENSSL_free(tmp_data2); /* * realloc failure implies the original data space is b0rked * too! */ OPENSSL_free((*policy)->data); (*policy)->data = NULL; (*policy)->length = 0; X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE); X509V3_conf_err(val); goto err; } OPENSSL_free(tmp_data2); } else if (strncmp(val->value, "file:", 5) == 0) { unsigned char buf[2048]; int n; BIO *b = BIO_new_file(val->value + 5, "r"); if (!b) { X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_BIO_LIB); X509V3_conf_err(val); goto err; } while ((n = BIO_read(b, buf, sizeof(buf))) > 0 || (n == 0 && BIO_should_retry(b))) { if (!n) continue; tmp_data = OPENSSL_realloc((*policy)->data, (*policy)->length + n + 1); if (!tmp_data) { OPENSSL_free((*policy)->data); (*policy)->data = NULL; (*policy)->length = 0; X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE); X509V3_conf_err(val); BIO_free_all(b); goto err; } (*policy)->data = tmp_data; memcpy(&(*policy)->data[(*policy)->length], buf, n); (*policy)->length += n; (*policy)->data[(*policy)->length] = '\0'; } BIO_free_all(b); if (n < 0) { X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_BIO_LIB); X509V3_conf_err(val); goto err; } } else if (strncmp(val->value, "text:", 5) == 0) { val_len = strlen(val->value + 5); tmp_data = OPENSSL_realloc((*policy)->data, (*policy)->length + val_len + 1); if (tmp_data) { (*policy)->data = tmp_data; memcpy(&(*policy)->data[(*policy)->length], val->value + 5, val_len); (*policy)->length += val_len; (*policy)->data[(*policy)->length] = '\0'; } else { /* * realloc failure implies the original data space is b0rked * too! */ OPENSSL_free((*policy)->data); (*policy)->data = NULL; (*policy)->length = 0; X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE); X509V3_conf_err(val); goto err; } } else { X509V3err(X509V3_F_PROCESS_PCI_VALUE, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG); X509V3_conf_err(val); goto err; } if (!tmp_data) { X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE); X509V3_conf_err(val); goto err; } } return 1; err: if (free_policy) { ASN1_OCTET_STRING_free(*policy); *policy = NULL; } return 0; } static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *value) { PROXY_CERT_INFO_EXTENSION *pci = NULL; STACK_OF(CONF_VALUE) *vals; ASN1_OBJECT *language = NULL; ASN1_INTEGER *pathlen = NULL; ASN1_OCTET_STRING *policy = NULL; int i, j; vals = X509V3_parse_list(value); for (i = 0; i < sk_CONF_VALUE_num(vals); i++) { CONF_VALUE *cnf = sk_CONF_VALUE_value(vals, i); if (!cnf->name || (*cnf->name != '@' && !cnf->value)) { X509V3err(X509V3_F_R2I_PCI, X509V3_R_INVALID_PROXY_POLICY_SETTING); X509V3_conf_err(cnf); goto err; } if (*cnf->name == '@') { STACK_OF(CONF_VALUE) *sect; int success_p = 1; sect = X509V3_get_section(ctx, cnf->name + 1); if (!sect) { X509V3err(X509V3_F_R2I_PCI, X509V3_R_INVALID_SECTION); X509V3_conf_err(cnf); goto err; } for (j = 0; success_p && j < sk_CONF_VALUE_num(sect); j++) { success_p = process_pci_value(sk_CONF_VALUE_value(sect, j), &language, &pathlen, &policy); } X509V3_section_free(ctx, sect); if (!success_p) goto err; } else { if (!process_pci_value(cnf, &language, &pathlen, &policy)) { X509V3_conf_err(cnf); goto err; } } } /* Language is mandatory */ if (!language) { X509V3err(X509V3_F_R2I_PCI, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED); goto err; } i = OBJ_obj2nid(language); if ((i == NID_Independent || i == NID_id_ppl_inheritAll) && policy) { X509V3err(X509V3_F_R2I_PCI, X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY); goto err; } pci = PROXY_CERT_INFO_EXTENSION_new(); if (pci == NULL) { X509V3err(X509V3_F_R2I_PCI, ERR_R_MALLOC_FAILURE); goto err; } pci->proxyPolicy->policyLanguage = language; language = NULL; pci->proxyPolicy->policy = policy; policy = NULL; pci->pcPathLengthConstraint = pathlen; pathlen = NULL; goto end; err: ASN1_OBJECT_free(language); ASN1_INTEGER_free(pathlen); pathlen = NULL; ASN1_OCTET_STRING_free(policy); policy = NULL; PROXY_CERT_INFO_EXTENSION_free(pci); pci = NULL; end: sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); return pci; } diff --git a/crypto/openssl/crypto/x509v3/v3_utl.c b/crypto/openssl/crypto/x509v3/v3_utl.c index 7281a7b917a8..706dd22ffaba 100644 --- a/crypto/openssl/crypto/x509v3/v3_utl.c +++ b/crypto/openssl/crypto/x509v3/v3_utl.c @@ -1,1239 +1,1270 @@ /* * Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ /* X509 v3 extension utilities */ #include "e_os.h" #include "internal/cryptlib.h" #include +#include #include "crypto/ctype.h" #include #include #include #include "crypto/x509.h" #include #include "ext_dat.h" static char *strip_spaces(char *name); static int sk_strcmp(const char *const *a, const char *const *b); static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, GENERAL_NAMES *gens); static void str_free(OPENSSL_STRING str); static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, const ASN1_IA5STRING *email); static int ipv4_from_asc(unsigned char *v4, const char *in); static int ipv6_from_asc(unsigned char *v6, const char *in); static int ipv6_cb(const char *elem, int len, void *usr); static int ipv6_hex(unsigned char *out, const char *in, int inlen); /* Add a CONF_VALUE name value pair to stack */ -int X509V3_add_value(const char *name, const char *value, - STACK_OF(CONF_VALUE) **extlist) +static int x509v3_add_len_value(const char *name, const char *value, + size_t vallen, STACK_OF(CONF_VALUE) **extlist) { CONF_VALUE *vtmp = NULL; char *tname = NULL, *tvalue = NULL; int sk_allocated = (*extlist == NULL); - if (name && (tname = OPENSSL_strdup(name)) == NULL) - goto err; - if (value && (tvalue = OPENSSL_strdup(value)) == NULL) + if (name != NULL && (tname = OPENSSL_strdup(name)) == NULL) goto err; + if (value != NULL) { + /* We don't allow embeded NUL characters */ + if (memchr(value, 0, vallen) != NULL) + goto err; + tvalue = OPENSSL_strndup(value, vallen); + if (tvalue == NULL) + goto err; + } if ((vtmp = OPENSSL_malloc(sizeof(*vtmp))) == NULL) goto err; if (sk_allocated && (*extlist = sk_CONF_VALUE_new_null()) == NULL) goto err; vtmp->section = NULL; vtmp->name = tname; vtmp->value = tvalue; if (!sk_CONF_VALUE_push(*extlist, vtmp)) goto err; return 1; err: X509V3err(X509V3_F_X509V3_ADD_VALUE, ERR_R_MALLOC_FAILURE); if (sk_allocated) { sk_CONF_VALUE_free(*extlist); *extlist = NULL; } OPENSSL_free(vtmp); OPENSSL_free(tname); OPENSSL_free(tvalue); return 0; } +int X509V3_add_value(const char *name, const char *value, + STACK_OF(CONF_VALUE) **extlist) +{ + return x509v3_add_len_value(name, value, + value != NULL ? strlen((const char *)value) : 0, + extlist); +} + int X509V3_add_value_uchar(const char *name, const unsigned char *value, STACK_OF(CONF_VALUE) **extlist) { - return X509V3_add_value(name, (const char *)value, extlist); + return x509v3_add_len_value(name, (const char *)value, + value != NULL ? strlen((const char *)value) : 0, + extlist); +} + +int x509v3_add_len_value_uchar(const char *name, const unsigned char *value, + size_t vallen, STACK_OF(CONF_VALUE) **extlist) +{ + return x509v3_add_len_value(name, (const char *)value, vallen, extlist); } /* Free function for STACK_OF(CONF_VALUE) */ void X509V3_conf_free(CONF_VALUE *conf) { if (!conf) return; OPENSSL_free(conf->name); OPENSSL_free(conf->value); OPENSSL_free(conf->section); OPENSSL_free(conf); } int X509V3_add_value_bool(const char *name, int asn1_bool, STACK_OF(CONF_VALUE) **extlist) { if (asn1_bool) return X509V3_add_value(name, "TRUE", extlist); return X509V3_add_value(name, "FALSE", extlist); } int X509V3_add_value_bool_nf(const char *name, int asn1_bool, STACK_OF(CONF_VALUE) **extlist) { if (asn1_bool) return X509V3_add_value(name, "TRUE", extlist); return 1; } static char *bignum_to_string(const BIGNUM *bn) { char *tmp, *ret; size_t len; /* * Display large numbers in hex and small numbers in decimal. Converting to * decimal takes quadratic time and is no more useful than hex for large * numbers. */ if (BN_num_bits(bn) < 128) return BN_bn2dec(bn); tmp = BN_bn2hex(bn); if (tmp == NULL) return NULL; len = strlen(tmp) + 3; ret = OPENSSL_malloc(len); if (ret == NULL) { X509V3err(X509V3_F_BIGNUM_TO_STRING, ERR_R_MALLOC_FAILURE); OPENSSL_free(tmp); return NULL; } /* Prepend "0x", but place it after the "-" if negative. */ if (tmp[0] == '-') { OPENSSL_strlcpy(ret, "-0x", len); OPENSSL_strlcat(ret, tmp + 1, len); } else { OPENSSL_strlcpy(ret, "0x", len); OPENSSL_strlcat(ret, tmp, len); } OPENSSL_free(tmp); return ret; } char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, const ASN1_ENUMERATED *a) { BIGNUM *bntmp = NULL; char *strtmp = NULL; if (!a) return NULL; if ((bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) == NULL || (strtmp = bignum_to_string(bntmp)) == NULL) X509V3err(X509V3_F_I2S_ASN1_ENUMERATED, ERR_R_MALLOC_FAILURE); BN_free(bntmp); return strtmp; } char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, const ASN1_INTEGER *a) { BIGNUM *bntmp = NULL; char *strtmp = NULL; if (!a) return NULL; if ((bntmp = ASN1_INTEGER_to_BN(a, NULL)) == NULL || (strtmp = bignum_to_string(bntmp)) == NULL) X509V3err(X509V3_F_I2S_ASN1_INTEGER, ERR_R_MALLOC_FAILURE); BN_free(bntmp); return strtmp; } ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, const char *value) { BIGNUM *bn = NULL; ASN1_INTEGER *aint; int isneg, ishex; int ret; if (value == NULL) { X509V3err(X509V3_F_S2I_ASN1_INTEGER, X509V3_R_INVALID_NULL_VALUE); return NULL; } bn = BN_new(); if (bn == NULL) { X509V3err(X509V3_F_S2I_ASN1_INTEGER, ERR_R_MALLOC_FAILURE); return NULL; } if (value[0] == '-') { value++; isneg = 1; } else isneg = 0; if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) { value += 2; ishex = 1; } else ishex = 0; if (ishex) ret = BN_hex2bn(&bn, value); else ret = BN_dec2bn(&bn, value); if (!ret || value[ret]) { BN_free(bn); X509V3err(X509V3_F_S2I_ASN1_INTEGER, X509V3_R_BN_DEC2BN_ERROR); return NULL; } if (isneg && BN_is_zero(bn)) isneg = 0; aint = BN_to_ASN1_INTEGER(bn, NULL); BN_free(bn); if (!aint) { X509V3err(X509V3_F_S2I_ASN1_INTEGER, X509V3_R_BN_TO_ASN1_INTEGER_ERROR); return NULL; } if (isneg) aint->type |= V_ASN1_NEG; return aint; } int X509V3_add_value_int(const char *name, const ASN1_INTEGER *aint, STACK_OF(CONF_VALUE) **extlist) { char *strtmp; int ret; if (!aint) return 1; if ((strtmp = i2s_ASN1_INTEGER(NULL, aint)) == NULL) return 0; ret = X509V3_add_value(name, strtmp, extlist); OPENSSL_free(strtmp); return ret; } int X509V3_get_value_bool(const CONF_VALUE *value, int *asn1_bool) { const char *btmp; if ((btmp = value->value) == NULL) goto err; if (strcmp(btmp, "TRUE") == 0 || strcmp(btmp, "true") == 0 || strcmp(btmp, "Y") == 0 || strcmp(btmp, "y") == 0 || strcmp(btmp, "YES") == 0 || strcmp(btmp, "yes") == 0) { *asn1_bool = 0xff; return 1; } if (strcmp(btmp, "FALSE") == 0 || strcmp(btmp, "false") == 0 || strcmp(btmp, "N") == 0 || strcmp(btmp, "n") == 0 || strcmp(btmp, "NO") == 0 || strcmp(btmp, "no") == 0) { *asn1_bool = 0; return 1; } err: X509V3err(X509V3_F_X509V3_GET_VALUE_BOOL, X509V3_R_INVALID_BOOLEAN_STRING); X509V3_conf_err(value); return 0; } int X509V3_get_value_int(const CONF_VALUE *value, ASN1_INTEGER **aint) { ASN1_INTEGER *itmp; if ((itmp = s2i_ASN1_INTEGER(NULL, value->value)) == NULL) { X509V3_conf_err(value); return 0; } *aint = itmp; return 1; } #define HDR_NAME 1 #define HDR_VALUE 2 /* * #define DEBUG */ STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line) { char *p, *q, c; char *ntmp, *vtmp; STACK_OF(CONF_VALUE) *values = NULL; char *linebuf; int state; /* We are going to modify the line so copy it first */ linebuf = OPENSSL_strdup(line); if (linebuf == NULL) { X509V3err(X509V3_F_X509V3_PARSE_LIST, ERR_R_MALLOC_FAILURE); goto err; } state = HDR_NAME; ntmp = NULL; /* Go through all characters */ for (p = linebuf, q = linebuf; (c = *p) && (c != '\r') && (c != '\n'); p++) { switch (state) { case HDR_NAME: if (c == ':') { state = HDR_VALUE; *p = 0; ntmp = strip_spaces(q); if (!ntmp) { X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME); goto err; } q = p + 1; } else if (c == ',') { *p = 0; ntmp = strip_spaces(q); q = p + 1; if (!ntmp) { X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME); goto err; } X509V3_add_value(ntmp, NULL, &values); } break; case HDR_VALUE: if (c == ',') { state = HDR_NAME; *p = 0; vtmp = strip_spaces(q); if (!vtmp) { X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_VALUE); goto err; } X509V3_add_value(ntmp, vtmp, &values); ntmp = NULL; q = p + 1; } } } if (state == HDR_VALUE) { vtmp = strip_spaces(q); if (!vtmp) { X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_VALUE); goto err; } X509V3_add_value(ntmp, vtmp, &values); } else { ntmp = strip_spaces(q); if (!ntmp) { X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME); goto err; } X509V3_add_value(ntmp, NULL, &values); } OPENSSL_free(linebuf); return values; err: OPENSSL_free(linebuf); sk_CONF_VALUE_pop_free(values, X509V3_conf_free); return NULL; } /* Delete leading and trailing spaces from a string */ static char *strip_spaces(char *name) { char *p, *q; /* Skip over leading spaces */ p = name; while (*p && ossl_isspace(*p)) p++; if (!*p) return NULL; q = p + strlen(p) - 1; while ((q != p) && ossl_isspace(*q)) q--; if (p != q) q[1] = 0; if (!*p) return NULL; return p; } /* * V2I name comparison function: returns zero if 'name' matches cmp or cmp.* */ int name_cmp(const char *name, const char *cmp) { int len, ret; char c; len = strlen(cmp); if ((ret = strncmp(name, cmp, len))) return ret; c = name[len]; if (!c || (c == '.')) return 0; return 1; } static int sk_strcmp(const char *const *a, const char *const *b) { return strcmp(*a, *b); } STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x) { GENERAL_NAMES *gens; STACK_OF(OPENSSL_STRING) *ret; gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); ret = get_email(X509_get_subject_name(x), gens); sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); return ret; } STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x) { AUTHORITY_INFO_ACCESS *info; STACK_OF(OPENSSL_STRING) *ret = NULL; int i; info = X509_get_ext_d2i(x, NID_info_access, NULL, NULL); if (!info) return NULL; for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) { ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i); if (OBJ_obj2nid(ad->method) == NID_ad_OCSP) { if (ad->location->type == GEN_URI) { if (!append_ia5 (&ret, ad->location->d.uniformResourceIdentifier)) break; } } } AUTHORITY_INFO_ACCESS_free(info); return ret; } STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x) { GENERAL_NAMES *gens; STACK_OF(X509_EXTENSION) *exts; STACK_OF(OPENSSL_STRING) *ret; exts = X509_REQ_get_extensions(x); gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL); ret = get_email(X509_REQ_get_subject_name(x), gens); sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); return ret; } static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, GENERAL_NAMES *gens) { STACK_OF(OPENSSL_STRING) *ret = NULL; X509_NAME_ENTRY *ne; const ASN1_IA5STRING *email; GENERAL_NAME *gen; int i = -1; /* Now add any email address(es) to STACK */ /* First supplied X509_NAME */ while ((i = X509_NAME_get_index_by_NID(name, NID_pkcs9_emailAddress, i)) >= 0) { ne = X509_NAME_get_entry(name, i); email = X509_NAME_ENTRY_get_data(ne); if (!append_ia5(&ret, email)) return NULL; } for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { gen = sk_GENERAL_NAME_value(gens, i); if (gen->type != GEN_EMAIL) continue; if (!append_ia5(&ret, gen->d.ia5)) return NULL; } return ret; } static void str_free(OPENSSL_STRING str) { OPENSSL_free(str); } static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, const ASN1_IA5STRING *email) { char *emtmp; /* First some sanity checks */ if (email->type != V_ASN1_IA5STRING) return 1; - if (!email->data || !email->length) + if (email->data == NULL || email->length == 0) + return 1; + if (memchr(email->data, 0, email->length) != NULL) return 1; if (*sk == NULL) *sk = sk_OPENSSL_STRING_new(sk_strcmp); if (*sk == NULL) return 0; + + emtmp = OPENSSL_strndup((char *)email->data, email->length); + if (emtmp == NULL) + return 0; + /* Don't add duplicates */ - if (sk_OPENSSL_STRING_find(*sk, (char *)email->data) != -1) + if (sk_OPENSSL_STRING_find(*sk, emtmp) != -1) { + OPENSSL_free(emtmp); return 1; - emtmp = OPENSSL_strdup((char *)email->data); - if (emtmp == NULL || !sk_OPENSSL_STRING_push(*sk, emtmp)) { - OPENSSL_free(emtmp); /* free on push failure */ + } + if (!sk_OPENSSL_STRING_push(*sk, emtmp)) { + OPENSSL_free(emtmp); /* free on push failure */ X509_email_free(*sk); *sk = NULL; return 0; } return 1; } void X509_email_free(STACK_OF(OPENSSL_STRING) *sk) { sk_OPENSSL_STRING_pop_free(sk, str_free); } typedef int (*equal_fn) (const unsigned char *pattern, size_t pattern_len, const unsigned char *subject, size_t subject_len, unsigned int flags); /* Skip pattern prefix to match "wildcard" subject */ static void skip_prefix(const unsigned char **p, size_t *plen, size_t subject_len, unsigned int flags) { const unsigned char *pattern = *p; size_t pattern_len = *plen; /* * If subject starts with a leading '.' followed by more octets, and * pattern is longer, compare just an equal-length suffix with the * full subject (starting at the '.'), provided the prefix contains * no NULs. */ if ((flags & _X509_CHECK_FLAG_DOT_SUBDOMAINS) == 0) return; while (pattern_len > subject_len && *pattern) { if ((flags & X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS) && *pattern == '.') break; ++pattern; --pattern_len; } /* Skip if entire prefix acceptable */ if (pattern_len == subject_len) { *p = pattern; *plen = pattern_len; } } /* Compare while ASCII ignoring case. */ static int equal_nocase(const unsigned char *pattern, size_t pattern_len, const unsigned char *subject, size_t subject_len, unsigned int flags) { skip_prefix(&pattern, &pattern_len, subject_len, flags); if (pattern_len != subject_len) return 0; while (pattern_len) { unsigned char l = *pattern; unsigned char r = *subject; /* The pattern must not contain NUL characters. */ if (l == 0) return 0; if (l != r) { if ('A' <= l && l <= 'Z') l = (l - 'A') + 'a'; if ('A' <= r && r <= 'Z') r = (r - 'A') + 'a'; if (l != r) return 0; } ++pattern; ++subject; --pattern_len; } return 1; } /* Compare using memcmp. */ static int equal_case(const unsigned char *pattern, size_t pattern_len, const unsigned char *subject, size_t subject_len, unsigned int flags) { skip_prefix(&pattern, &pattern_len, subject_len, flags); if (pattern_len != subject_len) return 0; return !memcmp(pattern, subject, pattern_len); } /* * RFC 5280, section 7.5, requires that only the domain is compared in a * case-insensitive manner. */ static int equal_email(const unsigned char *a, size_t a_len, const unsigned char *b, size_t b_len, unsigned int unused_flags) { size_t i = a_len; if (a_len != b_len) return 0; /* * We search backwards for the '@' character, so that we do not have to * deal with quoted local-parts. The domain part is compared in a * case-insensitive manner. */ while (i > 0) { --i; if (a[i] == '@' || b[i] == '@') { if (!equal_nocase(a + i, a_len - i, b + i, a_len - i, 0)) return 0; break; } } if (i == 0) i = a_len; return equal_case(a, i, b, i, 0); } /* * Compare the prefix and suffix with the subject, and check that the * characters in-between are valid. */ static int wildcard_match(const unsigned char *prefix, size_t prefix_len, const unsigned char *suffix, size_t suffix_len, const unsigned char *subject, size_t subject_len, unsigned int flags) { const unsigned char *wildcard_start; const unsigned char *wildcard_end; const unsigned char *p; int allow_multi = 0; int allow_idna = 0; if (subject_len < prefix_len + suffix_len) return 0; if (!equal_nocase(prefix, prefix_len, subject, prefix_len, flags)) return 0; wildcard_start = subject + prefix_len; wildcard_end = subject + (subject_len - suffix_len); if (!equal_nocase(wildcard_end, suffix_len, suffix, suffix_len, flags)) return 0; /* * If the wildcard makes up the entire first label, it must match at * least one character. */ if (prefix_len == 0 && *suffix == '.') { if (wildcard_start == wildcard_end) return 0; allow_idna = 1; if (flags & X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS) allow_multi = 1; } /* IDNA labels cannot match partial wildcards */ if (!allow_idna && subject_len >= 4 && strncasecmp((char *)subject, "xn--", 4) == 0) return 0; /* The wildcard may match a literal '*' */ if (wildcard_end == wildcard_start + 1 && *wildcard_start == '*') return 1; /* * Check that the part matched by the wildcard contains only * permitted characters and only matches a single label unless * allow_multi is set. */ for (p = wildcard_start; p != wildcard_end; ++p) if (!(('0' <= *p && *p <= '9') || ('A' <= *p && *p <= 'Z') || ('a' <= *p && *p <= 'z') || *p == '-' || (allow_multi && *p == '.'))) return 0; return 1; } #define LABEL_START (1 << 0) #define LABEL_END (1 << 1) #define LABEL_HYPHEN (1 << 2) #define LABEL_IDNA (1 << 3) static const unsigned char *valid_star(const unsigned char *p, size_t len, unsigned int flags) { const unsigned char *star = 0; size_t i; int state = LABEL_START; int dots = 0; for (i = 0; i < len; ++i) { /* * Locate first and only legal wildcard, either at the start * or end of a non-IDNA first and not final label. */ if (p[i] == '*') { int atstart = (state & LABEL_START); int atend = (i == len - 1 || p[i + 1] == '.'); /*- * At most one wildcard per pattern. * No wildcards in IDNA labels. * No wildcards after the first label. */ if (star != NULL || (state & LABEL_IDNA) != 0 || dots) return NULL; /* Only full-label '*.example.com' wildcards? */ if ((flags & X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS) && (!atstart || !atend)) return NULL; /* No 'foo*bar' wildcards */ if (!atstart && !atend) return NULL; star = &p[i]; state &= ~LABEL_START; } else if (('a' <= p[i] && p[i] <= 'z') || ('A' <= p[i] && p[i] <= 'Z') || ('0' <= p[i] && p[i] <= '9')) { if ((state & LABEL_START) != 0 && len - i >= 4 && strncasecmp((char *)&p[i], "xn--", 4) == 0) state |= LABEL_IDNA; state &= ~(LABEL_HYPHEN | LABEL_START); } else if (p[i] == '.') { if ((state & (LABEL_HYPHEN | LABEL_START)) != 0) return NULL; state = LABEL_START; ++dots; } else if (p[i] == '-') { /* no domain/subdomain starts with '-' */ if ((state & LABEL_START) != 0) return NULL; state |= LABEL_HYPHEN; } else return NULL; } /* * The final label must not end in a hyphen or ".", and * there must be at least two dots after the star. */ if ((state & (LABEL_START | LABEL_HYPHEN)) != 0 || dots < 2) return NULL; return star; } /* Compare using wildcards. */ static int equal_wildcard(const unsigned char *pattern, size_t pattern_len, const unsigned char *subject, size_t subject_len, unsigned int flags) { const unsigned char *star = NULL; /* * Subject names starting with '.' can only match a wildcard pattern * via a subject sub-domain pattern suffix match. */ if (!(subject_len > 1 && subject[0] == '.')) star = valid_star(pattern, pattern_len, flags); if (star == NULL) return equal_nocase(pattern, pattern_len, subject, subject_len, flags); return wildcard_match(pattern, star - pattern, star + 1, (pattern + pattern_len) - star - 1, subject, subject_len, flags); } /* * Compare an ASN1_STRING to a supplied string. If they match return 1. If * cmp_type > 0 only compare if string matches the type, otherwise convert it * to UTF8. */ static int do_check_string(const ASN1_STRING *a, int cmp_type, equal_fn equal, unsigned int flags, const char *b, size_t blen, char **peername) { int rv = 0; if (!a->data || !a->length) return 0; if (cmp_type > 0) { if (cmp_type != a->type) return 0; if (cmp_type == V_ASN1_IA5STRING) rv = equal(a->data, a->length, (unsigned char *)b, blen, flags); else if (a->length == (int)blen && !memcmp(a->data, b, blen)) rv = 1; if (rv > 0 && peername) *peername = OPENSSL_strndup((char *)a->data, a->length); } else { int astrlen; unsigned char *astr; astrlen = ASN1_STRING_to_UTF8(&astr, a); if (astrlen < 0) { /* * -1 could be an internal malloc failure or a decoding error from * malformed input; we can't distinguish. */ return -1; } rv = equal(astr, astrlen, (unsigned char *)b, blen, flags); if (rv > 0 && peername) *peername = OPENSSL_strndup((char *)astr, astrlen); OPENSSL_free(astr); } return rv; } static int do_x509_check(X509 *x, const char *chk, size_t chklen, unsigned int flags, int check_type, char **peername) { GENERAL_NAMES *gens = NULL; X509_NAME *name = NULL; int i; int cnid = NID_undef; int alt_type; int san_present = 0; int rv = 0; equal_fn equal; /* See below, this flag is internal-only */ flags &= ~_X509_CHECK_FLAG_DOT_SUBDOMAINS; if (check_type == GEN_EMAIL) { cnid = NID_pkcs9_emailAddress; alt_type = V_ASN1_IA5STRING; equal = equal_email; } else if (check_type == GEN_DNS) { cnid = NID_commonName; /* Implicit client-side DNS sub-domain pattern */ if (chklen > 1 && chk[0] == '.') flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS; alt_type = V_ASN1_IA5STRING; if (flags & X509_CHECK_FLAG_NO_WILDCARDS) equal = equal_nocase; else equal = equal_wildcard; } else { alt_type = V_ASN1_OCTET_STRING; equal = equal_case; } if (chklen == 0) chklen = strlen(chk); gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); if (gens) { for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { GENERAL_NAME *gen; ASN1_STRING *cstr; gen = sk_GENERAL_NAME_value(gens, i); if (gen->type != check_type) continue; san_present = 1; if (check_type == GEN_EMAIL) cstr = gen->d.rfc822Name; else if (check_type == GEN_DNS) cstr = gen->d.dNSName; else cstr = gen->d.iPAddress; /* Positive on success, negative on error! */ if ((rv = do_check_string(cstr, alt_type, equal, flags, chk, chklen, peername)) != 0) break; } GENERAL_NAMES_free(gens); if (rv != 0) return rv; if (san_present && !(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT)) return 0; } /* We're done if CN-ID is not pertinent */ if (cnid == NID_undef || (flags & X509_CHECK_FLAG_NEVER_CHECK_SUBJECT)) return 0; i = -1; name = X509_get_subject_name(x); while ((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0) { const X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i); const ASN1_STRING *str = X509_NAME_ENTRY_get_data(ne); /* Positive on success, negative on error! */ if ((rv = do_check_string(str, -1, equal, flags, chk, chklen, peername)) != 0) return rv; } return 0; } int X509_check_host(X509 *x, const char *chk, size_t chklen, unsigned int flags, char **peername) { if (chk == NULL) return -2; /* * Embedded NULs are disallowed, except as the last character of a * string of length 2 or more (tolerate caller including terminating * NUL in string length). */ if (chklen == 0) chklen = strlen(chk); else if (memchr(chk, '\0', chklen > 1 ? chklen - 1 : chklen)) return -2; if (chklen > 1 && chk[chklen - 1] == '\0') --chklen; return do_x509_check(x, chk, chklen, flags, GEN_DNS, peername); } int X509_check_email(X509 *x, const char *chk, size_t chklen, unsigned int flags) { if (chk == NULL) return -2; /* * Embedded NULs are disallowed, except as the last character of a * string of length 2 or more (tolerate caller including terminating * NUL in string length). */ if (chklen == 0) chklen = strlen((char *)chk); else if (memchr(chk, '\0', chklen > 1 ? chklen - 1 : chklen)) return -2; if (chklen > 1 && chk[chklen - 1] == '\0') --chklen; return do_x509_check(x, chk, chklen, flags, GEN_EMAIL, NULL); } int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen, unsigned int flags) { if (chk == NULL) return -2; return do_x509_check(x, (char *)chk, chklen, flags, GEN_IPADD, NULL); } int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags) { unsigned char ipout[16]; size_t iplen; if (ipasc == NULL) return -2; iplen = (size_t)a2i_ipadd(ipout, ipasc); if (iplen == 0) return -2; return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, NULL); } /* * Convert IP addresses both IPv4 and IPv6 into an OCTET STRING compatible * with RFC3280. */ ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc) { unsigned char ipout[16]; ASN1_OCTET_STRING *ret; int iplen; /* If string contains a ':' assume IPv6 */ iplen = a2i_ipadd(ipout, ipasc); if (!iplen) return NULL; ret = ASN1_OCTET_STRING_new(); if (ret == NULL) return NULL; if (!ASN1_OCTET_STRING_set(ret, ipout, iplen)) { ASN1_OCTET_STRING_free(ret); return NULL; } return ret; } ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc) { ASN1_OCTET_STRING *ret = NULL; unsigned char ipout[32]; char *iptmp = NULL, *p; int iplen1, iplen2; p = strchr(ipasc, '/'); if (!p) return NULL; iptmp = OPENSSL_strdup(ipasc); if (!iptmp) return NULL; p = iptmp + (p - ipasc); *p++ = 0; iplen1 = a2i_ipadd(ipout, iptmp); if (!iplen1) goto err; iplen2 = a2i_ipadd(ipout + iplen1, p); OPENSSL_free(iptmp); iptmp = NULL; if (!iplen2 || (iplen1 != iplen2)) goto err; ret = ASN1_OCTET_STRING_new(); if (ret == NULL) goto err; if (!ASN1_OCTET_STRING_set(ret, ipout, iplen1 + iplen2)) goto err; return ret; err: OPENSSL_free(iptmp); ASN1_OCTET_STRING_free(ret); return NULL; } int a2i_ipadd(unsigned char *ipout, const char *ipasc) { /* If string contains a ':' assume IPv6 */ if (strchr(ipasc, ':')) { if (!ipv6_from_asc(ipout, ipasc)) return 0; return 16; } else { if (!ipv4_from_asc(ipout, ipasc)) return 0; return 4; } } static int ipv4_from_asc(unsigned char *v4, const char *in) { int a0, a1, a2, a3; if (sscanf(in, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) != 4) return 0; if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255) || (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255)) return 0; v4[0] = a0; v4[1] = a1; v4[2] = a2; v4[3] = a3; return 1; } typedef struct { /* Temporary store for IPV6 output */ unsigned char tmp[16]; /* Total number of bytes in tmp */ int total; /* The position of a zero (corresponding to '::') */ int zero_pos; /* Number of zeroes */ int zero_cnt; } IPV6_STAT; static int ipv6_from_asc(unsigned char *v6, const char *in) { IPV6_STAT v6stat; v6stat.total = 0; v6stat.zero_pos = -1; v6stat.zero_cnt = 0; /* * Treat the IPv6 representation as a list of values separated by ':'. * The presence of a '::' will parse as one, two or three zero length * elements. */ if (!CONF_parse_list(in, ':', 0, ipv6_cb, &v6stat)) return 0; /* Now for some sanity checks */ if (v6stat.zero_pos == -1) { /* If no '::' must have exactly 16 bytes */ if (v6stat.total != 16) return 0; } else { /* If '::' must have less than 16 bytes */ if (v6stat.total == 16) return 0; /* More than three zeroes is an error */ if (v6stat.zero_cnt > 3) return 0; /* Can only have three zeroes if nothing else present */ else if (v6stat.zero_cnt == 3) { if (v6stat.total > 0) return 0; } /* Can only have two zeroes if at start or end */ else if (v6stat.zero_cnt == 2) { if ((v6stat.zero_pos != 0) && (v6stat.zero_pos != v6stat.total)) return 0; } else /* Can only have one zero if *not* start or end */ { if ((v6stat.zero_pos == 0) || (v6stat.zero_pos == v6stat.total)) return 0; } } /* Format result */ if (v6stat.zero_pos >= 0) { /* Copy initial part */ memcpy(v6, v6stat.tmp, v6stat.zero_pos); /* Zero middle */ memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total); /* Copy final part */ if (v6stat.total != v6stat.zero_pos) memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total, v6stat.tmp + v6stat.zero_pos, v6stat.total - v6stat.zero_pos); } else memcpy(v6, v6stat.tmp, 16); return 1; } static int ipv6_cb(const char *elem, int len, void *usr) { IPV6_STAT *s = usr; /* Error if 16 bytes written */ if (s->total == 16) return 0; if (len == 0) { /* Zero length element, corresponds to '::' */ if (s->zero_pos == -1) s->zero_pos = s->total; /* If we've already got a :: its an error */ else if (s->zero_pos != s->total) return 0; s->zero_cnt++; } else { /* If more than 4 characters could be final a.b.c.d form */ if (len > 4) { /* Need at least 4 bytes left */ if (s->total > 12) return 0; /* Must be end of string */ if (elem[len]) return 0; if (!ipv4_from_asc(s->tmp + s->total, elem)) return 0; s->total += 4; } else { if (!ipv6_hex(s->tmp + s->total, elem, len)) return 0; s->total += 2; } } return 1; } /* * Convert a string of up to 4 hex digits into the corresponding IPv6 form. */ static int ipv6_hex(unsigned char *out, const char *in, int inlen) { unsigned char c; unsigned int num = 0; int x; if (inlen > 4) return 0; while (inlen--) { c = *in++; num <<= 4; x = OPENSSL_hexchar2int(c); if (x < 0) return 0; num |= (char)x; } out[0] = num >> 8; out[1] = num & 0xff; return 1; } int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE) *dn_sk, unsigned long chtype) { CONF_VALUE *v; int i, mval, spec_char, plus_char; char *p, *type; if (!nm) return 0; for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) { v = sk_CONF_VALUE_value(dn_sk, i); type = v->name; /* * Skip past any leading X. X: X, etc to allow for multiple instances */ for (p = type; *p; p++) { #ifndef CHARSET_EBCDIC spec_char = ((*p == ':') || (*p == ',') || (*p == '.')); #else spec_char = ((*p == os_toascii[':']) || (*p == os_toascii[',']) || (*p == os_toascii['.'])); #endif if (spec_char) { p++; if (*p) type = p; break; } } #ifndef CHARSET_EBCDIC plus_char = (*type == '+'); #else plus_char = (*type == os_toascii['+']); #endif if (plus_char) { mval = -1; type++; } else mval = 0; if (!X509_NAME_add_entry_by_txt(nm, type, chtype, (unsigned char *)v->value, -1, -1, mval)) return 0; } return 1; } diff --git a/crypto/openssl/include/crypto/sm2.h b/crypto/openssl/include/crypto/sm2.h index 76ee80baff19..50851a83cea2 100644 --- a/crypto/openssl/include/crypto/sm2.h +++ b/crypto/openssl/include/crypto/sm2.h @@ -1,78 +1,77 @@ /* * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2017 Ribose Inc. All Rights Reserved. * Ported from Ribose contributions from Botan. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #ifndef OSSL_CRYPTO_SM2_H # define OSSL_CRYPTO_SM2_H # include # ifndef OPENSSL_NO_SM2 # include /* The default user id as specified in GM/T 0009-2012 */ # define SM2_DEFAULT_USERID "1234567812345678" int sm2_compute_z_digest(uint8_t *out, const EVP_MD *digest, const uint8_t *id, const size_t id_len, const EC_KEY *key); /* * SM2 signature operation. Computes Z and then signs H(Z || msg) using SM2 */ ECDSA_SIG *sm2_do_sign(const EC_KEY *key, const EVP_MD *digest, const uint8_t *id, const size_t id_len, const uint8_t *msg, size_t msg_len); int sm2_do_verify(const EC_KEY *key, const EVP_MD *digest, const ECDSA_SIG *signature, const uint8_t *id, const size_t id_len, const uint8_t *msg, size_t msg_len); /* * SM2 signature generation. */ int sm2_sign(const unsigned char *dgst, int dgstlen, unsigned char *sig, unsigned int *siglen, EC_KEY *eckey); /* * SM2 signature verification. */ int sm2_verify(const unsigned char *dgst, int dgstlen, const unsigned char *sig, int siglen, EC_KEY *eckey); /* * SM2 encryption */ int sm2_ciphertext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len, size_t *ct_size); -int sm2_plaintext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len, - size_t *pt_size); +int sm2_plaintext_size(const unsigned char *ct, size_t ct_size, size_t *pt_size); int sm2_encrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *msg, size_t msg_len, uint8_t *ciphertext_buf, size_t *ciphertext_len); int sm2_decrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *ptext_buf, size_t *ptext_len); # endif /* OPENSSL_NO_SM2 */ #endif diff --git a/crypto/openssl/include/crypto/x509.h b/crypto/openssl/include/crypto/x509.h index b53c2b03c39e..7ffb8abfe71b 100644 --- a/crypto/openssl/include/crypto/x509.h +++ b/crypto/openssl/include/crypto/x509.h @@ -1,286 +1,291 @@ /* * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include "internal/refcount.h" +#include +#include /* Internal X509 structures and functions: not for application use */ /* Note: unless otherwise stated a field pointer is mandatory and should * never be set to NULL: the ASN.1 code and accessors rely on mandatory * fields never being NULL. */ /* * name entry structure, equivalent to AttributeTypeAndValue defined * in RFC5280 et al. */ struct X509_name_entry_st { ASN1_OBJECT *object; /* AttributeType */ ASN1_STRING *value; /* AttributeValue */ int set; /* index of RDNSequence for this entry */ int size; /* temp variable */ }; /* Name from RFC 5280. */ struct X509_name_st { STACK_OF(X509_NAME_ENTRY) *entries; /* DN components */ int modified; /* true if 'bytes' needs to be built */ BUF_MEM *bytes; /* cached encoding: cannot be NULL */ /* canonical encoding used for rapid Name comparison */ unsigned char *canon_enc; int canon_enclen; } /* X509_NAME */ ; /* Signature info structure */ struct x509_sig_info_st { /* NID of message digest */ int mdnid; /* NID of public key algorithm */ int pknid; /* Security bits */ int secbits; /* Various flags */ uint32_t flags; }; /* PKCS#10 certificate request */ struct X509_req_info_st { ASN1_ENCODING enc; /* cached encoding of signed part */ ASN1_INTEGER *version; /* version, defaults to v1(0) so can be NULL */ X509_NAME *subject; /* certificate request DN */ X509_PUBKEY *pubkey; /* public key of request */ /* * Zero or more attributes. * NB: although attributes is a mandatory field some broken * encodings omit it so this may be NULL in that case. */ STACK_OF(X509_ATTRIBUTE) *attributes; }; struct X509_req_st { X509_REQ_INFO req_info; /* signed certificate request data */ X509_ALGOR sig_alg; /* signature algorithm */ ASN1_BIT_STRING *signature; /* signature */ CRYPTO_REF_COUNT references; CRYPTO_RWLOCK *lock; }; struct X509_crl_info_st { ASN1_INTEGER *version; /* version: defaults to v1(0) so may be NULL */ X509_ALGOR sig_alg; /* signature algorithm */ X509_NAME *issuer; /* CRL issuer name */ ASN1_TIME *lastUpdate; /* lastUpdate field */ ASN1_TIME *nextUpdate; /* nextUpdate field: optional */ STACK_OF(X509_REVOKED) *revoked; /* revoked entries: optional */ STACK_OF(X509_EXTENSION) *extensions; /* extensions: optional */ ASN1_ENCODING enc; /* encoding of signed portion of CRL */ }; struct X509_crl_st { X509_CRL_INFO crl; /* signed CRL data */ X509_ALGOR sig_alg; /* CRL signature algorithm */ ASN1_BIT_STRING signature; /* CRL signature */ CRYPTO_REF_COUNT references; int flags; /* * Cached copies of decoded extension values, since extensions * are optional any of these can be NULL. */ AUTHORITY_KEYID *akid; ISSUING_DIST_POINT *idp; /* Convenient breakdown of IDP */ int idp_flags; int idp_reasons; /* CRL and base CRL numbers for delta processing */ ASN1_INTEGER *crl_number; ASN1_INTEGER *base_crl_number; STACK_OF(GENERAL_NAMES) *issuers; /* hash of CRL */ unsigned char sha1_hash[SHA_DIGEST_LENGTH]; /* alternative method to handle this CRL */ const X509_CRL_METHOD *meth; void *meth_data; CRYPTO_RWLOCK *lock; }; struct x509_revoked_st { ASN1_INTEGER serialNumber; /* revoked entry serial number */ ASN1_TIME *revocationDate; /* revocation date */ STACK_OF(X509_EXTENSION) *extensions; /* CRL entry extensions: optional */ /* decoded value of CRLissuer extension: set if indirect CRL */ STACK_OF(GENERAL_NAME) *issuer; /* revocation reason: set to CRL_REASON_NONE if reason extension absent */ int reason; /* * CRL entries are reordered for faster lookup of serial numbers. This * field contains the original load sequence for this entry. */ int sequence; }; /* * This stuff is certificate "auxiliary info": it contains details which are * useful in certificate stores and databases. When used this is tagged onto * the end of the certificate itself. OpenSSL specific structure not defined * in any RFC. */ struct x509_cert_aux_st { STACK_OF(ASN1_OBJECT) *trust; /* trusted uses */ STACK_OF(ASN1_OBJECT) *reject; /* rejected uses */ ASN1_UTF8STRING *alias; /* "friendly name" */ ASN1_OCTET_STRING *keyid; /* key id of private key */ STACK_OF(X509_ALGOR) *other; /* other unspecified info */ }; struct x509_cinf_st { ASN1_INTEGER *version; /* [ 0 ] default of v1 */ ASN1_INTEGER serialNumber; X509_ALGOR signature; X509_NAME *issuer; X509_VAL validity; X509_NAME *subject; X509_PUBKEY *key; ASN1_BIT_STRING *issuerUID; /* [ 1 ] optional in v2 */ ASN1_BIT_STRING *subjectUID; /* [ 2 ] optional in v2 */ STACK_OF(X509_EXTENSION) *extensions; /* [ 3 ] optional in v3 */ ASN1_ENCODING enc; }; struct x509_st { X509_CINF cert_info; X509_ALGOR sig_alg; ASN1_BIT_STRING signature; X509_SIG_INFO siginf; CRYPTO_REF_COUNT references; CRYPTO_EX_DATA ex_data; /* These contain copies of various extension values */ long ex_pathlen; long ex_pcpathlen; uint32_t ex_flags; uint32_t ex_kusage; uint32_t ex_xkusage; uint32_t ex_nscert; ASN1_OCTET_STRING *skid; AUTHORITY_KEYID *akid; X509_POLICY_CACHE *policy_cache; STACK_OF(DIST_POINT) *crldp; STACK_OF(GENERAL_NAME) *altname; NAME_CONSTRAINTS *nc; #ifndef OPENSSL_NO_RFC3779 STACK_OF(IPAddressFamily) *rfc3779_addr; struct ASIdentifiers_st *rfc3779_asid; # endif unsigned char sha1_hash[SHA_DIGEST_LENGTH]; X509_CERT_AUX *aux; CRYPTO_RWLOCK *lock; volatile int ex_cached; } /* X509 */ ; /* * This is a used when verifying cert chains. Since the gathering of the * cert chain can take some time (and have to be 'retried', this needs to be * kept and passed around. */ struct x509_store_ctx_st { /* X509_STORE_CTX */ X509_STORE *ctx; /* The following are set by the caller */ /* The cert to check */ X509 *cert; /* chain of X509s - untrusted - passed in */ STACK_OF(X509) *untrusted; /* set of CRLs passed in */ STACK_OF(X509_CRL) *crls; X509_VERIFY_PARAM *param; /* Other info for use with get_issuer() */ void *other_ctx; /* Callbacks for various operations */ /* called to verify a certificate */ int (*verify) (X509_STORE_CTX *ctx); /* error callback */ int (*verify_cb) (int ok, X509_STORE_CTX *ctx); /* get issuers cert from ctx */ int (*get_issuer) (X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* check issued */ int (*check_issued) (X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* Check revocation status of chain */ int (*check_revocation) (X509_STORE_CTX *ctx); /* retrieve CRL */ int (*get_crl) (X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* Check CRL validity */ int (*check_crl) (X509_STORE_CTX *ctx, X509_CRL *crl); /* Check certificate against CRL */ int (*cert_crl) (X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check policy status of the chain */ int (*check_policy) (X509_STORE_CTX *ctx); STACK_OF(X509) *(*lookup_certs) (X509_STORE_CTX *ctx, X509_NAME *nm); STACK_OF(X509_CRL) *(*lookup_crls) (X509_STORE_CTX *ctx, X509_NAME *nm); int (*cleanup) (X509_STORE_CTX *ctx); /* The following is built up */ /* if 0, rebuild chain */ int valid; /* number of untrusted certs */ int num_untrusted; /* chain of X509s - built up and trusted */ STACK_OF(X509) *chain; /* Valid policy tree */ X509_POLICY_TREE *tree; /* Require explicit policy value */ int explicit_policy; /* When something goes wrong, this is why */ int error_depth; int error; X509 *current_cert; /* cert currently being tested as valid issuer */ X509 *current_issuer; /* current CRL */ X509_CRL *current_crl; /* score of current CRL */ int current_crl_score; /* Reason mask */ unsigned int current_reasons; /* For CRL path validation: parent context */ X509_STORE_CTX *parent; CRYPTO_EX_DATA ex_data; SSL_DANE *dane; /* signed via bare TA public key, rather than CA certificate */ int bare_ta_signed; }; /* PKCS#8 private key info structure */ struct pkcs8_priv_key_info_st { ASN1_INTEGER *version; X509_ALGOR *pkeyalg; ASN1_OCTET_STRING *pkey; STACK_OF(X509_ATTRIBUTE) *attributes; }; struct X509_sig_st { X509_ALGOR *algor; ASN1_OCTET_STRING *digest; }; struct x509_object_st { /* one of the above types */ X509_LOOKUP_TYPE type; union { char *ptr; X509 *x509; X509_CRL *crl; EVP_PKEY *pkey; } data; }; int a2i_ipadd(unsigned char *ipout, const char *ipasc); int x509_set1_time(ASN1_TIME **ptm, const ASN1_TIME *tm); void x509_init_sig_info(X509 *x); + +int x509v3_add_len_value_uchar(const char *name, const unsigned char *value, + size_t vallen, STACK_OF(CONF_VALUE) **extlist); diff --git a/crypto/openssl/include/openssl/opensslv.h b/crypto/openssl/include/openssl/opensslv.h index ec4a1123f131..328d0971c414 100644 --- a/crypto/openssl/include/openssl/opensslv.h +++ b/crypto/openssl/include/openssl/opensslv.h @@ -1,101 +1,101 @@ /* * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #ifndef HEADER_OPENSSLV_H # define HEADER_OPENSSLV_H #ifdef __cplusplus extern "C" { #endif /*- * Numeric release version identifier: * MNNFFPPS: major minor fix patch status * The status nibble has one of the values 0 for development, 1 to e for betas * 1 to 14, and f for release. The patch level is exactly that. * For example: * 0.9.3-dev 0x00903000 * 0.9.3-beta1 0x00903001 * 0.9.3-beta2-dev 0x00903002 * 0.9.3-beta2 0x00903002 (same as ...beta2-dev) * 0.9.3 0x0090300f * 0.9.3a 0x0090301f * 0.9.4 0x0090400f * 1.2.3z 0x102031af * * For continuity reasons (because 0.9.5 is already out, and is coded * 0x00905100), between 0.9.5 and 0.9.6 the coding of the patch level * part is slightly different, by setting the highest bit. This means * that 0.9.5a looks like this: 0x0090581f. At 0.9.6, we can start * with 0x0090600S... * * (Prior to 0.9.3-dev a different scheme was used: 0.9.2b is 0x0922.) * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for * major minor fix final patch/beta) */ # define OPENSSL_VERSION_NUMBER 0x101010bfL -# define OPENSSL_VERSION_TEXT "OpenSSL 1.1.1k-freebsd 25 Mar 2021" +# define OPENSSL_VERSION_TEXT "OpenSSL 1.1.1k-freebsd 24 Aug 2021" /*- * The macros below are to be used for shared library (.so, .dll, ...) * versioning. That kind of versioning works a bit differently between * operating systems. The most usual scheme is to set a major and a minor * number, and have the runtime loader check that the major number is equal * to what it was at application link time, while the minor number has to * be greater or equal to what it was at application link time. With this * scheme, the version number is usually part of the file name, like this: * * libcrypto.so.0.9 * * Some unixen also make a softlink with the major version number only: * * libcrypto.so.0 * * On Tru64 and IRIX 6.x it works a little bit differently. There, the * shared library version is stored in the file, and is actually a series * of versions, separated by colons. The rightmost version present in the * library when linking an application is stored in the application to be * matched at run time. When the application is run, a check is done to * see if the library version stored in the application matches any of the * versions in the version string of the library itself. * This version string can be constructed in any way, depending on what * kind of matching is desired. However, to implement the same scheme as * the one used in the other unixen, all compatible versions, from lowest * to highest, should be part of the string. Consecutive builds would * give the following versions strings: * * 3.0 * 3.0:3.1 * 3.0:3.1:3.2 * 4.0 * 4.0:4.1 * * Notice how version 4 is completely incompatible with version, and * therefore give the breach you can see. * * There may be other schemes as well that I haven't yet discovered. * * So, here's the way it works here: first of all, the library version * number doesn't need at all to match the overall OpenSSL version. * However, it's nice and more understandable if it actually does. * The current library version is stored in the macro SHLIB_VERSION_NUMBER, * which is just a piece of text in the format "M.m.e" (Major, minor, edit). * For the sake of Tru64, IRIX, and any other OS that behaves in similar ways, * we need to keep a history of version numbers, which is done in the * macro SHLIB_VERSION_HISTORY. The numbers are separated by colons and * should only keep the versions that are binary compatible with the current. */ # define SHLIB_VERSION_HISTORY "" # define SHLIB_VERSION_NUMBER "111" #ifdef __cplusplus } #endif #endif /* HEADER_OPENSSLV_H */