diff --git a/certs/test/cert-ext-ndir-exc.cfg b/certs/test/cert-ext-ndir-exc.cfg new file mode 100644 index 000000000..8d66b8a07 --- /dev/null +++ b/certs/test/cert-ext-ndir-exc.cfg @@ -0,0 +1,24 @@ +[ req ] +distinguished_name = req_distinguished_name +prompt = no +x509_extensions = constraints + +[ req_distinguished_name ] +C = US +ST = Montana +L = Bozeman +O = Sawtooth +OU = Consulting +CN = www.wolfssl.com +emailAddress = info@wolfsssl.com + +[constraints] +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always +basicConstraints=CA:TRUE +nameConstraints=critical,excluded;dirName:dir_name_exclude + +[dir_name_exclude] +countryName = US +stateOrProvinceName = California + diff --git a/certs/test/cert-ext-ndir-exc.der b/certs/test/cert-ext-ndir-exc.der new file mode 100644 index 000000000..19afbab84 Binary files /dev/null and b/certs/test/cert-ext-ndir-exc.der differ diff --git a/certs/test/cert-ext-ndir.cfg b/certs/test/cert-ext-ndir.cfg new file mode 100644 index 000000000..0757874d8 --- /dev/null +++ b/certs/test/cert-ext-ndir.cfg @@ -0,0 +1,23 @@ +[ req ] +distinguished_name = req_distinguished_name +prompt = no +x509_extensions = constraints + +[ req_distinguished_name ] +C = US +ST = Montana +L = Bozeman +O = Sawtooth +OU = Consulting +CN = www.wolfssl.com +emailAddress = info@wolfsssl.com + +[constraints] +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always +basicConstraints=CA:TRUE +nameConstraints=critical,permitted;dirName:dir_name + +[dir_name] +countryName = US + diff --git a/certs/test/cert-ext-ndir.der b/certs/test/cert-ext-ndir.der new file mode 100644 index 000000000..63f566bfc Binary files /dev/null and b/certs/test/cert-ext-ndir.der differ diff --git a/certs/test/gen-ext-certs.sh b/certs/test/gen-ext-certs.sh index 10b887133..e418157ab 100755 --- a/certs/test/gen-ext-certs.sh +++ b/certs/test/gen-ext-certs.sh @@ -2,8 +2,9 @@ TMP="/tmp/`basename $0`" +KEY=certs/server-key.der gen_cert() { - openssl req -x509 -keyform DER -key certs/server-key.der \ + openssl req -x509 -keyform DER -key $KEY \ -days 1000 -new -outform DER -out $OUT -config $CONFIG \ >$TMP 2>&1 @@ -96,3 +97,66 @@ nsComment = "Testing Netscape Certificate Type" EOF gen_cert +KEY=certs/ca-key.der +OUT=certs/test/cert-ext-ndir.der +KEYFILE=certs/ca-key.der +CONFIG=certs/test/cert-ext-ndir.cfg +tee >$CONFIG <$CONFIG <altEmailNames) FreeAltNames(cert->altEmailNames, cert->heap); + if (cert->altDirNames) + FreeAltNames(cert->altDirNames, cert->heap); if (cert->permittedNames) FreeNameSubtrees(cert->permittedNames, cert->heap); if (cert->excludedNames) @@ -7626,6 +7628,25 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert) base->nameSz) == 0) { return 0; } + #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 (cert->altDirNames != NULL) { + DNS_entry* cur = cert->altDirNames; + while (cur != NULL) { + if (XMEMCMP(cur->name, base->name, base->nameSz) + == 0) { + WOLFSSL_MSG("DIR alt name constraint err"); + return 0; + } + cur = cur->next; + } + } + #endif /* !WOLFSSL_NO_ASN_STRICT */ break; } }; /* switch */ @@ -7684,6 +7705,26 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert) XMEMCMP(cert->subjectRaw, base->name, base->nameSz) == 0) { matchDir = 1; + + #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 (cert->altDirNames != NULL) { + DNS_entry* cur = cert->altDirNames; + while (cur != NULL) { + if (XMEMCMP(cur->name, base->name, base->nameSz) + != 0) { + WOLFSSL_MSG("DIR alt name constraint err"); + matchDir = 0; /* did not match */ + } + cur = cur->next; + } + } + #endif /* !WOLFSSL_NO_ASN_STRICT */ } break; } @@ -7768,6 +7809,47 @@ static int DecodeAltNames(const byte* input, int sz, DecodedCert* cert) idx += strLen; } #ifndef IGNORE_NAME_CONSTRAINTS + else if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_DIR_TYPE)) { + DNS_entry* dirEntry; + int strLen; + word32 lenStartIdx = idx; + + if (GetLength(input, &idx, &strLen, sz) < 0) { + WOLFSSL_MSG("\tfail: str length"); + return ASN_PARSE_E; + } + + if (GetSequence(input, &idx, &strLen, sz) < 0) { + WOLFSSL_MSG("\tfail: seq length"); + return ASN_PARSE_E; + } + length -= (idx - lenStartIdx); + + dirEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap, + DYNAMIC_TYPE_ALTNAME); + if (dirEntry == NULL) { + WOLFSSL_MSG("\tOut of Memory"); + return MEMORY_E; + } + + dirEntry->type = ASN_DIR_TYPE; + dirEntry->name = (char*)XMALLOC(strLen + 1, cert->heap, + DYNAMIC_TYPE_ALTNAME); + if (dirEntry->name == NULL) { + WOLFSSL_MSG("\tOut of Memory"); + XFREE(dirEntry, cert->heap, DYNAMIC_TYPE_ALTNAME); + return MEMORY_E; + } + dirEntry->len = strLen; + XMEMCPY(dirEntry->name, &input[idx], strLen); + dirEntry->name[strLen] = '\0'; + + dirEntry->next = cert->altDirNames; + cert->altDirNames = dirEntry; + + length -= strLen; + idx += strLen; + } else if (b == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE)) { DNS_entry* emailEntry; int strLen; @@ -12659,7 +12741,11 @@ int FlattenAltNames(byte* output, word32 outputSz, const DNS_entry* names) curName = names; do { - output[idx++] = ASN_CONTEXT_SPECIFIC | curName->type; + output[idx] = ASN_CONTEXT_SPECIFIC | curName->type; + if (curName->type == ASN_DIR_TYPE) { + output[idx] |= ASN_CONSTRUCTED; + } + idx++; idx += SetLength(curName->len, output + idx); XMEMCPY(output + idx, curName->name, curName->len); idx += curName->len; diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index edb3d0d12..26eeee647 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -769,6 +769,7 @@ struct DecodedCert { DNS_entry* altNames; /* alt names list of dns entries */ #ifndef IGNORE_NAME_CONSTRAINTS DNS_entry* altEmailNames; /* alt names list of RFC822 entries */ + DNS_entry* altDirNames; /* alt names list of DIR entries */ Base_entry* permittedNames; /* Permitted name bases */ Base_entry* excludedNames; /* Excluded name bases */ #endif /* IGNORE_NAME_CONSTRAINTS */