diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index 613f9ae713..cc0a59ca4c 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * 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 @@ -49,6 +49,7 @@ static const ERR_STRING_DATA ASN1_str_functs[] = { "asn1_item_embed_d2i"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_ITEM_EMBED_NEW, 0), "asn1_item_embed_new"}, + {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_ITEM_EX_I2D, 0), "ASN1_item_ex_i2d"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_ITEM_FLAGS_I2D, 0), "asn1_item_flags_i2d"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_ITEM_I2D_BIO, 0), "ASN1_item_i2d_bio"}, @@ -160,6 +161,7 @@ static const ERR_STRING_DATA ASN1_str_reasons[] = { "asn1 sig parse error"}, {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_AUX_ERROR), "aux error"}, {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_OBJECT_HEADER), "bad object header"}, + {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_TEMPLATE), "bad template"}, {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BMPSTRING_IS_WRONG_LENGTH), "bmpstring is wrong length"}, {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BN_LIB), "bn lib"}, diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c index 2332b204ed..1021705f43 100644 --- a/crypto/asn1/tasn_dec.c +++ b/crypto/asn1/tasn_dec.c @@ -182,6 +182,15 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in, tag, aclass, opt, ctx); case ASN1_ITYPE_MSTRING: + /* + * It never makes sense for multi-strings to have implicit tagging, so + * if tag != -1, then this looks like an error in the template. + */ + if (tag != -1) { + ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_BAD_TEMPLATE); + goto err; + } + p = *in; /* Just read in tag and class */ ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, @@ -199,6 +208,7 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in, ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_MSTRING_NOT_UNIVERSAL); goto err; } + /* Check tag matches bit map */ if (!(ASN1_tag2bit(otag) & it->utype)) { /* If OPTIONAL, assume this is OK */ @@ -215,6 +225,15 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in, return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx); case ASN1_ITYPE_CHOICE: + /* + * It never makes sense for CHOICE types to have implicit tagging, so + * if tag != -1, then this looks like an error in the template. + */ + if (tag != -1) { + ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_BAD_TEMPLATE); + goto err; + } + if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) goto auxerr; if (*pval) { diff --git a/crypto/asn1/tasn_enc.c b/crypto/asn1/tasn_enc.c index d600c7a538..52a051d5b1 100644 --- a/crypto/asn1/tasn_enc.c +++ b/crypto/asn1/tasn_enc.c @@ -103,9 +103,25 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); case ASN1_ITYPE_MSTRING: + /* + * It never makes sense for multi-strings to have implicit tagging, so + * if tag != -1, then this looks like an error in the template. + */ + if (tag != -1) { + ASN1err(ASN1_F_ASN1_ITEM_EX_I2D, ASN1_R_BAD_TEMPLATE); + return -1; + } return asn1_i2d_ex_primitive(pval, out, it, -1, aclass); case ASN1_ITYPE_CHOICE: + /* + * It never makes sense for CHOICE types to have implicit tagging, so + * if tag != -1, then this looks like an error in the template. + */ + if (tag != -1) { + ASN1err(ASN1_F_ASN1_ITEM_EX_I2D, ASN1_R_BAD_TEMPLATE); + return -1; + } if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) return 0; i = asn1_get_choice_selector(pval, it); diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 0b5873ebbc..815460b24f 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -36,6 +36,7 @@ ASN1_F_ASN1_ITEM_D2I_FP:206:ASN1_item_d2i_fp ASN1_F_ASN1_ITEM_DUP:191:ASN1_item_dup ASN1_F_ASN1_ITEM_EMBED_D2I:120:asn1_item_embed_d2i ASN1_F_ASN1_ITEM_EMBED_NEW:121:asn1_item_embed_new +ASN1_F_ASN1_ITEM_EX_I2D:144:ASN1_item_ex_i2d ASN1_F_ASN1_ITEM_FLAGS_I2D:118:asn1_item_flags_i2d ASN1_F_ASN1_ITEM_I2D_BIO:192:ASN1_item_i2d_bio ASN1_F_ASN1_ITEM_I2D_FP:193:ASN1_item_i2d_fp @@ -1771,6 +1772,7 @@ ASN1_R_ASN1_PARSE_ERROR:203:asn1 parse error ASN1_R_ASN1_SIG_PARSE_ERROR:204:asn1 sig parse error ASN1_R_AUX_ERROR:100:aux error ASN1_R_BAD_OBJECT_HEADER:102:bad object header +ASN1_R_BAD_TEMPLATE:230:bad template ASN1_R_BMPSTRING_IS_WRONG_LENGTH:214:bmpstring is wrong length ASN1_R_BN_LIB:105:bn lib ASN1_R_BOOLEAN_IS_WRONG_LENGTH:106:boolean is wrong length diff --git a/crypto/x509v3/v3_genn.c b/crypto/x509v3/v3_genn.c index 23e3bc4565..6f0a347cce 100644 --- a/crypto/x509v3/v3_genn.c +++ b/crypto/x509v3/v3_genn.c @@ -22,8 +22,9 @@ ASN1_SEQUENCE(OTHERNAME) = { IMPLEMENT_ASN1_FUNCTIONS(OTHERNAME) ASN1_SEQUENCE(EDIPARTYNAME) = { - ASN1_IMP_OPT(EDIPARTYNAME, nameAssigner, DIRECTORYSTRING, 0), - ASN1_IMP_OPT(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1) + /* DirectoryString is a CHOICE type so use explicit tagging */ + ASN1_EXP_OPT(EDIPARTYNAME, nameAssigner, DIRECTORYSTRING, 0), + ASN1_EXP(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1) } ASN1_SEQUENCE_END(EDIPARTYNAME) IMPLEMENT_ASN1_FUNCTIONS(EDIPARTYNAME) @@ -57,6 +58,37 @@ GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a) (char *)a); } +static int edipartyname_cmp(const EDIPARTYNAME *a, const EDIPARTYNAME *b) +{ + int res; + + if (a == NULL || b == NULL) { + /* + * Shouldn't be possible in a valid GENERAL_NAME, but we handle it + * anyway. OTHERNAME_cmp treats NULL != NULL so we do the same here + */ + return -1; + } + if (a->nameAssigner == NULL && b->nameAssigner != NULL) + return -1; + if (a->nameAssigner != NULL && b->nameAssigner == NULL) + return 1; + /* If we get here then both have nameAssigner set, or both unset */ + if (a->nameAssigner != NULL) { + res = ASN1_STRING_cmp(a->nameAssigner, b->nameAssigner); + if (res != 0) + return res; + } + /* + * partyName is required, so these should never be NULL. We treat it in + * the same way as the a == NULL || b == NULL case above + */ + if (a->partyName == NULL || b->partyName == NULL) + return -1; + + return ASN1_STRING_cmp(a->partyName, b->partyName); +} + /* Returns 0 if they are equal, != 0 otherwise. */ int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) { @@ -66,8 +98,11 @@ int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) return -1; switch (a->type) { case GEN_X400: + result = ASN1_TYPE_cmp(a->d.x400Address, b->d.x400Address); + break; + case GEN_EDIPARTY: - result = ASN1_TYPE_cmp(a->d.other, b->d.other); + result = edipartyname_cmp(a->d.ediPartyName, b->d.ediPartyName); break; case GEN_OTHERNAME: @@ -114,8 +149,11 @@ void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value) { switch (type) { case GEN_X400: + a->d.x400Address = value; + break; + case GEN_EDIPARTY: - a->d.other = value; + a->d.ediPartyName = value; break; case GEN_OTHERNAME: @@ -149,8 +187,10 @@ void *GENERAL_NAME_get0_value(const GENERAL_NAME *a, int *ptype) *ptype = a->type; switch (a->type) { case GEN_X400: + return a->d.x400Address; + case GEN_EDIPARTY: - return a->d.other; + return a->d.ediPartyName; case GEN_OTHERNAME: return a->d.otherName; diff --git a/include/openssl/asn1err.h b/include/openssl/asn1err.h index faed5a5518..e1ad1fefec 100644 --- a/include/openssl/asn1err.h +++ b/include/openssl/asn1err.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * 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 @@ -11,9 +11,7 @@ #ifndef HEADER_ASN1ERR_H # define HEADER_ASN1ERR_H -# ifndef HEADER_SYMHACKS_H -# include -# endif +# include # ifdef __cplusplus extern "C" @@ -53,6 +51,7 @@ int ERR_load_ASN1_strings(void); # define ASN1_F_ASN1_ITEM_DUP 191 # define ASN1_F_ASN1_ITEM_EMBED_D2I 120 # define ASN1_F_ASN1_ITEM_EMBED_NEW 121 +# define ASN1_F_ASN1_ITEM_EX_I2D 144 # define ASN1_F_ASN1_ITEM_FLAGS_I2D 118 # define ASN1_F_ASN1_ITEM_I2D_BIO 192 # define ASN1_F_ASN1_ITEM_I2D_FP 193 @@ -145,6 +144,7 @@ int ERR_load_ASN1_strings(void); # define ASN1_R_ASN1_SIG_PARSE_ERROR 204 # define ASN1_R_AUX_ERROR 100 # define ASN1_R_BAD_OBJECT_HEADER 102 +# define ASN1_R_BAD_TEMPLATE 230 # define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 214 # define ASN1_R_BN_LIB 105 # define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106 diff --git a/test/asn1_decode_test.c b/test/asn1_decode_test.c index 369023d5f1..94a22c6682 100644 --- a/test/asn1_decode_test.c +++ b/test/asn1_decode_test.c @@ -160,6 +160,41 @@ static int test_uint64(void) return 1; } +typedef struct { + ASN1_STRING *invalidDirString; +} INVALIDTEMPLATE; + +ASN1_SEQUENCE(INVALIDTEMPLATE) = { + /* + * DirectoryString is a CHOICE type so it must use explicit tagging - + * but we deliberately use implicit here, which makes this template invalid. + */ + ASN1_IMP(INVALIDTEMPLATE, invalidDirString, DIRECTORYSTRING, 12) +} static_ASN1_SEQUENCE_END(INVALIDTEMPLATE) + +IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(INVALIDTEMPLATE) +IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(INVALIDTEMPLATE) + +/* Empty sequence for invalid template test */ +static unsigned char t_invalid_template[] = { + 0x30, 0x03, /* SEQUENCE tag + length */ + 0x0c, 0x01, 0x41 /* UTF8String, length 1, "A" */ +}; + +static int test_invalid_template(void) +{ + const unsigned char *p = t_invalid_template; + INVALIDTEMPLATE *tmp = d2i_INVALIDTEMPLATE(NULL, &p, + sizeof(t_invalid_template)); + + /* We expect a NULL pointer return */ + if (TEST_ptr_null(tmp)) + return 1; + + INVALIDTEMPLATE_free(tmp); + return 0; +} + int setup_tests(void) { #if OPENSSL_API_COMPAT < 0x10200000L @@ -169,5 +204,6 @@ int setup_tests(void) ADD_TEST(test_uint32); ADD_TEST(test_int64); ADD_TEST(test_uint64); + ADD_TEST(test_invalid_template); return 1; } diff --git a/test/asn1_encode_test.c b/test/asn1_encode_test.c index ed920a4d66..afbd18be6f 100644 --- a/test/asn1_encode_test.c +++ b/test/asn1_encode_test.c @@ -856,6 +856,38 @@ static int test_uint64(void) return test_intern(&uint64_test_package); } +typedef struct { + ASN1_STRING *invalidDirString; +} INVALIDTEMPLATE; + +ASN1_SEQUENCE(INVALIDTEMPLATE) = { + /* + * DirectoryString is a CHOICE type so it must use explicit tagging - + * but we deliberately use implicit here, which makes this template invalid. + */ + ASN1_IMP(INVALIDTEMPLATE, invalidDirString, DIRECTORYSTRING, 12) +} static_ASN1_SEQUENCE_END(INVALIDTEMPLATE) + +IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(INVALIDTEMPLATE) +IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(INVALIDTEMPLATE) + +static int test_invalid_template(void) +{ + INVALIDTEMPLATE *temp = INVALIDTEMPLATE_new(); + int ret; + + if (!TEST_ptr(temp)) + return 0; + + ret = i2d_INVALIDTEMPLATE(temp, NULL); + + INVALIDTEMPLATE_free(temp); + + /* We expect the i2d operation to fail */ + return ret < 0; +} + + int setup_tests(void) { #if OPENSSL_API_COMPAT < 0x10200000L @@ -866,5 +898,6 @@ int setup_tests(void) ADD_TEST(test_uint32); ADD_TEST(test_int64); ADD_TEST(test_uint64); + ADD_TEST(test_invalid_template); return 1; } diff --git a/test/v3nametest.c b/test/v3nametest.c index 86f3829aed..4c8af92ce9 100644 --- a/test/v3nametest.c +++ b/test/v3nametest.c @@ -359,8 +359,352 @@ static int call_run_cert(int i) return failed == 0; } +struct gennamedata { + const unsigned char der[22]; + size_t derlen; +} gennames[] = { + { + /* + * [0] { + * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } + * [0] { + * SEQUENCE {} + * } + * } + */ + { + 0xa0, 0x13, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, + 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x02, 0x30, 0x00 + }, + 21 + }, { + /* + * [0] { + * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } + * [0] { + * [APPLICATION 0] {} + * } + * } + */ + { + 0xa0, 0x13, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, + 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x02, 0x60, 0x00 + }, + 21 + }, { + /* + * [0] { + * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } + * [0] { + * UTF8String { "a" } + * } + * } + */ + { + 0xa0, 0x14, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, + 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x03, 0x0c, 0x01, 0x61 + }, + 22 + }, { + /* + * [0] { + * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.2 } + * [0] { + * UTF8String { "a" } + * } + * } + */ + { + 0xa0, 0x14, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, + 0x01, 0x84, 0xb7, 0x09, 0x02, 0x02, 0xa0, 0x03, 0x0c, 0x01, 0x61 + }, + 22 + }, { + /* + * [0] { + * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } + * [0] { + * UTF8String { "b" } + * } + * } + */ + { + 0xa0, 0x14, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, + 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x03, 0x0c, 0x01, 0x62 + }, + 22 + }, { + /* + * [0] { + * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } + * [0] { + * BOOLEAN { TRUE } + * } + * } + */ + { + 0xa0, 0x14, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, + 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x03, 0x01, 0x01, 0xff + }, + 22 + }, { + /* + * [0] { + * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } + * [0] { + * BOOLEAN { FALSE } + * } + * } + */ + { + 0xa0, 0x14, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, + 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x03, 0x01, 0x01, 0x00 + }, + 22 + }, { + /* [1 PRIMITIVE] { "a" } */ + { + 0x81, 0x01, 0x61 + }, + 3 + }, { + /* [1 PRIMITIVE] { "b" } */ + { + 0x81, 0x01, 0x62 + }, + 3 + }, { + /* [2 PRIMITIVE] { "a" } */ + { + 0x82, 0x01, 0x61 + }, + 3 + }, { + /* [2 PRIMITIVE] { "b" } */ + { + 0x82, 0x01, 0x62 + }, + 3 + }, { + /* + * [4] { + * SEQUENCE { + * SET { + * SEQUENCE { + * # commonName + * OBJECT_IDENTIFIER { 2.5.4.3 } + * UTF8String { "a" } + * } + * } + * } + * } + */ + { + 0xa4, 0x0e, 0x30, 0x0c, 0x31, 0x0a, 0x30, 0x08, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x01, 0x61 + }, + 16 + }, { + /* + * [4] { + * SEQUENCE { + * SET { + * SEQUENCE { + * # commonName + * OBJECT_IDENTIFIER { 2.5.4.3 } + * UTF8String { "b" } + * } + * } + * } + * } + */ + { + 0xa4, 0x0e, 0x30, 0x0c, 0x31, 0x0a, 0x30, 0x08, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x01, 0x62 + }, + 16 + }, { + /* + * [5] { + * [1] { + * UTF8String { "a" } + * } + * } + */ + { + 0xa5, 0x05, 0xa1, 0x03, 0x0c, 0x01, 0x61 + }, + 7 + }, { + /* + * [5] { + * [1] { + * UTF8String { "b" } + * } + * } + */ + { + 0xa5, 0x05, 0xa1, 0x03, 0x0c, 0x01, 0x62 + }, + 7 + }, { + /* + * [5] { + * [0] { + * UTF8String {} + * } + * [1] { + * UTF8String { "a" } + * } + * } + */ + { + 0xa5, 0x09, 0xa0, 0x02, 0x0c, 0x00, 0xa1, 0x03, 0x0c, 0x01, 0x61 + }, + 11 + }, { + /* + * [5] { + * [0] { + * UTF8String { "a" } + * } + * [1] { + * UTF8String { "a" } + * } + * } + */ + { + 0xa5, 0x0a, 0xa0, 0x03, 0x0c, 0x01, 0x61, 0xa1, 0x03, 0x0c, 0x01, + 0x61 + }, + 12 + }, { + /* + * [5] { + * [0] { + * UTF8String { "b" } + * } + * [1] { + * UTF8String { "a" } + * } + * } + */ + { + 0xa5, 0x0a, 0xa0, 0x03, 0x0c, 0x01, 0x62, 0xa1, 0x03, 0x0c, 0x01, + 0x61 + }, + 12 + }, { + /* [6 PRIMITIVE] { "a" } */ + { + 0x86, 0x01, 0x61 + }, + 3 + }, { + /* [6 PRIMITIVE] { "b" } */ + { + 0x86, 0x01, 0x62 + }, + 3 + }, { + /* [7 PRIMITIVE] { `11111111` } */ + { + 0x87, 0x04, 0x11, 0x11, 0x11, 0x11 + }, + 6 + }, { + /* [7 PRIMITIVE] { `22222222`} */ + { + 0x87, 0x04, 0x22, 0x22, 0x22, 0x22 + }, + 6 + }, { + /* [7 PRIMITIVE] { `11111111111111111111111111111111` } */ + { + 0x87, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 + }, + 18 + }, { + /* [7 PRIMITIVE] { `22222222222222222222222222222222` } */ + { + 0x87, 0x10, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 + }, + 18 + }, { + /* [8 PRIMITIVE] { 1.2.840.113554.4.1.72585.2.1 } */ + { + 0x88, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, + 0xb7, 0x09, 0x02, 0x01 + }, + 15 + }, { + /* [8 PRIMITIVE] { 1.2.840.113554.4.1.72585.2.2 } */ + { + 0x88, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, + 0xb7, 0x09, 0x02, 0x02 + }, + 15 + } +}; + +static int test_GENERAL_NAME_cmp(void) +{ + size_t i, j; + GENERAL_NAME **namesa = OPENSSL_malloc(sizeof(*namesa) + * OSSL_NELEM(gennames)); + GENERAL_NAME **namesb = OPENSSL_malloc(sizeof(*namesb) + * OSSL_NELEM(gennames)); + int testresult = 0; + + if (!TEST_ptr(namesa) || !TEST_ptr(namesb)) + goto end; + + for (i = 0; i < OSSL_NELEM(gennames); i++) { + const unsigned char *derp = gennames[i].der; + + /* + * We create two versions of each GENERAL_NAME so that we ensure when + * we compare them they are always different pointers. + */ + namesa[i] = d2i_GENERAL_NAME(NULL, &derp, gennames[i].derlen); + derp = gennames[i].der; + namesb[i] = d2i_GENERAL_NAME(NULL, &derp, gennames[i].derlen); + if (!TEST_ptr(namesa[i]) || !TEST_ptr(namesb[i])) + goto end; + } + + /* Every name should be equal to itself and not equal to any others. */ + for (i = 0; i < OSSL_NELEM(gennames); i++) { + for (j = 0; j < OSSL_NELEM(gennames); j++) { + if (i == j) { + if (!TEST_int_eq(GENERAL_NAME_cmp(namesa[i], namesb[j]), 0)) + goto end; + } else { + if (!TEST_int_ne(GENERAL_NAME_cmp(namesa[i], namesb[j]), 0)) + goto end; + } + } + } + testresult = 1; + + end: + for (i = 0; i < OSSL_NELEM(gennames); i++) { + if (namesa != NULL) + GENERAL_NAME_free(namesa[i]); + if (namesb != NULL) + GENERAL_NAME_free(namesb[i]); + } + OPENSSL_free(namesa); + OPENSSL_free(namesb); + + return testresult; +} + int setup_tests(void) { ADD_ALL_TESTS(call_run_cert, OSSL_NELEM(name_fns)); + ADD_TEST(test_GENERAL_NAME_cmp); return 1; }