diff --git a/src/ssl.c b/src/ssl.c index 689e4579b..3a8cb62ad 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -23867,11 +23867,10 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) return WOLFSSL_FATAL_ERROR; } - /* Use the public key to verify the signature. Note: this only verifies * the certificate signature. * returns WOLFSSL_SUCCESS on successful signature verification */ -int wolfSSL_X509_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey) +static int wolfSSL_X509_X509_REQ_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey, int req) { int ret; const byte* der; @@ -23906,13 +23905,31 @@ int wolfSSL_X509_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey) return WOLFSSL_FATAL_ERROR; } - ret = CheckCertSignaturePubKey(der, derSz, x509->heap, - (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, type); +#ifdef WOLFSSL_CERT_REQ + if (req) + ret = CheckCSRSignaturePubKey(der, derSz, x509->heap, + (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, type); + else +#endif + ret = CheckCertSignaturePubKey(der, derSz, x509->heap, + (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, type); if (ret == 0) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } + +int wolfSSL_X509_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey) +{ + return wolfSSL_X509_X509_REQ_verify(x509, pkey, 0); +} + +#ifdef WOLFSSL_CERT_REQ +int wolfSSL_X509_REQ_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey) +{ + return wolfSSL_X509_X509_REQ_verify(x509, pkey, 1); +} +#endif /* WOLFSSL_CERT_REQ */ #endif /* !NO_CERTS */ #if !defined(NO_FILESYSTEM) @@ -49644,7 +49661,8 @@ int wolfSSL_X509_set_serialNumber(WOLFSSL_X509* x509, WOLFSSL_ASN1_INTEGER* s) int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey) { - byte* p; + byte* p = NULL; + int pLen; WOLFSSL_ENTER("wolfSSL_X509_set_pubkey"); if (cert == NULL || pkey == NULL) @@ -49657,15 +49675,29 @@ int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey) else return WOLFSSL_FAILURE; - p = (byte*)XMALLOC(pkey->pkey_sz, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); - if (p == NULL) - return WOLFSSL_FAILURE; + if (pkey->type == EVP_PKEY_RSA) { + /* Public and private key formats differ. Make sure to put in the + * public key format in the cert. */ + if ((pLen = wolfSSL_i2d_RSAPublicKey(pkey->rsa, (const byte**)&p)) <= 0) { + WOLFSSL_MSG("wolfSSL_i2d_RSAPublicKey error"); + return WOLFSSL_FAILURE; + } + if (cert->pubKey.buffer != NULL) + XFREE(cert->pubKey.buffer, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); + cert->pubKey.buffer = p; + cert->pubKey.length = pLen; + } + else { + p = (byte*)XMALLOC(pkey->pkey_sz, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (p == NULL) + return WOLFSSL_FAILURE; - if (cert->pubKey.buffer != NULL) - XFREE(cert->pubKey.buffer, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); - cert->pubKey.buffer = p; - XMEMCPY(cert->pubKey.buffer, pkey->pkey.ptr, pkey->pkey_sz); - cert->pubKey.length = pkey->pkey_sz; + if (cert->pubKey.buffer != NULL) + XFREE(cert->pubKey.buffer, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); + cert->pubKey.buffer = p; + XMEMCPY(cert->pubKey.buffer, pkey->pkey.ptr, pkey->pkey_sz); + cert->pubKey.length = pkey->pkey_sz; + } return WOLFSSL_SUCCESS; } diff --git a/tests/api.c b/tests/api.c index c4e0a07a7..3e1d5dce6 100644 --- a/tests/api.c +++ b/tests/api.c @@ -37884,12 +37884,23 @@ static void test_wolfSSL_d2i_X509_REQ(void) { const char* csrFile = "./csr.signed.der"; BIO* bio = NULL; - X509* x509 = NULL; + X509* req = NULL; + EVP_PKEY *pub_key = NULL; AssertNotNull(bio = BIO_new_file(csrFile, "rb")); - AssertNotNull(d2i_X509_REQ_bio(bio, &x509)); + AssertNotNull(d2i_X509_REQ_bio(bio, &req)); - X509_free(x509); + /* + * Extract the public key from the CSR + */ + AssertNotNull(pub_key = X509_REQ_get_pubkey(req)); + + /* + * Verify the signature in the CSR + */ + AssertIntEQ(X509_REQ_verify(req, pub_key), 1); + + X509_free(req); BIO_free(bio); } diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index c09ceb269..efbdc078a 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -9093,6 +9093,7 @@ static Signer* GetCABySubjectAndPubKey(DecodedCert* cert, void* cm) /* Only quick step through the certificate to find fields that are then used * in certificate signature verification. * Must use the signature OID from the signed part of the certificate. + * Works also on certificate signing requests. * * This is only for minimizing dynamic memory usage during TLS certificate * chain processing. @@ -9100,7 +9101,7 @@ static Signer* GetCABySubjectAndPubKey(DecodedCert* cert, void* cm) * OCSP Only: alt lookup using subject and pub key w/o sig check */ static int CheckCertSignature_ex(const byte* cert, word32 certSz, void* heap, - void* cm, const byte* pubKey, word32 pubKeySz, int pubKeyOID) + void* cm, const byte* pubKey, word32 pubKeySz, int pubKeyOID, int req) { #ifndef WOLFSSL_SMALL_STACK SignatureCtx sigCtx[1]; @@ -9177,13 +9178,14 @@ static int CheckCertSignature_ex(const byte* cert, word32 certSz, void* heap, idx += len; /* signature */ - if (GetAlgoId(cert, &idx, &signatureOID, oidSigType, certSz) < 0) + if (!req && + GetAlgoId(cert, &idx, &signatureOID, oidSigType, certSz) < 0) ret = ASN_PARSE_E; } if (ret == 0) { issuerIdx = idx; - /* issuer */ + /* issuer for cert or subject for csr */ if (GetSequence(cert, &idx, &len, certSz) < 0) ret = ASN_PARSE_E; } @@ -9191,14 +9193,14 @@ static int CheckCertSignature_ex(const byte* cert, word32 certSz, void* heap, issuerSz = len + idx - issuerIdx; } #ifndef NO_SKID - if (ret == 0) { + if (!req && ret == 0) { idx += len; /* validity */ if (GetSequence(cert, &idx, &len, certSz) < 0) ret = ASN_PARSE_E; } - if (ret == 0) { + if (!req && ret == 0) { idx += len; /* subject */ @@ -9212,123 +9214,137 @@ static int CheckCertSignature_ex(const byte* cert, word32 certSz, void* heap, if (GetSequence(cert, &idx, &len, certSz) < 0) ret = ASN_PARSE_E; } - if (ret == 0) { + if (req && ret == 0) { idx += len; - if ((idx + 1) > certSz) - ret = BUFFER_E; - } - if (ret == 0) { - /* issuerUniqueID - optional */ - localIdx = idx; - if (GetASNTag(cert, &localIdx, &tag, certSz) == 0) { - if (tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) { - idx++; - if (GetLength(cert, &idx, &len, certSz) < 0) - ret = ASN_PARSE_E; - idx += len; - } - } - } - if (ret == 0) { - if ((idx + 1) > certSz) - ret = BUFFER_E; - } - if (ret == 0) { - /* subjectUniqueID - optional */ - localIdx = idx; - if (GetASNTag(cert, &localIdx, &tag, certSz) == 0) { - if (tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 2)) { - idx++; - if (GetLength(cert, &idx, &len, certSz) < 0) - ret = ASN_PARSE_E; - idx += len; - } - } - } - - if (ret == 0) { - if ((idx + 1) > certSz) - ret = BUFFER_E; - } - /* extensions - optional */ - localIdx = idx; - if (ret == 0 && GetASNTag(cert, &localIdx, &tag, certSz) == 0 && - tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 3)) { - idx++; - if (GetLength(cert, &idx, &extLen, certSz) < 0) + /* attributes */ + if (GetASNHeader_ex(cert, + ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED, &idx, + &len, certSz, 1) < 0) ret = ASN_PARSE_E; + } + if (!req) { if (ret == 0) { - if (GetSequence(cert, &idx, &extLen, certSz) < 0) - ret = ASN_PARSE_E; + idx += len; + + if ((idx + 1) > certSz) + ret = BUFFER_E; } if (ret == 0) { - extEndIdx = idx + extLen; - - /* Check each extension for the ones we want. */ - while (ret == 0 && idx < extEndIdx) { - if (GetSequence(cert, &idx, &len, certSz) < 0) - ret = ASN_PARSE_E; - if (ret == 0) { - extIdx = idx; - if (GetObjectId(cert, &extIdx, &oid, oidCertExtType, - certSz) < 0) { + /* issuerUniqueID - optional */ + localIdx = idx; + if (GetASNTag(cert, &localIdx, &tag, certSz) == 0) { + if (tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) { + idx++; + if (GetLength(cert, &idx, &len, certSz) < 0) ret = ASN_PARSE_E; + idx += len; + } + } + } + if (ret == 0) { + if ((idx + 1) > certSz) + ret = BUFFER_E; + } + if (ret == 0) { + /* subjectUniqueID - optional */ + localIdx = idx; + if (GetASNTag(cert, &localIdx, &tag, certSz) == 0) { + if (tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 2)) { + idx++; + if (GetLength(cert, &idx, &len, certSz) < 0) + ret = ASN_PARSE_E; + idx += len; + } + } + } + + if (ret == 0) { + if ((idx + 1) > certSz) + ret = BUFFER_E; + } + /* extensions - optional */ + localIdx = idx; + if (ret == 0 && GetASNTag(cert, &localIdx, &tag, certSz) == 0 && + tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 3)) { + idx++; + if (GetLength(cert, &idx, &extLen, certSz) < 0) + ret = ASN_PARSE_E; + if (ret == 0) { + if (GetSequence(cert, &idx, &extLen, certSz) < 0) + ret = ASN_PARSE_E; + } + if (ret == 0) { + extEndIdx = idx + extLen; + + /* Check each extension for the ones we want. */ + while (ret == 0 && idx < extEndIdx) { + if (GetSequence(cert, &idx, &len, certSz) < 0) + ret = ASN_PARSE_E; + if (ret == 0) { + extIdx = idx; + if (GetObjectId(cert, &extIdx, &oid, oidCertExtType, + certSz) < 0) { + ret = ASN_PARSE_E; + } + + if (ret == 0) { + if ((extIdx + 1) > certSz) + ret = BUFFER_E; + } } if (ret == 0) { - if ((extIdx + 1) > certSz) - ret = BUFFER_E; - } - } - - if (ret == 0) { - localIdx = extIdx; - if (GetASNTag(cert, &localIdx, &tag, certSz) == 0 && - tag == ASN_BOOLEAN) { - if (GetBoolean(cert, &extIdx, certSz) < 0) - ret = ASN_PARSE_E; - } - } - if (ret == 0) { - if (GetOctetString(cert, &extIdx, &extLen, certSz) < 0) - ret = ASN_PARSE_E; - } - - if (ret == 0) { - switch (oid) { - case AUTH_KEY_OID: - if (GetSequence(cert, &extIdx, &extLen, certSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0 && (extIdx + 1) >= certSz) - ret = BUFFER_E; - - if (ret == 0 && - GetASNTag(cert, &extIdx, &tag, certSz) == 0 && - tag == (ASN_CONTEXT_SPECIFIC | 0)) { - if (GetLength(cert, &extIdx, &extLen, certSz) <= 0) + localIdx = extIdx; + if (GetASNTag(cert, &localIdx, &tag, certSz) == 0 && + tag == ASN_BOOLEAN) { + if (GetBoolean(cert, &extIdx, certSz) < 0) ret = ASN_PARSE_E; - if (ret == 0) { - extAuthKeyIdSet = 1; - if (extLen == KEYID_SIZE) - XMEMCPY(hash, cert + extIdx, extLen); - else { - ret = CalcHashId(cert + extIdx, extLen, - hash); + } + } + if (ret == 0) { + if (GetOctetString(cert, &extIdx, &extLen, certSz) < 0) + ret = ASN_PARSE_E; + } + + if (ret == 0) { + switch (oid) { + case AUTH_KEY_OID: + if (GetSequence(cert, &extIdx, &extLen, certSz) < 0) + ret = ASN_PARSE_E; + + if (ret == 0 && (extIdx + 1) >= certSz) + ret = BUFFER_E; + + if (ret == 0 && + GetASNTag(cert, &extIdx, &tag, certSz) == 0 && + tag == (ASN_CONTEXT_SPECIFIC | 0)) { + if (GetLength(cert, &extIdx, &extLen, certSz) <= 0) + ret = ASN_PARSE_E; + if (ret == 0) { + extAuthKeyIdSet = 1; + if (extLen == KEYID_SIZE) + XMEMCPY(hash, cert + extIdx, extLen); + else { + ret = CalcHashId(cert + extIdx, extLen, + hash); + } } } - } - break; + break; - default: - break; + default: + break; + } } + idx += len; } - idx += len; } } } + else if (ret == 0) { + idx += len; + } if (ret == 0 && pubKey == NULL) { if (extAuthKeyIdSet) @@ -9354,6 +9370,9 @@ static int CheckCertSignature_ex(const byte* cert, word32 certSz, void* heap, /* signatureAlgorithm */ if (GetAlgoId(cert, &idx, &oid, oidSigType, certSz) < 0) ret = ASN_PARSE_E; + /* In CSR signature data is not present in body */ + if (req) + signatureOID = oid; } if (ret == 0) { if (oid != signatureOID) @@ -9398,15 +9417,23 @@ int CheckCertSignaturePubKey(const byte* cert, word32 certSz, void* heap, const byte* pubKey, word32 pubKeySz, int pubKeyOID) { return CheckCertSignature_ex(cert, certSz, heap, NULL, - pubKey, pubKeySz, pubKeyOID); + pubKey, pubKeySz, pubKeyOID, 0); } +#ifdef WOLFSSL_CERT_REQ +int CheckCSRSignaturePubKey(const byte* cert, word32 certSz, void* heap, + const byte* pubKey, word32 pubKeySz, int pubKeyOID) +{ + return CheckCertSignature_ex(cert, certSz, heap, NULL, + pubKey, pubKeySz, pubKeyOID, 1); +} +#endif /* WOLFSSL_CERT_REQ */ #endif /* OPENSSL_EXTRA */ #ifdef WOLFSSL_SMALL_CERT_VERIFY /* Call CheckCertSignature_ex using a certificate manager (cm) */ int CheckCertSignature(const byte* cert, word32 certSz, void* heap, void* cm) { - return CheckCertSignature_ex(cert, certSz, heap, cm, NULL, 0, 0); + return CheckCertSignature_ex(cert, certSz, heap, cm, NULL, 0, 0, 0); } #endif /* WOLFSSL_SMALL_CERT_VERIFY */ #endif /* WOLFSSL_SMALL_CERT_VERIFY || OPENSSL_EXTRA */ diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 33a65fc89..b477c8374 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -441,7 +441,7 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define X509_verify_cert_error_string wolfSSL_X509_verify_cert_error_string #define X509_verify_cert wolfSSL_X509_verify_cert #define X509_verify wolfSSL_X509_verify -#define X509_REQ_verify wolfSSL_X509_verify +#define X509_REQ_verify wolfSSL_X509_REQ_verify #define X509_check_private_key wolfSSL_X509_check_private_key #define X509_check_ca wolfSSL_X509_check_ca #define X509_check_host wolfSSL_X509_check_host diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index bcfadaa7b..c1a0effbc 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1377,6 +1377,9 @@ WOLFSSL_API unsigned char* wolfSSL_X509_get_subjectKeyID( WOLFSSL_X509*, unsigned char*, int*); WOLFSSL_API int wolfSSL_X509_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey); +#ifdef WOLFSSL_CERT_REQ +WOLFSSL_API int wolfSSL_X509_REQ_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey); +#endif WOLFSSL_API int wolfSSL_X509_set_subject_name(WOLFSSL_X509*, WOLFSSL_X509_NAME*); WOLFSSL_API int wolfSSL_X509_set_issuer_name(WOLFSSL_X509*, diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index ebb953f05..88742f5ae 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1043,6 +1043,10 @@ WOLFSSL_LOCAL int EncodePolicyOID(byte *out, word32 *outSz, WOLFSSL_API int CheckCertSignature(const byte*,word32,void*,void* cm); WOLFSSL_LOCAL int CheckCertSignaturePubKey(const byte* cert, word32 certSz, void* heap, const byte* pubKey, word32 pubKeySz, int pubKeyOID); +#ifdef WOLFSSL_CERT_REQ +WOLFSSL_LOCAL int CheckCSRSignaturePubKey(const byte* cert, word32 certSz, void* heap, + const byte* pubKey, word32 pubKeySz, int pubKeyOID); +#endif /* WOLFSSL_CERT_REQ */ WOLFSSL_LOCAL int AddSignature(byte* buf, int bodySz, const byte* sig, int sigSz, int sigAlgoType); WOLFSSL_LOCAL int ParseCertRelative(DecodedCert*,int type,int verify,void* cm);