From 78a20ec3ae3e97d3538f5bcf23f47577f96fd488 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 14 Sep 2020 17:05:25 +0200 Subject: [PATCH] Extension manipulation --- configure.ac | 2 +- src/internal.c | 1 + src/ssl.c | 207 +++++++++++++++++++++++++++--------------- wolfcrypt/src/asn.c | 25 +++++ wolfssl/internal.h | 1 + wolfssl/openssl/ssl.h | 2 +- wolfssl/ssl.h | 1 + 7 files changed, 163 insertions(+), 76 deletions(-) diff --git a/configure.ac b/configure.ac index 51b6a04c2..842fe1563 100644 --- a/configure.ac +++ b/configure.ac @@ -4250,7 +4250,7 @@ AC_ARG_ENABLE([libest], if test "$ENABLED_LIBEST" = "yes" then - AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA -DHAVE_LIBEST" + AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA -DHAVE_LIBEST -DWOLFSSL_ALT_NAMES" # Requires opensslextra and opensslall if test "x$ENABLED_OPENSSLALL" = "xno" && test "x$ENABLED_OPENSSLCOEXIST" = "xno" diff --git a/src/internal.c b/src/internal.c index 62bbeaa8c..365d13174 100644 --- a/src/internal.c +++ b/src/internal.c @@ -9568,6 +9568,7 @@ int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert) x509->subjectCN[0] = '\0'; #ifdef WOLFSSL_CERT_REQ + x509->isCSR = dCert->isCSR; /* CSR attributes */ if (dCert->cPwd) { if (dCert->cPwdLen < CTC_NAME_SIZE) { diff --git a/src/ssl.c b/src/ssl.c index 7357b5bce..0ad142dca 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -8065,7 +8065,8 @@ int wolfSSL_X509_get_ext_count(const WOLFSSL_X509* passedCert) } InitDecodedCert(&cert, rawCert, (word32)outSz, 0); - if (ParseCert(&cert, CA_TYPE, NO_VERIFY, NULL) < 0) { + if (ParseCert(&cert, passedCert->isCSR ? CERTREQ_TYPE : CA_TYPE, + NO_VERIFY, NULL) < 0) { WOLFSSL_MSG("\tCertificate parsing failed"); return WOLFSSL_FAILURE; } @@ -8079,16 +8080,18 @@ int wolfSSL_X509_get_ext_count(const WOLFSSL_X509* passedCert) return WOLFSSL_FAILURE; } - if (input[idx++] != ASN_EXTENSIONS) { - WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); - FreeDecodedCert(&cert); - return WOLFSSL_FAILURE; - } + if (!passedCert->isCSR) { + if (input[idx++] != ASN_EXTENSIONS) { + WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); + FreeDecodedCert(&cert); + return WOLFSSL_FAILURE; + } - if (GetLength(input, &idx, &length, sz) < 0) { - WOLFSSL_MSG("\tfail: invalid length"); - FreeDecodedCert(&cert); - return WOLFSSL_FAILURE; + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: invalid length"); + FreeDecodedCert(&cert); + return WOLFSSL_FAILURE; + } } if (GetSequence(input, &idx, &length, sz) < 0) { @@ -8295,6 +8298,17 @@ const WOLFSSL_STACK *wolfSSL_X509_get0_extensions(const WOLFSSL_X509 *x) return x509->ext_sk_full; } +/** + * Caller is responsible for freeing the returned stack. + */ +const WOLFSSL_STACK *wolfSSL_X509_REQ_get_extensions(const WOLFSSL_X509 *x) +{ + const WOLFSSL_STACK *ret = wolfSSL_X509_get0_extensions(x); + if (x) + ((WOLFSSL_X509*)x)->ext_sk_full = NULL; + return ret; +} + /* Gets the X509_EXTENSION* ext based on it's location in WOLFSSL_X509* x509. * * x509 : The X509 structure to look for the extension. @@ -8389,7 +8403,8 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509_set_ext(WOLFSSL_X509* x509, int loc) InitDecodedCert( &cert, rawCert, (word32)outSz, 0); - if (ParseCert(&cert, CA_TYPE, NO_VERIFY, NULL) < 0) { + if (ParseCert(&cert, x509->isCSR ? CERTREQ_TYPE : CA_TYPE, + NO_VERIFY, NULL) < 0) { WOLFSSL_MSG("\tCertificate parsing failed"); wolfSSL_X509_EXTENSION_free(ext); return NULL; @@ -8405,18 +8420,20 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509_set_ext(WOLFSSL_X509* x509, int loc) return NULL; } - if (input[idx++] != ASN_EXTENSIONS) { - WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); - wolfSSL_X509_EXTENSION_free(ext); - FreeDecodedCert(&cert); - return NULL; - } + if (!x509->isCSR) { + if (input[idx++] != ASN_EXTENSIONS) { + WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } - if (GetLength(input, &idx, &length, sz) < 0) { - WOLFSSL_MSG("\tfail: invalid length"); - wolfSSL_X509_EXTENSION_free(ext); - FreeDecodedCert(&cert); - return NULL; + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: invalid length"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } } if (GetSequence(input, &idx, &length, sz) < 0) { @@ -9299,7 +9316,8 @@ int wolfSSL_X509_get_ext_by_NID(const WOLFSSL_X509* x509, int nid, int lastPos) InitDecodedCert( &cert, rawCert, (word32)outSz, 0); - if (ParseCert(&cert, CA_TYPE, NO_VERIFY, NULL) < 0) { + if (ParseCert(&cert, x509->isCSR ? CERTREQ_TYPE : CA_TYPE, + NO_VERIFY, NULL) < 0) { WOLFSSL_MSG("\tCertificate parsing failed"); return WOLFSSL_FATAL_ERROR; } @@ -9313,16 +9331,18 @@ int wolfSSL_X509_get_ext_by_NID(const WOLFSSL_X509* x509, int nid, int lastPos) return WOLFSSL_FATAL_ERROR; } - if (input[idx++] != ASN_EXTENSIONS) { - WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); - FreeDecodedCert(&cert); - return WOLFSSL_FATAL_ERROR; - } + if (!x509->isCSR) { + if (input[idx++] != ASN_EXTENSIONS) { + WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); + FreeDecodedCert(&cert); + return WOLFSSL_FATAL_ERROR; + } - if (GetLength(input, &idx, &length, sz) < 0) { - WOLFSSL_MSG("\tfail: invalid length"); - FreeDecodedCert(&cert); - return WOLFSSL_FATAL_ERROR; + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: invalid length"); + FreeDecodedCert(&cert); + return WOLFSSL_FATAL_ERROR; + } } if (GetSequence(input, &idx, &length, sz) < 0) { @@ -9892,16 +9912,59 @@ int wolfSSL_X509_add_altname(WOLFSSL_X509* x509, const char* name, int type) } -#ifndef NO_WOLFSSL_STUB int wolfSSL_X509_add_ext(WOLFSSL_X509 *x509, WOLFSSL_X509_EXTENSION *ext, int loc) { - WOLFSSL_STUB("wolfSSL_X509_add_ext"); - (void)x509; - (void)ext; - (void)loc; - return WOLFSSL_FAILURE; + WOLFSSL_ENTER("wolfSSL_X509_add_ext"); + + if (!x509 || !ext || !ext->obj || loc >= 0) { + WOLFSSL_MSG("Bad parameter"); + return WOLFSSL_FAILURE; + } + + switch (ext->obj->type) { + case NID_subject_alt_name: + { + WOLFSSL_GENERAL_NAMES* gns = ext->ext_sk; + while (gns) { + WOLFSSL_GENERAL_NAME* gn = gns->data.gn; + if (!gn || !gn->d.ia5 || + wolfSSL_X509_add_altname_ex(x509, gn->d.ia5->data, + gn->d.ia5->length, gn->type) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Subject alternative name missing extension"); + return WOLFSSL_FAILURE; + } + gns = gns->next; + } + x509->subjAltNameSet = 1; + x509->subjAltNameCrit = ext->crit; + break; + } + case NID_key_usage: + if (ext && ext->value.data && + ext->value.length == sizeof(word16)) { + x509->keyUsage = *(word16*)ext->value.data; + x509->keyUsageCrit = ext->crit; + x509->keyUsageSet = 1; + } + break; + case NID_basic_constraints: + if (ext->obj) { + x509->isCa = ext->obj->ca; + x509->basicConstCrit = ext->crit; + if (ext->obj->pathlen) + x509->pathLength = ext->obj->pathlen->length; + x509->basicConstSet = 1; + } + break; + default: + WOLFSSL_MSG("Unsupported extension to add"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; } +#ifndef NO_WOLFSSL_STUB WOLFSSL_X509_EXTENSION *wolfSSL_X509_delete_ext(WOLFSSL_X509 *x509, int loc) { WOLFSSL_STUB("wolfSSL_X509_delete_ext"); @@ -39366,6 +39429,10 @@ void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) XMEMCPY(cert->challengePw, req->challengePw, CTC_NAME_SIZE); cert->challengePwPrintableString = req->challengePw[0] != 0; #endif + #ifdef WOLFSSL_ALT_NAMES + cert->altNamesSz = FlattenAltNames(cert->altNames, + sizeof(cert->altNames), req->altNames); + #endif /* WOLFSSL_ALT_NAMES */ } return ret; @@ -51586,6 +51653,31 @@ int wolfSSL_X509_REQ_sign_ctx(WOLFSSL_X509 *req, return WOLFSSL_FAILURE; } +static int wolfSSL_regen_X509_REQ_der_buffer(WOLFSSL_X509* x509) +{ + byte der[4096]; + int derSz = sizeof(der); + + if (wolfSSL_X509_make_der(x509, 1, der, &derSz, 0) != + WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Unable to make DER for X509 REQ"); + return WOLFSSL_FAILURE; + } + + FreeDer(&x509->derCert); + + /* store cert for potential retrieval */ + if (AllocDer(&x509->derCert, derSz, CERT_TYPE, x509->heap) == 0) { + XMEMCPY(x509->derCert->buffer, der, derSz); + } + else { + WOLFSSL_MSG("Failed to allocate DER buffer for X509"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + int wolfSSL_X509_REQ_add_extensions(WOLFSSL_X509* req, WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)* ext_sk) { @@ -51597,48 +51689,15 @@ int wolfSSL_X509_REQ_add_extensions(WOLFSSL_X509* req, while (ext_sk) { WOLFSSL_X509_EXTENSION* ext = ext_sk->data.ext; - switch (ext->obj->type) { - case NID_subject_alt_name: - { - WOLFSSL_GENERAL_NAMES* gns = ext->ext_sk; - while (gns) { - WOLFSSL_GENERAL_NAME* gn = gns->data.gn; - if (!gn || !gn->d.ia5 || - wolfSSL_X509_add_altname_ex(req, gn->d.ia5->data, - gn->d.ia5->length, gn->type) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Subject alternative name missing extension"); - return WOLFSSL_FAILURE; - } - gns = gns->next; - } - req->subjAltNameSet = 1; - req->subjAltNameCrit = ext->crit; - break; - } - case NID_key_usage: - if (ext && ext->value.data && - ext->value.length == sizeof(word16)) { - req->keyUsage = *(word16*)ext->value.data; - req->keyUsageCrit = ext->crit; - } - break; - case NID_basic_constraints: - if (ext->obj) { - req->isCa = ext->obj->ca; - req->basicConstCrit = ext->crit; - if (ext->obj->pathlen) - req->pathLength = ext->obj->pathlen->length; - } - break; - default: - WOLFSSL_MSG("Unsupported extension to add"); + if (wolfSSL_X509_add_ext(req, ext, -1) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_X509_add_ext error"); return WOLFSSL_FAILURE; } ext_sk = ext_sk->next; } - return WOLFSSL_SUCCESS; + return wolfSSL_regen_X509_REQ_der_buffer(req); } #ifndef NO_WOLFSSL_STUB int wolfSSL_X509_REQ_add1_attr_by_txt(WOLFSSL_X509 *req, diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index dc44a3b8b..1fe8c09d8 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -14259,6 +14259,20 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, else der->caSz = 0; +#ifdef WOLFSSL_ALT_NAMES + /* Alternative Name */ + if (cert->altNamesSz) { + der->altNamesSz = SetAltNames(der->altNames, sizeof(der->altNames), + cert->altNames, cert->altNamesSz); + if (der->altNamesSz <= 0) + return ALT_NAME_E; + + der->extensionsSz += der->altNamesSz; + } + else + der->altNamesSz = 0; +#endif + #ifdef WOLFSSL_CERT_EXT /* SKID */ if (cert->skidSz) { @@ -14320,6 +14334,17 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, return EXTENSIONS_E; } +#ifdef WOLFSSL_ALT_NAMES + /* put Alternative Names */ + if (der->altNamesSz) { + ret = SetExtensions(der->extensions, sizeof(der->extensions), + &der->extensionsSz, + der->altNames, der->altNamesSz); + if (ret <= 0) + return EXTENSIONS_E; + } +#endif + #ifdef WOLFSSL_CERT_EXT /* put SKID */ if (der->skidSz) { diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 53d2c1545..fc42030de 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3760,6 +3760,7 @@ struct WOLFSSL_X509 { byte authKeyIdSet:1; byte authKeyIdCrit:1; byte issuerSet:1; + byte isCSR:1; #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ byte serial[EXTERNAL_SERIAL_SIZE]; char subjectCN[ASN_NAME_MAX]; /* common name short cut */ diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index ee4aecfa1..6665aaf47 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -406,7 +406,7 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define X509V3_EXT_i2d wolfSSL_X509V3_EXT_i2d #define X509_get0_extensions wolfSSL_X509_get0_extensions #define X509_get_extensions wolfSSL_X509_get0_extensions -#define X509_REQ_get_extensions wolfSSL_X509_get0_extensions +#define X509_REQ_get_extensions wolfSSL_X509_REQ_get_extensions #define X509_get_ext wolfSSL_X509_get_ext #define X509_get_ext_by_NID wolfSSL_X509_get_ext_by_NID #define X509_get_issuer_name wolfSSL_X509_get_issuer_name diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index be30dff38..81482cec2 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3429,6 +3429,7 @@ WOLFSSL_API int wolfSSL_CTX_use_PrivateKey_ASN1(int pri, WOLFSSL_CTX* ctx, #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) WOLFSSL_API int wolfSSL_X509_cmp(const WOLFSSL_X509* a, const WOLFSSL_X509* b); WOLFSSL_API const WOLFSSL_STACK *wolfSSL_X509_get0_extensions(const WOLFSSL_X509 *x); +WOLFSSL_API const WOLFSSL_STACK *wolfSSL_X509_REQ_get_extensions(const WOLFSSL_X509 *x); WOLFSSL_API WOLFSSL_X509_EXTENSION* wolfSSL_X509_get_ext(const WOLFSSL_X509* x, int loc); WOLFSSL_API int wolfSSL_X509_get_ext_by_OBJ(const WOLFSSL_X509 *x, const WOLFSSL_ASN1_OBJECT *obj, int lastpos);