commit 54dee08a997875d7aa43e6fb40f5bd63e32bc20f Author: John Denker Date: Tue Sep 9 11:08:47 2014 -0700 fix bypass bug by creating effective_names function diff --git a/crypto/x509v3/v3_ncons.c b/crypto/x509v3/v3_ncons.c index 257d3d2..6a06cfa 100644 --- a/crypto/x509v3/v3_ncons.c +++ b/crypto/x509v3/v3_ncons.c @@ -224,6 +224,81 @@ static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip) return 1; } + +/* Return a stack containing the effective name(s) of a given X509 cert. + * + * If there is a subjectAltNames section containing zero or more names, + * those are the effective names. + * Otherwise, if there is no subjectAltNames section at all, + * we use the common name as found in the subject name. + * + * If the result is non-null, caller is responsible for freeing it. + */ + +// should be: STACK_OF(GENERAL_NAMES) * effective_names(X509 const *x) +// but X509_get_subject_name(x) spoils it, because it's not +// declared const. +STACK_OF(GENERAL_NAME) * effective_names(X509 *x) + { + STACK_OF(GENERAL_NAME) *rslt = NULL; + GENERAL_NAME* gntmp = NULL; + X509_NAME *nm = NULL; + int tmp, idx = -1; + + int num_altnames = sk_GENERAL_NAME_num(x->altname); + if (num_altnames >= 0) /* we have a subjectAltNames section */ + { + rslt = sk_GENERAL_NAME_dup(x->altname); + if (rslt == NULL) + goto memerr; + return rslt; + } + +/* Here if there is no subjectAltNames section at all. */ + nm = X509_get_subject_name(x); + + rslt = sk_GENERAL_NAME_new_null(); + if (rslt == NULL) + goto memerr; + +/* At this point, rslt is a zero-length list. */ + if(!nm) + return rslt; /* no subject name at all?! */ + +/* Get idx of the last common name in the subject name: */ + while((tmp = X509_NAME_get_index_by_NID(nm, NID_commonName, idx)) >= 0) + idx=tmp; + if (idx >= 0) + { + X509_NAME_ENTRY* ne = X509_NAME_get_entry(nm, idx); + gntmp = GENERAL_NAME_new(); + if (gntmp == NULL) + goto memerr; + gntmp->type = GEN_DNS; + gntmp->d.dNSName = X509_NAME_ENTRY_get_data(ne); + if (gntmp->d.dNSName->type != V_ASN1_PRINTABLESTRING) + { + /* Can this ever happen? */ + /* Should we complain? */ + /* Should this be X509_V_ERR_UNSUPPORTED_NAME_SYNTAX ? */ + goto punt; + } + if (!sk_GENERAL_NAME_push(rslt, gntmp)) + goto punt; + gntmp = NULL; /* Ownership is lost. */ + } + return rslt; + + memerr: + X509V3err(X509V3_F_V2I_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE); + punt: + if (gntmp != NULL) + GENERAL_NAME_free(gntmp); + if (rslt != NULL) + sk_GENERAL_NAME_free(rslt); + return NULL; + } + /* Check a certificate conforms to a specified set of constraints. * Return values: * X509_V_OK: All constraints obeyed. @@ -239,6 +314,8 @@ static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip) int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc) { int r, i; + STACK_OF(GENERAL_NAME) * allnames; + int num_all; X509_NAME *nm; nm = X509_get_subject_name(x); @@ -280,16 +357,21 @@ int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc) } - for (i = 0; i < sk_GENERAL_NAME_num(x->altname); i++) + allnames = effective_names(x); + num_all = sk_GENERAL_NAME_num(allnames); /* could be -1 if allnames is NULL */ + +/* Process each of the names */ + r = X509_V_OK; /* things are OK if no names */ + for (i = 0; i < num_all; i++) { - GENERAL_NAME *gen = sk_GENERAL_NAME_value(x->altname, i); + GENERAL_NAME *gen = sk_GENERAL_NAME_value(allnames, i); r = nc_match(gen, nc); if (r != X509_V_OK) - return r; + break; } - - return X509_V_OK; - + if (allnames) + sk_GENERAL_NAME_free(allnames); + return r; } static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc) diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h index b308abe..cfe8803 100644 --- a/crypto/x509v3/x509v3.h +++ b/crypto/x509v3/x509v3.h @@ -572,6 +572,7 @@ DECLARE_ASN1_FUNCTIONS(ISSUING_DIST_POINT) int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname); +STACK_OF(GENERAL_NAME) * effective_names(X509 *x); int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc); DECLARE_ASN1_FUNCTIONS(ACCESS_DESCRIPTION)