From ea7ea356a0218195ba75fd57255c13aba0a0166f Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 6 Jul 2023 15:13:51 -0600 Subject: [PATCH 1/2] Fixes for WOLFSSL_X509 cert generation with key usage, extended key usage, and basic constraints --- src/ssl_asn1.c | 3 + src/x509.c | 52 +++++++++- tests/api.c | 33 ++++++- wolfcrypt/src/asn.c | 210 ++++++++++++++++++++++++---------------- wolfssl/wolfcrypt/asn.h | 8 ++ 5 files changed, 218 insertions(+), 88 deletions(-) diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index e9ece79df3..cb0b073eff 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -1606,6 +1606,9 @@ WOLFSSL_ASN1_OBJECT* wolfSSL_ASN1_OBJECT_dup(WOLFSSL_ASN1_OBJECT* obj) dupl->grp = obj->grp; dupl->nid = obj->nid; dupl->objSz = obj->objSz; + #ifdef OPENSSL_EXTRA + dupl->ca = obj->ca; + #endif /* Check for encoding. */ if (obj->obj) { /* Allocate memory for ASN.1 OBJECT_ID DER encoding. */ diff --git a/src/x509.c b/src/x509.c index 63ff45b1d8..97926c3209 100644 --- a/src/x509.c +++ b/src/x509.c @@ -1360,11 +1360,45 @@ int wolfSSL_X509_add_ext(WOLFSSL_X509 *x509, WOLFSSL_X509_EXTENSION *ext, int lo break; } case NID_key_usage: - if (ext && ext->value.data && - ext->value.length == sizeof(word16)) { - x509->keyUsage = *(word16*)ext->value.data; - x509->keyUsageCrit = (byte)ext->crit; - x509->keyUsageSet = 1; + if (ext && ext->value.data) { + if (ext->value.length == sizeof(word16)) { + /* if ext->value is already word16, set directly */ + x509->keyUsage = *(word16*)ext->value.data; + x509->keyUsageCrit = (byte)ext->crit; + x509->keyUsageSet = 1; + } + else if (ext->value.length > 0) { + /* ext->value is comma-delimited string, convert to word16 */ + if (ParseKeyUsageStr(ext->value.data, &x509->keyUsage, + x509->heap) != 0) { + return WOLFSSL_FAILURE; + } + x509->keyUsageCrit = (byte)ext->crit; + x509->keyUsageSet = 1; + } + else { + return WOLFSSL_FAILURE; + } + } + break; + case NID_ext_key_usage: + if (ext && ext->value.data) { + if (ext->value.length == sizeof(byte)) { + /* if ext->value is already word16, set directly */ + x509->extKeyUsage = *(byte*)ext->value.data; + x509->extKeyUsageCrit = (byte)ext->crit; + } + else if (ext->value.length > 0) { + /* ext->value is comma-delimited string, convert to word16 */ + if (ParseExtKeyUsageStr(ext->value.data, &x509->extKeyUsage, + x509->heap) != 0) { + return WOLFSSL_FAILURE; + } + x509->extKeyUsageCrit = (byte)ext->crit; + } + else { + return WOLFSSL_FAILURE; + } } break; case NID_basic_constraints: @@ -2781,6 +2815,14 @@ static WOLFSSL_X509_EXTENSION* createExtFromStr(int nid, const char *value) } ext->value.type = KEY_USAGE_OID; break; + case NID_ext_key_usage: + if (wolfSSL_ASN1_STRING_set(&ext->value, value, -1) + != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_ASN1_STRING_set error"); + goto err_cleanup; + } + ext->value.type = EXT_KEY_USAGE_OID; + break; default: WOLFSSL_MSG("invalid or unsupported NID"); goto err_cleanup; diff --git a/tests/api.c b/tests/api.c index 1fa2655ae5..79c4581a5e 100644 --- a/tests/api.c +++ b/tests/api.c @@ -46250,6 +46250,7 @@ static int test_wolfSSL_X509V3_EXT_nconf(void) "authorityKeyIdentifier", "subjectAltName", "keyUsage", + "extendedKeyUsage", }; size_t ext_names_count = sizeof(ext_names)/sizeof(*ext_names); int ext_nids[] = { @@ -46257,20 +46258,43 @@ static int test_wolfSSL_X509V3_EXT_nconf(void) NID_authority_key_identifier, NID_subject_alt_name, NID_key_usage, + NID_ext_key_usage, }; size_t ext_nids_count = sizeof(ext_nids)/sizeof(*ext_nids); const char *ext_values[] = { "hash", "hash", "DNS:example.com, IP:127.0.0.1", - "digitalSignature,keyEncipherment,dataEncipherment", + "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment," + "keyAgreement,keyCertSign,cRLSign,encipherOnly,decipherOnly", + "serverAuth,clientAuth,codeSigning,emailProtection,timeStamping," + "OCSPSigning", }; size_t i; X509_EXTENSION* ext = NULL; X509* x509 = NULL; + unsigned int keyUsageFlags; + unsigned int extKeyUsageFlags; ExpectNotNull(x509 = X509_new()); + /* keyUsage / extKeyUsage should match string above */ + keyUsageFlags = KU_DIGITAL_SIGNATURE + | KU_NON_REPUDIATION + | KU_KEY_ENCIPHERMENT + | KU_DATA_ENCIPHERMENT + | KU_KEY_AGREEMENT + | KU_KEY_CERT_SIGN + | KU_CRL_SIGN + | KU_ENCIPHER_ONLY + | KU_DECIPHER_ONLY; + extKeyUsageFlags = XKU_SSL_CLIENT + | XKU_SSL_SERVER + | XKU_CODE_SIGN + | XKU_SMIME + | XKU_TIMESTAMP + | XKU_OCSP_SIGN; + for (i = 0; i < ext_names_count; i++) { ExpectNotNull(ext = X509V3_EXT_nconf(NULL, NULL, ext_names[i], ext_values[i])); @@ -46290,6 +46314,13 @@ static int test_wolfSSL_X509V3_EXT_nconf(void) ExpectNotNull(ext = X509V3_EXT_nconf(NULL, NULL, ext_names[i], ext_values[i])); ExpectIntEQ(X509_add_ext(x509, ext, -1), WOLFSSL_SUCCESS); + + if (ext_nids[i] == NID_key_usage) { + ExpectIntEQ(X509_get_key_usage(x509), keyUsageFlags); + } + else if (ext_nids[i] == NID_ext_key_usage) { + ExpectIntEQ(X509_get_extended_key_usage(x509), extKeyUsageFlags); + } X509_EXTENSION_free(ext); ext = NULL; } diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 8373daee73..d032aa2416 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -26660,6 +26660,132 @@ int wc_EncodeNameCanonical(EncodedName* name, const char* nameStr, } #endif /* WOLFSSL_CERT_GEN || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ +#if (defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT)) || \ + (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) + +/* Convert key usage string (comma delimited, null terminated) to word16 + * Returns 0 on success, negative on error */ +int ParseKeyUsageStr(const char* value, word16* keyUsage, void* heap) +{ + int ret = 0; + char *token, *str, *ptr; + word32 len = 0; + word16 usage = 0; + + if (value == NULL || keyUsage == NULL) { + return BAD_FUNC_ARG; + } + + /* duplicate string (including terminator) */ + len = (word32)XSTRLEN(value); + str = (char*)XMALLOC(len + 1, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (str == NULL) { + return MEMORY_E; + } + XMEMCPY(str, value, len + 1); + + /* parse value, and set corresponding Key Usage value */ + if ((token = XSTRTOK(str, ",", &ptr)) == NULL) { + XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); + return KEYUSAGE_E; + } + while (token != NULL) { + if (!XSTRCASECMP(token, "digitalSignature")) + usage |= KEYUSE_DIGITAL_SIG; + else if (!XSTRCASECMP(token, "nonRepudiation") || + !XSTRCASECMP(token, "contentCommitment")) + usage |= KEYUSE_CONTENT_COMMIT; + else if (!XSTRCASECMP(token, "keyEncipherment")) + usage |= KEYUSE_KEY_ENCIPHER; + else if (!XSTRCASECMP(token, "dataEncipherment")) + usage |= KEYUSE_DATA_ENCIPHER; + else if (!XSTRCASECMP(token, "keyAgreement")) + usage |= KEYUSE_KEY_AGREE; + else if (!XSTRCASECMP(token, "keyCertSign")) + usage |= KEYUSE_KEY_CERT_SIGN; + else if (!XSTRCASECMP(token, "cRLSign")) + usage |= KEYUSE_CRL_SIGN; + else if (!XSTRCASECMP(token, "encipherOnly")) + usage |= KEYUSE_ENCIPHER_ONLY; + else if (!XSTRCASECMP(token, "decipherOnly")) + usage |= KEYUSE_DECIPHER_ONLY; + else { + ret = KEYUSAGE_E; + break; + } + + token = XSTRTOK(NULL, ",", &ptr); + } + + XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); + + if (ret == 0) { + *keyUsage = usage; + } + + return ret; +} + +/* Convert extended key usage string (comma delimited, null terminated) to byte + * Returns 0 on success, negative on error */ +int ParseExtKeyUsageStr(const char* value, byte* extKeyUsage, void* heap) +{ + int ret = 0; + char *token, *str, *ptr; + word32 len = 0; + byte usage = 0; + + if (value == NULL || extKeyUsage == NULL) { + return BAD_FUNC_ARG; + } + + /* duplicate string (including terminator) */ + len = (word32)XSTRLEN(value); + str = (char*)XMALLOC(len + 1, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (str == NULL) { + return MEMORY_E; + } + XMEMCPY(str, value, len + 1); + + /* parse value, and set corresponding Key Usage value */ + if ((token = XSTRTOK(str, ",", &ptr)) == NULL) { + XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); + return EXTKEYUSAGE_E; + } + while (token != NULL) { + if (!XSTRCASECMP(token, "any")) + usage |= EXTKEYUSE_ANY; + else if (!XSTRCASECMP(token, "serverAuth")) + usage |= EXTKEYUSE_SERVER_AUTH; + else if (!XSTRCASECMP(token, "clientAuth")) + usage |= EXTKEYUSE_CLIENT_AUTH; + else if (!XSTRCASECMP(token, "codeSigning")) + usage |= EXTKEYUSE_CODESIGN; + else if (!XSTRCASECMP(token, "emailProtection")) + usage |= EXTKEYUSE_EMAILPROT; + else if (!XSTRCASECMP(token, "timeStamping")) + usage |= EXTKEYUSE_TIMESTAMP; + else if (!XSTRCASECMP(token, "OCSPSigning")) + usage |= EXTKEYUSE_OCSP_SIGN; + else { + ret = EXTKEYUSAGE_E; + break; + } + + token = XSTRTOK(NULL, ",", &ptr); + } + + XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); + + if (ret == 0) { + *extKeyUsage = usage; + } + + return ret; +} + +#endif /* (CERT_GEN && CERT_EXT) || (OPENSSL_ALL || OPENSSL_EXTRA) */ + #ifdef WOLFSSL_CERT_GEN /* Encodes one attribute of the name (issuer/subject) * call we_EncodeName_ex with 0x16, IA5String for email type @@ -30484,56 +30610,14 @@ int wc_SetAuthKeyId(Cert *cert, const char* file) int wc_SetKeyUsage(Cert *cert, const char *value) { int ret = 0; - char *token, *str, *ptr; - word32 len; if (cert == NULL || value == NULL) return BAD_FUNC_ARG; cert->keyUsage = 0; - /* duplicate string (including terminator) */ - len = (word32)XSTRLEN(value); - str = (char*)XMALLOC(len+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (str == NULL) - return MEMORY_E; - XMEMCPY(str, value, len+1); - - /* parse value, and set corresponding Key Usage value */ - if ((token = XSTRTOK(str, ",", &ptr)) == NULL) { - XFREE(str, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); - return KEYUSAGE_E; - } - while (token != NULL) - { - if (!XSTRCASECMP(token, "digitalSignature")) - cert->keyUsage |= KEYUSE_DIGITAL_SIG; - else if (!XSTRCASECMP(token, "nonRepudiation") || - !XSTRCASECMP(token, "contentCommitment")) - cert->keyUsage |= KEYUSE_CONTENT_COMMIT; - else if (!XSTRCASECMP(token, "keyEncipherment")) - cert->keyUsage |= KEYUSE_KEY_ENCIPHER; - else if (!XSTRCASECMP(token, "dataEncipherment")) - cert->keyUsage |= KEYUSE_DATA_ENCIPHER; - else if (!XSTRCASECMP(token, "keyAgreement")) - cert->keyUsage |= KEYUSE_KEY_AGREE; - else if (!XSTRCASECMP(token, "keyCertSign")) - cert->keyUsage |= KEYUSE_KEY_CERT_SIGN; - else if (!XSTRCASECMP(token, "cRLSign")) - cert->keyUsage |= KEYUSE_CRL_SIGN; - else if (!XSTRCASECMP(token, "encipherOnly")) - cert->keyUsage |= KEYUSE_ENCIPHER_ONLY; - else if (!XSTRCASECMP(token, "decipherOnly")) - cert->keyUsage |= KEYUSE_DECIPHER_ONLY; - else { - ret = KEYUSAGE_E; - break; - } - - token = XSTRTOK(NULL, ",", &ptr); - } + ret = ParseKeyUsageStr(value, &cert->keyUsage, cert->heap); - XFREE(str, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } @@ -30541,52 +30625,14 @@ int wc_SetKeyUsage(Cert *cert, const char *value) int wc_SetExtKeyUsage(Cert *cert, const char *value) { int ret = 0; - char *token, *str, *ptr; - word32 len; if (cert == NULL || value == NULL) return BAD_FUNC_ARG; cert->extKeyUsage = 0; - /* duplicate string (including terminator) */ - len = (word32)XSTRLEN(value); - str = (char*)XMALLOC(len+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (str == NULL) - return MEMORY_E; - XMEMCPY(str, value, len+1); - - /* parse value, and set corresponding Key Usage value */ - if ((token = XSTRTOK(str, ",", &ptr)) == NULL) { - XFREE(str, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); - return EXTKEYUSAGE_E; - } - - while (token != NULL) - { - if (!XSTRCASECMP(token, "any")) - cert->extKeyUsage |= EXTKEYUSE_ANY; - else if (!XSTRCASECMP(token, "serverAuth")) - cert->extKeyUsage |= EXTKEYUSE_SERVER_AUTH; - else if (!XSTRCASECMP(token, "clientAuth")) - cert->extKeyUsage |= EXTKEYUSE_CLIENT_AUTH; - else if (!XSTRCASECMP(token, "codeSigning")) - cert->extKeyUsage |= EXTKEYUSE_CODESIGN; - else if (!XSTRCASECMP(token, "emailProtection")) - cert->extKeyUsage |= EXTKEYUSE_EMAILPROT; - else if (!XSTRCASECMP(token, "timeStamping")) - cert->extKeyUsage |= EXTKEYUSE_TIMESTAMP; - else if (!XSTRCASECMP(token, "OCSPSigning")) - cert->extKeyUsage |= EXTKEYUSE_OCSP_SIGN; - else { - ret = EXTKEYUSAGE_E; - break; - } - - token = XSTRTOK(NULL, ",", &ptr); - } + ret = ParseExtKeyUsageStr(value, &cert->extKeyUsage, cert->heap); - XFREE(str, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 29d5df388b..342b154ac7 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2287,6 +2287,14 @@ WOLFSSL_LOCAL int PemToDer(const unsigned char* buff, long sz, int type, WOLFSSL_LOCAL int AllocDer(DerBuffer** der, word32 length, int type, void* heap); WOLFSSL_LOCAL void FreeDer(DerBuffer** der); +#if (defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT)) || \ + (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) +WOLFSSL_LOCAL int ParseKeyUsageStr(const char* value, word16* keyUsage, + void* heap); +WOLFSSL_LOCAL int ParseExtKeyUsageStr(const char* value, byte* extKeyUsage, + void* heap); +#endif /* (CERT_GEN && CERT_EXT) || (OPENSSL_ALL || OPENSSL_EXTRA) */ + #endif /* !NO_CERTS */ #ifdef HAVE_SMIME From a8ed78e012dd8ab980d0e27f8faf66862d3c6e6f Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 6 Jul 2023 15:06:32 -0600 Subject: [PATCH 2/2] define WOLFSSL_ALT_NAMES in --enable-jni build --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index b20f5b7f08..46dfa81d47 100644 --- a/configure.ac +++ b/configure.ac @@ -5839,6 +5839,9 @@ then ENABLED_ALPN="yes" AM_CFLAGS="$AM_CFLAGS -DHAVE_ALPN" fi + + # cert gen requires alt names + ENABLED_ALTNAMES="yes" fi if test "$ENABLED_LIGHTY" = "yes"