diff --git a/tests/api.c b/tests/api.c index 7e2e14ddc..73efbfae6 100644 --- a/tests/api.c +++ b/tests/api.c @@ -47067,6 +47067,11 @@ static void test_wc_ParseCert(void) wc_InitDecodedCert(&decodedCert, rawCert, rawCertSize, NULL); AssertIntEQ(wc_ParseCert(&decodedCert, CERT_TYPE, NO_VERIFY, NULL), 0); +#ifndef IGNORE_NAME_CONSTRAINTS + /* check that the subjects emailAddress was not put in the alt name list */ + AssertNotNull(decodedCert.subjectEmail); + AssertNull(decodedCert.altEmailNames); +#endif wc_FreeDecodedCert(&decodedCert); printf(resultFmt, passed); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index ea212c2fe..11ceb678e 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -11261,14 +11261,14 @@ static int SetSubject(DecodedCert* cert, int id, byte* str, word32 strLen, SetCertNameSubjectLen(cert, id, strLen); SetCertNameSubjectEnc(cert, id, tag); } +#endif +#if !defined(IGNORE_NAME_CONSTRAINTS) || \ + defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT) else if (id == ASN_EMAIL) { cert->subjectEmail = (char*)str; cert->subjectEmailLen = strLen; - #if !defined(IGNORE_NAME_CONSTRAINTS) - ret = SetDNSEntry(cert, cert->subjectEmail, strLen, 0, - &cert->altEmailNames); - #endif } +#endif #ifdef WOLFSSL_CERT_EXT /* TODO: consider mapping id to an index and using SetCertNameSubect*(). */ else if (id == ASN_JURIS_C) { @@ -11281,7 +11281,6 @@ static int SetSubject(DecodedCert* cert, int id, byte* str, word32 strLen, cert->subjectJSLen = strLen; cert->subjectJSEnc = tag; } -#endif #endif return ret; @@ -11904,7 +11903,8 @@ static int GetCertName(DecodedCert* cert, char* full, byte* hash, int nameType, copy = WOLFSSL_EMAIL_ADDR; } - #if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT) + #if !defined(IGNORE_NAME_CONSTRAINTS) || \ + defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT) if (nameType == SUBJECT) { cert->subjectEmail = (char*)&input[srcIdx]; cert->subjectEmailLen = strLen; @@ -11921,41 +11921,6 @@ static int GetCertName(DecodedCert* cert, char* full, byte* hash, int nameType, && !defined(WOLFCRYPT_ONLY) nid = NID_emailAddress; #endif /* OPENSSL_EXTRA */ - #ifndef IGNORE_NAME_CONSTRAINTS - { - DNS_entry* emailName; - - emailName = AltNameNew(cert->heap); - if (emailName == NULL) { - WOLFSSL_MSG("\tOut of Memory"); - #if (defined(OPENSSL_EXTRA) || \ - defined(OPENSSL_EXTRA_X509_SMALL)) && \ - !defined(WOLFCRYPT_ONLY) - wolfSSL_X509_NAME_free(dName); - #endif /* OPENSSL_EXTRA */ - return MEMORY_E; - } - emailName->type = 0; - emailName->name = (char*)XMALLOC(strLen + 1, - cert->heap, DYNAMIC_TYPE_ALTNAME); - if (emailName->name == NULL) { - WOLFSSL_MSG("\tOut of Memory"); - XFREE(emailName, cert->heap, DYNAMIC_TYPE_ALTNAME); - #if (defined(OPENSSL_EXTRA) || \ - defined(OPENSSL_EXTRA_X509_SMALL)) && \ - !defined(WOLFCRYPT_ONLY) - wolfSSL_X509_NAME_free(dName); - #endif /* OPENSSL_EXTRA */ - return MEMORY_E; - } - emailName->len = strLen; - XMEMCPY(emailName->name, &input[srcIdx], strLen); - emailName->name[strLen] = '\0'; - - emailName->next = cert->altEmailNames; - cert->altEmailNames = emailName; - } - #endif /* IGNORE_NAME_CONSTRAINTS */ } if (pilot) { @@ -14525,6 +14490,68 @@ static int MatchBaseName(int type, const char* name, int nameSz, } +/* Search through the list to find if the name is permitted. + * name The DNS name to search for + * dnsList The list to search through + * nameType Type of DNS name to currently searching + * return 1 if found in list or if not needed + * return 0 if not found in the list but is needed + */ +static int PermittedListOk(DNS_entry* name, Base_entry* dnsList, byte nameType) +{ + Base_entry* current = dnsList; + int match = 0; + int need = 0; + int ret = 1; /* is ok unless needed and no match found */ + + while (current != NULL) { + if (current->type == nameType) { + need = 1; /* restriction on permitted names is set for this type */ + if (name->len >= current->nameSz && + MatchBaseName(nameType, name->name, name->len, + current->name, current->nameSz)) { + match = 1; /* found the current name in the permitted list*/ + break; + } + } + current = current->next; + } + + /* check if permitted name restriction was set and no matching name found */ + if (need && !match) + ret = 0; + + return ret; +} + + +/* Search through the list to find if the name is excluded. + * name The DNS name to search for + * dnsList The list to search through + * nameType Type of DNS name to currently searching + * return 1 if found in list and 0 if not found in the list + */ +static int IsInExcludedList(DNS_entry* name, Base_entry* dnsList, byte nameType) +{ + int ret = 0; /* default of not found in the list */ + Base_entry* current = dnsList; + + while (current != NULL) { + if (current->type == nameType) { + if (name->len >= current->nameSz && + MatchBaseName(nameType, name->name, name->len, + current->name, current->nameSz)) { + ret = 1; + break; + } + } + current = current->next; + } + + return ret; +} + + static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert) { const byte nameTypes[] = {ASN_RFC822_TYPE, ASN_DNS_TYPE, ASN_DIR_TYPE}; @@ -14539,9 +14566,9 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert) for (i=0; i < (int)sizeof(nameTypes); i++) { byte nameType = nameTypes[i]; DNS_entry* name = NULL; - DNS_entry subjectDnsName; - Base_entry* base; + DNS_entry subjectDnsName; /* temporary node used for subject name */ + XMEMSET(&subjectDnsName, 0, sizeof(DNS_entry)); switch (nameType) { case ASN_DNS_TYPE: /* Should it also consider CN in subject? It could use @@ -14551,28 +14578,38 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert) case ASN_RFC822_TYPE: /* Shouldn't it validade E= in subject as well? */ name = cert->altEmailNames; + + /* Add subject email for checking. */ + if (cert->subjectEmail != NULL) { + /* RFC 5280 section 4.2.1.10 + * "When constraints are imposed on the rfc822Name name + * form, but the certificate does not include a subject + * alternative name, the rfc822Name constraint MUST be + * applied to the attribute of type emailAddress in the + * subject distinguished name" */ + subjectDnsName.next = NULL; + subjectDnsName.type = ASN_RFC822_TYPE; + subjectDnsName.len = cert->subjectEmailLen; + subjectDnsName.name = (char *)cert->subjectEmail; + } break; case ASN_DIR_TYPE: - if (cert->subjectRaw != NULL) { - subjectDnsName.next = NULL; - subjectDnsName.type = ASN_DIR_TYPE; - subjectDnsName.len = cert->subjectRawLen; - subjectDnsName.name = (char *)cert->subjectRaw; - name = &subjectDnsName; - } + name = cert->altDirNames; - #ifndef WOLFSSL_NO_ASN_STRICT + #ifndef WOLFSSL_NO_ASN_STRICT /* RFC 5280 section 4.2.1.10 "Restrictions of the form directoryName MUST be applied to the subject field .... and to any names of type directoryName in the subjectAltName extension" */ - if (name != NULL) - name->next = cert->altDirNames; - else - name = cert->altDirNames; - #endif + if (cert->subjectRaw != NULL) { + subjectDnsName.next = NULL; + subjectDnsName.type = ASN_DIR_TYPE; + subjectDnsName.len = cert->subjectRawLen; + subjectDnsName.name = (char *)cert->subjectRaw; + } + #endif break; default: /* Other types of names are ignored for now. @@ -14582,44 +14619,35 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert) } while (name != NULL) { - int match = 0; - int need = 0; - - base = signer->excludedNames; - /* Check against the excluded list */ - while (base != NULL) { - if (base->type == nameType) { - if (name->len >= base->nameSz && - MatchBaseName(nameType, - name->name, name->len, - base->name, base->nameSz)) { - return 0; - } - } - base = base->next; + if (IsInExcludedList(name, signer->excludedNames, nameType) == 1) { + WOLFSSL_MSG("Excluded name was found!"); + return 0; } /* Check against the permitted list */ - base = signer->permittedNames; - while (base != NULL) { - if (base->type == nameType) { - need = 1; - if (name->len >= base->nameSz && - MatchBaseName(nameType, - name->name, name->len, - base->name, base->nameSz)) { - match = 1; - break; - } - } - base = base->next; + if (PermittedListOk(name, signer->permittedNames, nameType) != 1) { + WOLFSSL_MSG("Permitted name was not found!"); + return 0; } - if (need && !match) - return 0; - name = name->next; } + + /* handle comparing against subject name too */ + if (subjectDnsName.len > 0 && subjectDnsName.name != NULL) { + if (IsInExcludedList(&subjectDnsName, signer->excludedNames, + nameType) == 1) { + WOLFSSL_MSG("Excluded name was found!"); + return 0; + } + + /* Check against the permitted list */ + if (PermittedListOk(&subjectDnsName, signer->permittedNames, + nameType) != 1) { + WOLFSSL_MSG("Permitted name was not found!"); + return 0; + } + } } return 1; diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index a82d60f0f..905d40932 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1636,6 +1636,11 @@ struct DecodedCert { const byte* subjectRaw; /* pointer to subject inside source */ int subjectRawLen; #endif +#if !defined(IGNORE_NAME_CONSTRAINTS) || \ + defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT) + char* subjectEmail; + int subjectEmailLen; +#endif #if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT) /* easy access to subject info for other sign */ char* subjectSN; @@ -1677,8 +1682,6 @@ struct DecodedCert { char* subjectPC; int subjectPCLen; char subjectPCEnc; - char* subjectEmail; - int subjectEmailLen; #if defined(WOLFSSL_HAVE_ISSUER_NAMES) char* issuerCN; int issuerCNLen;