From 9d2082f7e12a826b94eb6eb7f6ca54119d5a0b07 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 6 Oct 2021 18:12:06 -0700 Subject: [PATCH] Fixes and improvements for crypto callbacks with TLS (mutual auth) (#4437) * This PR resolves issues with using TLS client authentication (mutual auth) with crypto callbacks. The TLS client auth will not be sent without a private key being set. The solution is to allow setting a public key only if crypto callbacks is enabled and a devId is set. * Fix to allow using crypto callbacks with TLS mutual authentication where a private key is not available. * Fix for ED25519 sign when only a private key is loaded. * Fix to enable crypto callbacks for ED25519 and Curve25519 in TLS by using the _ex init functions. * Fix for wc_PemToDer return code where a PKCS8 header does not exist. * Remove duplicate logs in DoCertificateVerify. * Doxygen API updates: Added crypto callback help and updated use_PrivateKey with info about public key use. * * Added crypto callback tests for TLS client and server with mutual auth for RSA, ECC and ED25519. * Enhanced the API unit test TLS code to allow setting CA, cert and key. * Revert ED25519 changes. Opt to calculate public key directly when required for signing in the TLS crypto callback test. Build configuration fixes. * Fix to use proper devId in `ProcessBufferTryDecode`. * Various build fixes due to changes in PR. G++ issue with `missing-field-initializers`. Unused api.c func with DTLS and session export. Duplicate `eccKeyPubFile` def. * Added crypto callback TLS tests at WOLFSSL object level. Fix for ED25519/ED448 with client mutual auth where the private key is not set till WOLFSSL object. Fix issues with `wolfSSL_CTX_GetDevId` where devId is set on WOLFSSL object. Enable the `_id` API's for crypto callbacks. * Proper fix for `eccKeyPubFile` name conflict. Was causing RSA test to fail (expected DER, not PEM). --- certs/client-keyPub.pem | 9 + certs/ecc-keyPub.pem | 4 + certs/include.am | 4 +- certs/renewcerts.sh | 19 + .../{server-pub-key.pem => server-keyPub.pem} | 0 doc/dox_comments/header_files/cryptocb.h | 111 ++++ .../header_files/doxygen_groups.h | 1 + doc/dox_comments/header_files/doxygen_pages.h | 1 + doc/dox_comments/header_files/ssl.h | 18 + src/internal.c | 45 +- src/ssl.c | 71 ++- src/tls13.c | 8 - tests/api.c | 574 +++++++++++++++--- wolfcrypt/src/asn.c | 34 +- wolfcrypt/test/test.c | 5 +- wolfssl/test.h | 18 + 16 files changed, 798 insertions(+), 124 deletions(-) create mode 100644 certs/client-keyPub.pem create mode 100644 certs/ecc-keyPub.pem rename certs/{server-pub-key.pem => server-keyPub.pem} (100%) create mode 100644 doc/dox_comments/header_files/cryptocb.h diff --git a/certs/client-keyPub.pem b/certs/client-keyPub.pem new file mode 100644 index 000000000..5f7c1cdd3 --- /dev/null +++ b/certs/client-keyPub.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwwPRK/45pDJFO1PIhCsq +fHSavaoqUgdH1qY2sgcyjtC6aXvGw0Se1IFI/S1oootnu6F1yDYsStIb94u6zw35 +7+zxgR57mwNHmr9lzH9lJGmm6BSJW+Q098WwFJP1Z3s6enjhAVZWkaYTQo3SPECc +TO/Rht83URsMoTv18aNKNeThzpbfG36/TpfQEOioCDCBryALQxTFdGe0MoJvjYbC +iECZNoO6HkByIhfXUmUkc7DO7xnNrv94bHvAEgPUTnINUG07ozujmV6dyNkMhbPZ +itlUJttt+qy7/yVMxNF59HHThkAYE7BjtXJOMMSXhIYtVi/XFfd/wK71/Fvl+6G6 +0wIDAQAB +-----END PUBLIC KEY----- diff --git a/certs/ecc-keyPub.pem b/certs/ecc-keyPub.pem new file mode 100644 index 000000000..30363efab --- /dev/null +++ b/certs/ecc-keyPub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuzOsTCdQSsZKpQTDPN6fNttyLc6U +6iv6yyAJOSwW6GEC6a9N0wKTmjFbl5Ihf/DPGNqREQI0huggWDMLgDSJ2A== +-----END PUBLIC KEY----- diff --git a/certs/include.am b/certs/include.am index 971c268a4..5c46c5e8f 100644 --- a/certs/include.am +++ b/certs/include.am @@ -14,6 +14,7 @@ EXTRA_DIST += \ certs/client-crl-dist.pem \ certs/client-crl-dist.der \ certs/ecc-key.pem \ + certs/ecc-keyPub.pem \ certs/ecc-privkey.pem \ certs/ecc-privkeyPkcs8.der \ certs/ecc-privkeyPkcs8.pem \ @@ -34,13 +35,13 @@ EXTRA_DIST += \ certs/server-ecc-rsa.pem \ certs/server-keyEnc.pem \ certs/server-key.pem \ + certs/server-keyPub.pem \ certs/server-keyPkcs8.der \ certs/server-keyPkcs8Enc12.pem \ certs/server-keyPkcs8Enc2.pem \ certs/server-keyPkcs8Enc.pem \ certs/server-keyPkcs8Enc.der \ certs/server-keyPkcs8.pem \ - certs/server-pub-key.pem \ certs/server-revoked-cert.pem \ certs/server-revoked-key.pem \ certs/wolfssl-website-ca.pem \ @@ -71,6 +72,7 @@ EXTRA_DIST += \ certs/client-key.der \ certs/client-ecc-cert.der \ certs/client-keyPub.der \ + certs/client-keyPub.pem \ certs/dh2048.der \ certs/dh3072.der \ certs/dh4096.der \ diff --git a/certs/renewcerts.sh b/certs/renewcerts.sh index 126583060..7c546cbff 100755 --- a/certs/renewcerts.sh +++ b/certs/renewcerts.sh @@ -86,6 +86,25 @@ run_renewcerts(){ mv tmp.pem client-uri-cert.pem echo "End of section" echo "---------------------------------------------------------------------" + + ############################################################ + # Public Versions of client-key.pem + ############################################################ + openssl rsa -inform pem -in certs/client-key.pem -outform der -out certs/client-keyPub.der -pubout + openssl rsa -inform pem -in certs/client-key.pem -outform pem -out certs/client-keyPub.pem -pubout + + ############################################################ + # Public Versions of server-key.pem + ############################################################ + #openssl rsa -inform pem -in certs/server-key.pem -outform der -out certs/server-keyPub.der -pubout + openssl rsa -inform pem -in certs/server-key.pem -outform pem -out certs/server-keyPub.pem -pubout + + ############################################################ + # Public Versions of ecc-key.pem + ############################################################ + #openssl ec -inform pem -in certs/ecc-key.pem -outform der -out certs/ecc-keyPub.der -pubout + openssl ec -inform pem -in certs/ecc-key.pem -outform pem -out certs/ecc-keyPub.pem -pubout + ############################################################ #### update the self-signed (2048-bit) client-relative-uri.pem ############################################################ diff --git a/certs/server-pub-key.pem b/certs/server-keyPub.pem similarity index 100% rename from certs/server-pub-key.pem rename to certs/server-keyPub.pem diff --git a/doc/dox_comments/header_files/cryptocb.h b/doc/dox_comments/header_files/cryptocb.h new file mode 100644 index 000000000..7970cfef3 --- /dev/null +++ b/doc/dox_comments/header_files/cryptocb.h @@ -0,0 +1,111 @@ +/*! + \ingroup CryptoCb + + \brief This function registers a unique device identifier (devID) and + callback function for offloading crypto operations to external + hardware such as Key Store, Secure Element, HSM, PKCS11 or TPM. + + For STSAFE with Crypto Callbacks example see + wolfcrypt/src/port/st/stsafe.c and the wolfSSL_STSAFE_CryptoDevCb function. + + For TPM based crypto callbacks example see the wolfTPM2_CryptoDevCb + function in wolfTPM src/tpm2_wrap.c + + \return CRYPTOCB_UNAVAILABLE to fallback to using software crypto + \return 0 for success + \return negative value for failure + + \param devId any unique value, not -2 (INVALID_DEVID) + \param cb a callback function with prototype: + typedef int (*CryptoDevCallbackFunc)(int devId, wc_CryptoInfo* info, void* ctx); + + _Example_ + \code + #include + #include + static int myCryptoCb_Func(int devId, wc_CryptoInfo* info, void* ctx) + { + int ret = CRYPTOCB_UNAVAILABLE; + + if (info->algo_type == WC_ALGO_TYPE_PK) { + #ifndef NO_RSA + if (info->pk.type == WC_PK_TYPE_RSA) { + switch (info->pk.rsa.type) { + case RSA_PUBLIC_ENCRYPT: + case RSA_PUBLIC_DECRYPT: + // RSA public op + ret = wc_RsaFunction( + info->pk.rsa.in, info->pk.rsa.inLen, + info->pk.rsa.out, info->pk.rsa.outLen, + info->pk.rsa.type, info->pk.rsa.key, + info->pk.rsa.rng); + break; + case RSA_PRIVATE_ENCRYPT: + case RSA_PRIVATE_DECRYPT: + // RSA private op + ret = wc_RsaFunction( + info->pk.rsa.in, info->pk.rsa.inLen, + info->pk.rsa.out, info->pk.rsa.outLen, + info->pk.rsa.type, info->pk.rsa.key, + info->pk.rsa.rng); + break; + } + } + #endif + #ifdef HAVE_ECC + if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) { + // ECDSA + ret = wc_ecc_sign_hash( + info->pk.eccsign.in, info->pk.eccsign.inlen, + info->pk.eccsign.out, info->pk.eccsign.outlen, + info->pk.eccsign.rng, info->pk.eccsign.key); + } + #endif + #ifdef HAVE_ED25519 + if (info->pk.type == WC_PK_TYPE_ED25519_SIGN) { + // ED25519 sign + ret = wc_ed25519_sign_msg_ex( + info->pk.ed25519sign.in, info->pk.ed25519sign.inLen, + info->pk.ed25519sign.out, info->pk.ed25519sign.outLen, + info->pk.ed25519sign.key, info->pk.ed25519sign.type, + info->pk.ed25519sign.context, + info->pk.ed25519sign.contextLen); + } + #endif + } + return ret; + } + + int devId = 1; + wc_CryptoCb_RegisterDevice(devId, myCryptoCb_Func, &myCtx); + wolfSSL_CTX_SetDevId(ctx, devId); + \endcode + + \sa wc_CryptoCb_UnRegisterDevice + \sa wolfSSL_SetDevId + \sa wolfSSL_CTX_SetDevId +*/ +WOLFSSL_API int wc_CryptoCb_RegisterDevice(int devId, CryptoDevCallbackFunc cb, void* ctx); + +/*! + \ingroup CryptoCb + + \brief This function un-registers a unique device identifier (devID) + callback function. + + \return none No returns. + + \param devId any unique value, not -2 (INVALID_DEVID) + + _Example_ + \code + wc_CryptoCb_UnRegisterDevice(devId); + devId = INVALID_DEVID; + wolfSSL_CTX_SetDevId(ctx, devId); + \endcode + + \sa wc_CryptoCb_RegisterDevice + \sa wolfSSL_SetDevId + \sa wolfSSL_CTX_SetDevId +*/ +WOLFSSL_API void wc_CryptoCb_UnRegisterDevice(int devId); diff --git a/doc/dox_comments/header_files/doxygen_groups.h b/doc/dox_comments/header_files/doxygen_groups.h index 77a1fae9b..d699b234c 100644 --- a/doc/dox_comments/header_files/doxygen_groups.h +++ b/doc/dox_comments/header_files/doxygen_groups.h @@ -6,6 +6,7 @@ \defgroup Camellia Algorithms - Camellia \defgroup ChaCha Algorithms - ChaCha \defgroup ChaCha20Poly1305 Algorithms - ChaCha20_Poly1305 + \defgroup Crypto Callbacks - CryptoCb \defgroup Curve25519 Algorithms - Curve25519 \defgroup Curve448 Algorithms - Curve448 \defgroup DSA Algorithms - DSA diff --git a/doc/dox_comments/header_files/doxygen_pages.h b/doc/dox_comments/header_files/doxygen_pages.h index 765c0f472..dd558f9a8 100644 --- a/doc/dox_comments/header_files/doxygen_pages.h +++ b/doc/dox_comments/header_files/doxygen_pages.h @@ -33,6 +33,7 @@
  • \ref Camellia
  • \ref ChaCha
  • \ref ChaCha20Poly1305
  • +
  • \ref Crypto Callbacks
  • \ref Curve25519
  • \ref Curve448
  • \ref DSA
  • diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 4fceb5033..f55534c86 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -906,6 +906,13 @@ WOLFSSL_API int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX*, const char*, int) argument specifies the format type of the file - SSL_FILETYPE_ASN1or SSL_FILETYPE_PEM. Please see the examples for proper usage. + If using an external key store and do not have the private key you can + instead provide the public key and register the crypro callback to handle + the signing. For this you can build with --enable-cryptocb or + WOLF_CRYPTO_CB and register a crypto callback using + wc_CryptoCb_RegisterDevice and set the associated devId using + wolfSSL_CTX_SetDevId. + \return SSL_SUCCESS upon success. \return SSL_FAILURE The file is in the wrong format, or the wrong format has been given using the “format” argument. The file doesn’t exist, can’t @@ -931,6 +938,8 @@ WOLFSSL_API int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX*, const char*, int) \sa wolfSSL_CTX_use_PrivateKey_buffer \sa wolfSSL_use_PrivateKey_file \sa wolfSSL_use_PrivateKey_buffer + \sa wc_CryptoCb_RegisterDevice + \sa wolfSSL_CTX_SetDevId */ WOLFSSL_API int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX*, const char*, int); @@ -1311,6 +1320,13 @@ WOLFSSL_API int wolfSSL_use_certificate_file(WOLFSSL*, const char*, int); The format argument specifies the format type of the file - SSL_FILETYPE_ASN1 or SSL_FILETYPE_PEM. + If using an external key store and do not have the private key you can + instead provide the public key and register the crypro callback to handle + the signing. For this you can build with --enable-cryptocb or + WOLF_CRYPTO_CB and register a crypto callback using + wc_CryptoCb_RegisterDevice and set the associated devId using + wolfSSL_SetDevId. + \return SSL_SUCCESS upon success. \return SSL_FAILURE If the function call fails, possible causes might include: The file is in the wrong format, or the wrong format has been @@ -1340,6 +1356,8 @@ WOLFSSL_API int wolfSSL_use_certificate_file(WOLFSSL*, const char*, int); \sa wolfSSL_CTX_use_PrivateKey_buffer \sa wolfSSL_CTX_use_PrivateKey_file \sa wolfSSL_use_PrivateKey_buffer + \sa wc_CryptoCb_RegisterDevice + \sa wolfSSL_SetDevId */ WOLFSSL_API int wolfSSL_use_PrivateKey_file(WOLFSSL*, const char*, int); diff --git a/src/internal.c b/src/internal.c index c033a494f..0a68d6407 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6705,19 +6705,19 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 case DYNAMIC_TYPE_ED25519: - wc_ed25519_init((ed25519_key*)*pKey); + wc_ed25519_init_ex((ed25519_key*)*pKey, ssl->heap, ssl->devId); ret = 0; break; #endif /* HAVE_CURVE25519 */ #ifdef HAVE_CURVE25519 case DYNAMIC_TYPE_CURVE25519: - wc_curve25519_init((curve25519_key*)*pKey); + wc_curve25519_init_ex((curve25519_key*)*pKey, ssl->heap, ssl->devId); ret = 0; break; #endif /* HAVE_CURVE25519 */ #ifdef HAVE_ED448 case DYNAMIC_TYPE_ED448: - wc_ed448_init((ed448_key*)*pKey); + wc_ed448_init_ex((ed448_key*)*pKey, ssl->heap, ssl->devId); ret = 0; break; #endif /* HAVE_CURVE448 */ @@ -6768,19 +6768,21 @@ static int ReuseKey(WOLFSSL* ssl, int type, void* pKey) #ifdef HAVE_ED25519 case DYNAMIC_TYPE_ED25519: wc_ed25519_free((ed25519_key*)pKey); - ret = wc_ed25519_init((ed25519_key*)pKey); + ret = wc_ed25519_init_ex((ed25519_key*)pKey, ssl->heap, + ssl->devId); break; #endif /* HAVE_CURVE25519 */ #ifdef HAVE_CURVE25519 case DYNAMIC_TYPE_CURVE25519: wc_curve25519_free((curve25519_key*)pKey); - ret = wc_curve25519_init((curve25519_key*)pKey); + ret = wc_curve25519_init_ex((curve25519_key*)pKey, ssl->heap, + ssl->devId); break; #endif /* HAVE_CURVE25519 */ #ifdef HAVE_ED448 case DYNAMIC_TYPE_ED448: wc_ed448_free((ed448_key*)pKey); - ret = wc_ed448_init((ed448_key*)pKey); + ret = wc_ed448_init_ex((ed448_key*)pKey, ssl->heap, ssl->devId); break; #endif /* HAVE_CURVE448 */ #ifdef HAVE_CURVE448 @@ -22073,6 +22075,15 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) /* Decode the key assuming it is an RSA private key. */ ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &idx, (RsaKey*)ssl->hsKey, ssl->buffers.key->length); + #ifdef WOLF_CRYPTO_CB + /* if using crypto callbacks allow using a public key */ + if (ret != 0 && ssl->devId != INVALID_DEVID) { + WOLFSSL_MSG("Trying RSA public key with crypto callbacks"); + idx = 0; + ret = wc_RsaPublicKeyDecode(ssl->buffers.key->buffer, &idx, + (RsaKey*)ssl->hsKey, ssl->buffers.key->length); + } + #endif if (ret == 0) { WOLFSSL_MSG("Using RSA private key"); @@ -22119,6 +22130,16 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) ret = wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &idx, (ecc_key*)ssl->hsKey, ssl->buffers.key->length); + #ifdef WOLF_CRYPTO_CB + /* if using crypto callbacks allow using a public key */ + if (ret != 0 && ssl->devId != INVALID_DEVID) { + WOLFSSL_MSG("Trying ECC public key with crypto callbacks"); + idx = 0; + ret = wc_EccPublicKeyDecode(ssl->buffers.key->buffer, &idx, + (ecc_key*)ssl->hsKey, + ssl->buffers.key->length); + } + #endif if (ret == 0) { WOLFSSL_MSG("Using ECC private key"); @@ -22162,6 +22183,16 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) ret = wc_Ed25519PrivateKeyDecode(ssl->buffers.key->buffer, &idx, (ed25519_key*)ssl->hsKey, ssl->buffers.key->length); + #ifdef WOLF_CRYPTO_CB + /* if using crypto callbacks allow using a public key */ + if (ret != 0 && ssl->devId != INVALID_DEVID) { + WOLFSSL_MSG("Trying ED25519 public key with crypto callbacks"); + idx = 0; + ret = wc_Ed25519PublicKeyDecode(ssl->buffers.key->buffer, &idx, + (ed25519_key*)ssl->hsKey, + ssl->buffers.key->length); + } + #endif if (ret == 0) { WOLFSSL_MSG("Using ED25519 private key"); @@ -22197,7 +22228,7 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) #elif !defined(NO_RSA) WOLFSSL_MSG("Trying ED448 private key, RSA didn't work"); #else - WOLFSSL_MSG("Trying ED447 private key"); + WOLFSSL_MSG("Trying ED448 private key"); #endif /* Set start of data to beginning of buffer. */ diff --git a/src/ssl.c b/src/ssl.c index aa3f3453e..ee31ccaec 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -2325,10 +2325,10 @@ WOLFSSL_ABI int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl) { int devId = INVALID_DEVID; - if (ctx != NULL) - devId = ctx->devId; - else if (ssl != NULL) + if (ssl != NULL) devId = ssl->devId; + if (ctx != NULL && devId == INVALID_DEVID) + devId = ctx->devId; return devId; } void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl) @@ -5354,13 +5354,22 @@ static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der ret = wc_InitRsaKey_ex(key, heap, devId); if (ret == 0) { *idx = 0; - if (wc_RsaPrivateKeyDecode(der->buffer, idx, key, der->length) - != 0) { + ret = wc_RsaPrivateKeyDecode(der->buffer, idx, key, der->length); + #ifdef WOLF_CRYPTO_CB + if (ret != 0 && devId != INVALID_DEVID) { + /* if using crypto callbacks, try public key decode */ + *idx = 0; + ret = wc_RsaPublicKeyDecode(der->buffer, idx, key, der->length); + } + #endif + if (ret != 0) { #if !defined(HAVE_ECC) && !defined(HAVE_ED25519) && \ !defined(HAVE_ED448) WOLFSSL_MSG("RSA decode failed and ECC/ED25519/ED448 not " "enabled to try"); ret = WOLFSSL_BAD_FILE; + #else + ret = 0; /* continue trying other algorithms */ #endif } else { @@ -5415,8 +5424,15 @@ static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der if (wc_ecc_init_ex(key, heap, devId) == 0) { *idx = 0; - if (wc_EccPrivateKeyDecode(der->buffer, idx, key, - der->length) == 0) { + ret = wc_EccPrivateKeyDecode(der->buffer, idx, key, der->length); + #ifdef WOLF_CRYPTO_CB + if (ret != 0 && devId != INVALID_DEVID) { + /* if using crypto callbacks, try public key decode */ + *idx = 0; + ret = wc_EccPublicKeyDecode(der->buffer, idx, key, der->length); + } + #endif + if (ret == 0) { /* check for minimum ECC key size and then free */ int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz; @@ -5442,6 +5458,9 @@ static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der *resetSuites = 1; } } + else { + ret = 0; /* continue trying other algorithms */ + } wc_ecc_free(key); } @@ -5467,11 +5486,18 @@ static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der return MEMORY_E; #endif - ret = wc_ed25519_init(key); + ret = wc_ed25519_init_ex(key, heap, devId); if (ret == 0) { *idx = 0; - if (wc_Ed25519PrivateKeyDecode(der->buffer, idx, key, - der->length) == 0) { + ret = wc_Ed25519PrivateKeyDecode(der->buffer, idx, key, der->length); + #ifdef WOLF_CRYPTO_CB + if (ret != 0 && devId != INVALID_DEVID) { + /* if using crypto callbacks, try public key decode */ + *idx = 0; + ret = wc_Ed25519PublicKeyDecode(der->buffer, idx, key, der->length); + } + #endif + if (ret == 0) { /* check for minimum key size and then free */ int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz; @@ -5491,11 +5517,19 @@ static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der } *keyFormat = ED25519k; - if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { - *resetSuites = 1; + if (ssl != NULL) { + /* ED25519 requires caching enabled for tracking message + * hash used in EdDSA_Update for signing */ + ssl->options.cacheMessages = 1; + if (ssl->options.side == WOLFSSL_SERVER_END) { + *resetSuites = 1; + } } } } + else { + ret = 0; /* continue trying other algorithms */ + } wc_ed25519_free(key); } @@ -5549,8 +5583,13 @@ static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der } *keyFormat = ED448k; - if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { - *resetSuites = 1; + if (ssl != NULL) { + /* ED448 requires caching enabled for tracking message + * hash used in EdDSA_Update for signing */ + ssl->options.cacheMessages = 1; + if (ssl->options.side == WOLFSSL_SERVER_END) { + *resetSuites = 1; + } } } @@ -16070,7 +16109,7 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return ret; } -#ifdef HAVE_PKCS11 +#if defined(HAVE_PKCS11) || defined(WOLF_CRYPTO_CB) int wolfSSL_CTX_use_PrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id, long sz, int devId, long keySz) { @@ -16124,7 +16163,7 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return ret; } -#endif +#endif /* HAVE_PKCS11 || WOLF_CRYPTO_CB */ int wolfSSL_CTX_use_certificate_chain_buffer_format(WOLFSSL_CTX* ctx, const unsigned char* in, long sz, int format) diff --git a/src/tls13.c b/src/tls13.c index ae8a24408..99858037d 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -6656,8 +6656,6 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, { #ifndef NO_RSA if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { - WOLFSSL_MSG("Doing RSA peer cert verify"); - ret = RsaVerify(ssl, sig->buffer, (word32)sig->length, &args->output, args->sigAlgo, args->hashAlgo, ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS @@ -6674,8 +6672,6 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #endif /* !NO_RSA */ #ifdef HAVE_ECC if (ssl->peerEccDsaKeyPresent) { - WOLFSSL_MSG("Doing ECC peer cert verify"); - ret = EccVerify(ssl, input + args->idx, args->sz, args->sigData, args->sigDataSz, ssl->peerEccDsaKey, @@ -6694,8 +6690,6 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 if (ssl->peerEd25519KeyPresent) { - WOLFSSL_MSG("Doing ED25519 peer cert verify"); - ret = Ed25519Verify(ssl, input + args->idx, args->sz, args->sigData, args->sigDataSz, ssl->peerEd25519Key, @@ -6715,8 +6709,6 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #endif #ifdef HAVE_ED448 if (ssl->peerEd448KeyPresent) { - WOLFSSL_MSG("Doing ED448 peer cert verify"); - ret = Ed448Verify(ssl, input + args->idx, args->sz, args->sigData, args->sigDataSz, ssl->peerEd448Key, diff --git a/tests/api.c b/tests/api.c index 1525b3178..e2d55acf7 100644 --- a/tests/api.c +++ b/tests/api.c @@ -4820,20 +4820,33 @@ done: #endif /* defined(OPENSSL_EXTRA) && !defined(WOLFSSL_TIRTOS) && !defined(NO_WOLFSSL_CLIENT) */ } +#if (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)) && \ + defined(HAVE_ALPN) && defined(HAVE_SNI) && \ + defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(NO_BIO) + #define HAVE_ALPN_PROTOS_SUPPORT +#endif -/* SNI / ALPN / session export helper functions */ -#if defined(HAVE_SNI) || defined(HAVE_ALPN) ||\ - (defined(WOLFSSL_SESSION_EXPORT) && defined(WOLFSSL_DTLS)) +/* Generic TLS client / server with callbacks for API unit tests + * Used by SNI / ALPN / crypto callback helper functions */ +#if defined(HAVE_IO_TESTS_DEPENDENCIES) && \ + (defined(HAVE_SNI) || defined(HAVE_ALPN) || defined(WOLF_CRYPTO_CB) || \ + defined(HAVE_ALPN_PROTOS_SUPPORT)) + #define ENABLE_TLS_CALLBACK_TEST +#endif +#if defined(ENABLE_TLS_CALLBACK_TEST) || \ + (defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT)) +/* TLS server for API unit testing - generic */ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) { callback_functions* callbacks = ((func_args*)args)->callbacks; - WOLFSSL_CTX* ctx = wolfSSL_CTX_new(callbacks->method()); + WOLFSSL_CTX* ctx; WOLFSSL* ssl = NULL; - SOCKET_T sfd = 0; - SOCKET_T cfd = 0; - word16 port; + SOCKET_T sfd = 0; + SOCKET_T cfd = 0; + word16 port; char msg[] = "I hear you fa shizzle!"; int len = (int) XSTRLEN(msg); @@ -4841,10 +4854,27 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) int idx; int ret, err = 0; + ((func_args*)args)->return_code = TEST_FAIL; + + ctx = wolfSSL_CTX_new(callbacks->method()); + if (ctx == NULL) { + printf("CTX new failed\n"); + return 0; + } + + /* set defaults */ + if (callbacks->caPemFile == NULL) + callbacks->caPemFile = cliCertFile; + if (callbacks->certPemFile == NULL) + callbacks->certPemFile = svrCertFile; + if (callbacks->keyPemFile == NULL) + callbacks->keyPemFile = svrKeyFile; + #ifdef WOLFSSL_TIRTOS fdOpenSession(Task_self()); #endif - ((func_args*)args)->return_code = TEST_FAIL; + + wolfSSL_CTX_SetDevId(ctx, callbacks->devId); #if defined(USE_WINDOWS_API) port = ((func_args*)args)->signal->port; @@ -4869,19 +4899,25 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) AssertIntEQ(WOLFSSL_SUCCESS, - wolfSSL_CTX_load_verify_locations(ctx, cliCertFile, 0)); + wolfSSL_CTX_load_verify_locations(ctx, callbacks->caPemFile, 0)); AssertIntEQ(WOLFSSL_SUCCESS, - wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + wolfSSL_CTX_use_certificate_file(ctx, callbacks->certPemFile, WOLFSSL_FILETYPE_PEM)); AssertIntEQ(WOLFSSL_SUCCESS, - wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, WOLFSSL_FILETYPE_PEM)); + wolfSSL_CTX_use_PrivateKey_file(ctx, callbacks->keyPemFile, + WOLFSSL_FILETYPE_PEM)); if (callbacks->ctx_ready) callbacks->ctx_ready(ctx); ssl = wolfSSL_new(ctx); + if (ssl == NULL) { + printf("SSL new failed\n"); + wolfSSL_CTX_free(ctx); + return 0; + } if (wolfSSL_dtls(ssl)) { SOCKADDR_IN_T cliAddr; socklen_t cliLen; @@ -4900,6 +4936,18 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_set_fd(ssl, cfd)); + if (callbacks->loadToSSL) { + wolfSSL_SetDevId(ssl, callbacks->devId); + + AssertIntEQ(WOLFSSL_SUCCESS, + wolfSSL_use_certificate_file(ssl, callbacks->certPemFile, + WOLFSSL_FILETYPE_PEM)); + + AssertIntEQ(WOLFSSL_SUCCESS, + wolfSSL_use_PrivateKey_file(ssl, callbacks->keyPemFile, + WOLFSSL_FILETYPE_PEM)); + } + #ifdef NO_PSK #if !defined(NO_FILESYSTEM) && !defined(NO_DH) wolfSSL_SetTmpDH_file(ssl, dhParamFile, WOLFSSL_FILETYPE_PEM); @@ -4982,11 +5030,12 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) #endif } +/* TLS Client for API unit testing - generic */ static void run_wolfssl_client(void* args) { callback_functions* callbacks = ((func_args*)args)->callbacks; - WOLFSSL_CTX* ctx = wolfSSL_CTX_new(callbacks->method()); + WOLFSSL_CTX* ctx; WOLFSSL* ssl = NULL; SOCKET_T sfd = 0; @@ -4996,23 +5045,46 @@ static void run_wolfssl_client(void* args) int idx; int ret, err = 0; + ((func_args*)args)->return_code = TEST_FAIL; + + /* set defaults */ + if (callbacks->caPemFile == NULL) + callbacks->caPemFile = caCertFile; + if (callbacks->certPemFile == NULL) + callbacks->certPemFile = cliCertFile; + if (callbacks->keyPemFile == NULL) + callbacks->keyPemFile = cliKeyFile; + + ctx = wolfSSL_CTX_new(callbacks->method()); + if (ctx == NULL) { + printf("CTX new failed\n"); + return; + } + #ifdef WOLFSSL_TIRTOS fdOpenSession(Task_self()); #endif - ((func_args*)args)->return_code = TEST_FAIL; + if (!callbacks->loadToSSL) { + wolfSSL_CTX_SetDevId(ctx, callbacks->devId); + } #ifdef WOLFSSL_ENCRYPTED_KEYS wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); #endif - AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0)); + AssertIntEQ(WOLFSSL_SUCCESS, + wolfSSL_CTX_load_verify_locations(ctx, callbacks->caPemFile, 0)); - AssertIntEQ(WOLFSSL_SUCCESS, - wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, WOLFSSL_FILETYPE_PEM)); + if (!callbacks->loadToSSL) { + AssertIntEQ(WOLFSSL_SUCCESS, + wolfSSL_CTX_use_certificate_file(ctx, callbacks->certPemFile, + WOLFSSL_FILETYPE_PEM)); - AssertIntEQ(WOLFSSL_SUCCESS, - wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, WOLFSSL_FILETYPE_PEM)); + AssertIntEQ(WOLFSSL_SUCCESS, + wolfSSL_CTX_use_PrivateKey_file(ctx, callbacks->keyPemFile, + WOLFSSL_FILETYPE_PEM)); + } if (callbacks->ctx_ready) callbacks->ctx_ready(ctx); @@ -5028,6 +5100,18 @@ static void run_wolfssl_client(void* args) } AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_set_fd(ssl, sfd)); + if (callbacks->loadToSSL) { + wolfSSL_SetDevId(ssl, callbacks->devId); + + AssertIntEQ(WOLFSSL_SUCCESS, + wolfSSL_use_certificate_file(ssl, callbacks->certPemFile, + WOLFSSL_FILETYPE_PEM)); + + AssertIntEQ(WOLFSSL_SUCCESS, + wolfSSL_use_PrivateKey_file(ssl, callbacks->keyPemFile, + WOLFSSL_FILETYPE_PEM)); + } + if (callbacks->ssl_ready) callbacks->ssl_ready(ssl); @@ -5073,8 +5157,8 @@ static void run_wolfssl_client(void* args) #endif } -#endif /* defined(HAVE_SNI) || defined(HAVE_ALPN) || - defined(WOLFSSL_SESSION_EXPORT) */ +#endif /* ENABLE_TLS_CALLBACK_TEST */ + static void test_wolfSSL_read_write(void) { @@ -6092,8 +6176,8 @@ static void test_wolfSSL_tls_export(void) | TLS extensions tests *----------------------------------------------------------------------------*/ -#if defined(HAVE_SNI) || defined(HAVE_ALPN) -/* connection test runner */ +#ifdef ENABLE_TLS_CALLBACK_TEST +/* Connection test runner - generic */ static void test_wolfSSL_client_server(callback_functions* client_callbacks, callback_functions* server_callbacks) { @@ -6135,8 +6219,12 @@ static void test_wolfSSL_client_server(callback_functions* client_callbacks, #ifdef WOLFSSL_TIRTOS fdCloseSession(Task_self()); #endif + + client_callbacks->return_code = client_args.return_code; + server_callbacks->return_code = server_args.return_code; } -#endif /* defined(HAVE_SNI) || defined(HAVE_ALPN) */ +#endif /* ENABLE_TLS_CALLBACK_TEST */ + #ifdef HAVE_SNI static void test_wolfSSL_UseSNI_params(void) @@ -6267,58 +6355,69 @@ static void verify_FATAL_ERROR_on_client(WOLFSSL* ssl) } /* END of connection tests callbacks */ +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + static void test_wolfSSL_UseSNI_connection(void) { unsigned long i; callback_functions callbacks[] = { /* success case at ctx */ - {0, use_SNI_at_ctx, 0, 0, 0, 0}, - {0, use_SNI_at_ctx, 0, verify_SNI_real_matching, 0, 0}, + {.ctx_ready = use_SNI_at_ctx}, + {.ctx_ready = use_SNI_at_ctx, .on_result = verify_SNI_real_matching}, /* success case at ssl */ - {0, 0, use_SNI_at_ssl, verify_SNI_real_matching, 0, 0}, - {0, 0, use_SNI_at_ssl, verify_SNI_real_matching, 0, 0}, + {.ssl_ready = use_SNI_at_ssl, .on_result = verify_SNI_real_matching}, + {.ssl_ready = use_SNI_at_ssl, .on_result = verify_SNI_real_matching}, /* default mismatch behavior */ - {0, 0, different_SNI_at_ssl, verify_FATAL_ERROR_on_client, 0, 0}, - {0, 0, use_SNI_at_ssl, verify_UNKNOWN_SNI_on_server, 0, 0}, + {.ssl_ready = different_SNI_at_ssl, .on_result = verify_FATAL_ERROR_on_client}, + {.ssl_ready = use_SNI_at_ssl, .on_result = verify_UNKNOWN_SNI_on_server}, /* continue on mismatch */ - {0, 0, different_SNI_at_ssl, 0, 0, 0}, - {0, 0, use_SNI_WITH_CONTINUE_at_ssl, verify_SNI_no_matching, 0, 0}, + {.ssl_ready = different_SNI_at_ssl}, + {.ssl_ready = use_SNI_WITH_CONTINUE_at_ssl, .on_result = verify_SNI_no_matching}, /* fake answer on mismatch */ - {0, 0, different_SNI_at_ssl, 0, 0, 0}, - {0, 0, use_SNI_WITH_FAKE_ANSWER_at_ssl, verify_SNI_fake_matching, 0, 0}, + {.ssl_ready = different_SNI_at_ssl}, + {.ssl_ready = use_SNI_WITH_FAKE_ANSWER_at_ssl, .on_result = verify_SNI_fake_matching}, /* sni abort - success */ - {0, use_SNI_at_ctx, 0, 0, 0, 0}, - {0, use_MANDATORY_SNI_at_ctx, 0, verify_SNI_real_matching, 0, 0}, + {.ctx_ready = use_SNI_at_ctx}, + {.ctx_ready = use_MANDATORY_SNI_at_ctx, .on_result = verify_SNI_real_matching}, /* sni abort - abort when absent (ctx) */ - {0, 0, 0, verify_FATAL_ERROR_on_client, 0, 0}, - {0, use_MANDATORY_SNI_at_ctx, 0, verify_SNI_ABSENT_on_server, 0, 0}, + { .on_result = verify_FATAL_ERROR_on_client}, + {.ctx_ready = use_MANDATORY_SNI_at_ctx, .on_result = verify_SNI_ABSENT_on_server}, /* sni abort - abort when absent (ssl) */ - {0, 0, 0, verify_FATAL_ERROR_on_client, 0, 0}, - {0, 0, use_MANDATORY_SNI_at_ssl, verify_SNI_ABSENT_on_server, 0, 0}, + { .on_result = verify_FATAL_ERROR_on_client}, + {.ssl_ready = use_MANDATORY_SNI_at_ssl, .on_result = verify_SNI_ABSENT_on_server}, /* sni abort - success when overwritten */ - {0, 0, 0, 0, 0, 0}, - {0, use_MANDATORY_SNI_at_ctx, use_SNI_at_ssl, verify_SNI_no_matching, 0, 0}, + {.ctx_ready = NULL}, + {.ctx_ready = use_MANDATORY_SNI_at_ctx, .ssl_ready = use_SNI_at_ssl, .on_result = verify_SNI_no_matching}, /* sni abort - success when allowing mismatches */ - {0, 0, different_SNI_at_ssl, 0, 0, 0}, - {0, use_PSEUDO_MANDATORY_SNI_at_ctx, 0, verify_SNI_fake_matching, 0, 0}, + {.ssl_ready = different_SNI_at_ssl}, + {.ctx_ready = use_PSEUDO_MANDATORY_SNI_at_ctx, .on_result = verify_SNI_fake_matching}, }; for (i = 0; i < sizeof(callbacks) / sizeof(callback_functions); i += 2) { callbacks[i ].method = wolfSSLv23_client_method; callbacks[i + 1].method = wolfSSLv23_server_method; + callbacks[i ].devId = devId; + callbacks[i + 1].devId = devId; test_wolfSSL_client_server(&callbacks[i], &callbacks[i + 1]); } } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + static void test_wolfSSL_SNI_GetFromBuffer(void) { byte buff[] = { /* www.paypal.com */ @@ -6641,8 +6740,7 @@ static void test_wolfSSL_UseSupportedCurve(void) #endif } -#if defined(HAVE_ALPN) && !defined(NO_WOLFSSL_SERVER) && \ - defined(HAVE_IO_TESTS_DEPENDENCIES) +#if defined(HAVE_ALPN) && defined(HAVE_IO_TESTS_DEPENDENCIES) static void verify_ALPN_FATAL_ERROR_on_client(WOLFSSL* ssl) { @@ -6776,51 +6874,62 @@ static void verify_ALPN_client_list(WOLFSSL* ssl) AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_ALPN_FreePeerProtocol(ssl, &clist)); } +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + static void test_wolfSSL_UseALPN_connection(void) { unsigned long i; callback_functions callbacks[] = { /* success case same list */ - {0, 0, use_ALPN_all, 0, 0, 0}, - {0, 0, use_ALPN_all, verify_ALPN_matching_http1, 0, 0}, + {.ssl_ready = use_ALPN_all}, + {.ssl_ready = use_ALPN_all, .on_result = verify_ALPN_matching_http1}, /* success case only one for server */ - {0, 0, use_ALPN_all, 0, 0, 0}, - {0, 0, use_ALPN_one, verify_ALPN_matching_spdy2, 0, 0}, + {.ssl_ready = use_ALPN_all}, + {.ssl_ready = use_ALPN_one, .on_result = verify_ALPN_matching_spdy2}, /* success case only one for client */ - {0, 0, use_ALPN_one, 0, 0, 0}, - {0, 0, use_ALPN_all, verify_ALPN_matching_spdy2, 0, 0}, + {.ssl_ready = use_ALPN_one}, + {.ssl_ready = use_ALPN_all, .on_result = verify_ALPN_matching_spdy2}, /* success case none for client */ - {0, 0, 0, 0, 0, 0}, - {0, 0, use_ALPN_all, 0, 0, 0}, + {.ssl_ready = NULL}, + {.ssl_ready = use_ALPN_all}, /* success case mismatch behavior but option 'continue' set */ - {0, 0, use_ALPN_all_continue, verify_ALPN_not_matching_continue, 0, 0}, - {0, 0, use_ALPN_unknown_continue, 0, 0, 0}, + {.ssl_ready = use_ALPN_all_continue, .on_result = verify_ALPN_not_matching_continue}, + {.ssl_ready = use_ALPN_unknown_continue}, /* success case read protocol send by client */ - {0, 0, use_ALPN_all, 0, 0, 0}, - {0, 0, use_ALPN_one, verify_ALPN_client_list, 0, 0}, + {.ssl_ready = use_ALPN_all}, + {.ssl_ready = use_ALPN_one, .on_result = verify_ALPN_client_list}, /* mismatch behavior with same list * the first and only this one must be taken */ - {0, 0, use_ALPN_all, 0, 0, 0}, - {0, 0, use_ALPN_all, verify_ALPN_not_matching_spdy3, 0, 0}, + {.ssl_ready = use_ALPN_all}, + {.ssl_ready = use_ALPN_all, .on_result = verify_ALPN_not_matching_spdy3}, /* default mismatch behavior */ - {0, 0, use_ALPN_all, 0, 0, 0}, - {0, 0, use_ALPN_unknown, verify_ALPN_FATAL_ERROR_on_client, 0, 0}, + {.ssl_ready = use_ALPN_all}, + {.ssl_ready = use_ALPN_unknown, .on_result = verify_ALPN_FATAL_ERROR_on_client}, }; for (i = 0; i < sizeof(callbacks) / sizeof(callback_functions); i += 2) { callbacks[i ].method = wolfSSLv23_client_method; callbacks[i + 1].method = wolfSSLv23_server_method; + callbacks[i ].devId = devId; + callbacks[i + 1].devId = devId; test_wolfSSL_client_server(&callbacks[i], &callbacks[i + 1]); } } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + static void test_wolfSSL_UseALPN_params(void) { #ifndef NO_WOLFSSL_CLIENT @@ -6896,11 +7005,7 @@ static void test_wolfSSL_UseALPN_params(void) } #endif /* HAVE_ALPN */ -#if (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ - defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)) && \ - (defined(HAVE_ALPN) && defined(HAVE_SNI)) &&\ - defined(HAVE_IO_TESTS_DEPENDENCIES) - +#ifdef HAVE_ALPN_PROTOS_SUPPORT static void CTX_set_alpn_protos(SSL_CTX *ctx) { unsigned char p[] = { @@ -6919,7 +7024,6 @@ static void CTX_set_alpn_protos(SSL_CTX *ctx) #else AssertIntEQ(ret, SSL_SUCCESS); #endif - } static void set_alpn_protos(SSL* ssl) @@ -6972,26 +7076,38 @@ static void verify_alpn_matching_http1(WOLFSSL* ssl) AssertIntEQ(0, XMEMCMP(nego_proto, proto, protoSz)); } +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + static void test_wolfSSL_set_alpn_protos(void) { unsigned long i; callback_functions callbacks[] = { /* use CTX_alpn_protos */ - {0, CTX_set_alpn_protos, 0, 0, 0, 0}, - {0, CTX_set_alpn_protos, 0, verify_alpn_matching_http1, 0, 0}, + {.ctx_ready = CTX_set_alpn_protos}, + {.ctx_ready = CTX_set_alpn_protos, .on_result = verify_alpn_matching_http1}, /* use set_alpn_protos */ - {0, 0, set_alpn_protos, 0, 0, 0}, - {0, 0, set_alpn_protos, verify_alpn_matching_spdy3, 0, 0}, + {.ssl_ready = set_alpn_protos}, + {.ssl_ready = set_alpn_protos, .on_result = verify_alpn_matching_spdy3}, }; for (i = 0; i < sizeof(callbacks) / sizeof(callback_functions); i += 2) { callbacks[i ].method = wolfSSLv23_client_method; callbacks[i + 1].method = wolfSSLv23_server_method; + callbacks[i ].devId = devId; + callbacks[i + 1].devId = devId; test_wolfSSL_client_server(&callbacks[i], &callbacks[i + 1]); } } + +#ifdef __GNUC__ +#pragma GCC diagnostic pop #endif +#endif /* HAVE_ALPN_PROTOS_SUPPORT */ + static void test_wolfSSL_UseALPN(void) { #if defined(HAVE_ALPN) && !defined(NO_WOLFSSL_SERVER) &&\ @@ -7000,17 +7116,9 @@ static void test_wolfSSL_UseALPN(void) test_wolfSSL_UseALPN_params(); #endif -#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_BIO) - -#if (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ - defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)) && \ - (defined(HAVE_ALPN) && defined(HAVE_SNI)) && \ - defined(HAVE_IO_TESTS_DEPENDENCIES) - +#ifdef HAVE_ALPN_PROTOS_SUPPORT test_wolfSSL_set_alpn_protos(); #endif - -#endif } static void test_wolfSSL_DisableExtendedMasterSecret(void) @@ -30294,7 +30402,7 @@ static void test_wolfSSL_PEM_bio_RSAKey(void) RSA_free(rsa); /* Ensure that keys beginning with BEGIN RSA PUBLIC KEY can be read, too. */ - AssertNotNull(bio = BIO_new_file("./certs/server-pub-key.pem", "rb")); + AssertNotNull(bio = BIO_new_file("./certs/server-keyPub.pem", "rb")); AssertNotNull((rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL))); BIO_free(bio); RSA_free(rsa); @@ -49768,6 +49876,308 @@ static void test_SSL_CIPHER_get_xxx(void) #endif } +#if defined(WOLF_CRYPTO_CB) && defined(HAVE_IO_TESTS_DEPENDENCIES) + +static int load_pem_key_file_as_der(const char* privKeyFile, DerBuffer** pDer, + int* keyFormat) +{ + int ret; + byte* key_buf = NULL; + size_t key_sz = 0; + EncryptedInfo encInfo; + + XMEMSET(&encInfo, 0, sizeof(encInfo)); + + ret = load_file(privKeyFile, &key_buf, &key_sz); + if (ret == 0) { + ret = wc_PemToDer(key_buf, key_sz, PRIVATEKEY_TYPE, pDer, + NULL, &encInfo, keyFormat); + } + + if (key_buf != NULL) { + free(key_buf); key_buf = NULL; + } + (void)encInfo; /* not used in this test */ + +#ifdef DEBUG_WOLFSSL + printf("%s (%d): Loading PEM %s (len %d) to DER (len %d)\n", + (ret == 0) ? "Success" : "Failure", ret, privKeyFile, (int)key_sz, + (*pDer)->length); +#endif + + return ret; +} +static int test_CryptoCb_Func(int thisDevId, wc_CryptoInfo* info, void* ctx) +{ + int ret = CRYPTOCB_UNAVAILABLE; + const char* privKeyFile = (const char*)ctx; + DerBuffer* pDer = NULL; + int keyFormat = 0; + + if (info->algo_type == WC_ALGO_TYPE_PK) { + #ifdef DEBUG_WOLFSSL + printf("test_CryptoCb_Func: Pk Type %d\n", info->pk.type); + #endif + + #ifndef NO_RSA + if (info->pk.type == WC_PK_TYPE_RSA) { + switch (info->pk.rsa.type) { + case RSA_PUBLIC_ENCRYPT: + case RSA_PUBLIC_DECRYPT: + /* perform software based RSA public op */ + ret = CRYPTOCB_UNAVAILABLE; /* fallback to software */ + break; + case RSA_PRIVATE_ENCRYPT: + case RSA_PRIVATE_DECRYPT: + { + RsaKey key; + + /* perform software based RSA private op */ + #ifdef DEBUG_WOLFSSL + printf("test_CryptoCb_Func: RSA Priv\n"); + #endif + + ret = load_pem_key_file_as_der(privKeyFile, &pDer, + &keyFormat); + if (ret != 0) { + return ret; + } + ret = wc_InitRsaKey(&key, NULL); + if (ret == 0) { + word32 keyIdx = 0; + /* load RSA private key and perform private transform */ + ret = wc_RsaPrivateKeyDecode(pDer->buffer, &keyIdx, + &key, pDer->length); + if (ret == 0) { + ret = wc_RsaFunction( + info->pk.rsa.in, info->pk.rsa.inLen, + info->pk.rsa.out, info->pk.rsa.outLen, + info->pk.rsa.type, &key, info->pk.rsa.rng); + } + else { + /* if decode fails, then fall-back to software based crypto */ + printf("test_CryptoCb_Func: RSA private key decode " + "failed %d, falling back to software\n", ret); + ret = CRYPTOCB_UNAVAILABLE; + } + wc_FreeRsaKey(&key); + } + wc_FreeDer(&pDer); pDer = NULL; + break; + } + } + #ifdef DEBUG_WOLFSSL + printf("test_CryptoCb_Func: RSA Type %d, Ret %d, Out %d\n", + info->pk.rsa.type, ret, *info->pk.rsa.outLen); + #endif + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) { + ecc_key key; + + /* perform software based ECC sign */ + #ifdef DEBUG_WOLFSSL + printf("test_CryptoCb_Func: ECC Sign\n"); + #endif + + ret = load_pem_key_file_as_der(privKeyFile, &pDer, &keyFormat); + if (ret != 0) { + return ret; + } + + ret = wc_ecc_init(&key); + if (ret == 0) { + word32 keyIdx = 0; + /* load ECC private key and perform private transform */ + ret = wc_EccPrivateKeyDecode(pDer->buffer, &keyIdx, + &key, pDer->length); + if (ret == 0) { + ret = wc_ecc_sign_hash( + info->pk.eccsign.in, info->pk.eccsign.inlen, + info->pk.eccsign.out, info->pk.eccsign.outlen, + info->pk.eccsign.rng, &key); + } + else { + /* if decode fails, then fall-back to software based crypto */ + printf("test_CryptoCb_Func: ECC private key decode " + "failed %d, falling back to software\n", ret); + ret = CRYPTOCB_UNAVAILABLE; + } + wc_ecc_free(&key); + } + wc_FreeDer(&pDer); pDer = NULL; + + #ifdef DEBUG_WOLFSSL + printf("test_CryptoCb_Func: ECC Ret %d, Out %d\n", + ret, *info->pk.eccsign.outlen); + #endif + } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (info->pk.type == WC_PK_TYPE_ED25519_SIGN) { + ed25519_key key; + + /* perform software based ED25519 sign */ + #ifdef DEBUG_WOLFSSL + printf("test_CryptoCb_Func: ED25519 Sign\n"); + #endif + + ret = load_pem_key_file_as_der(privKeyFile, &pDer, &keyFormat); + if (ret != 0) { + return ret; + } + ret = wc_ed25519_init(&key); + if (ret == 0) { + word32 keyIdx = 0; + /* load ED25519 private key and perform private transform */ + ret = wc_Ed25519PrivateKeyDecode(pDer->buffer, &keyIdx, + &key, pDer->length); + if (ret == 0) { + /* calculate public key */ + ret = wc_ed25519_make_public(&key, key.p, ED25519_PUB_KEY_SIZE); + if (ret == 0) { + key.pubKeySet = 1; + ret = wc_ed25519_sign_msg_ex( + info->pk.ed25519sign.in, info->pk.ed25519sign.inLen, + info->pk.ed25519sign.out, info->pk.ed25519sign.outLen, + &key, info->pk.ed25519sign.type, + info->pk.ed25519sign.context, + info->pk.ed25519sign.contextLen); + } + } + else { + /* if decode fails, then fall-back to software based crypto */ + printf("test_CryptoCb_Func: ED25519 private key decode " + "failed %d, falling back to software\n", ret); + ret = CRYPTOCB_UNAVAILABLE; + } + wc_ed25519_free(&key); + } + wc_FreeDer(&pDer); pDer = NULL; + + #ifdef DEBUG_WOLFSSL + printf("test_CryptoCb_Func: ED25519 Ret %d, Out %d\n", + ret, *info->pk.ed25519sign.outLen); + #endif + } + #endif /* HAVE_ED25519 */ + } + (void)thisDevId; + (void)keyFormat; + + return ret; +} + +/* tlsVer: WOLFSSL_TLSV1_2 or WOLFSSL_TLSV1_3 */ +static void test_wc_CryptoCb_TLS(int tlsVer, + const char* cliCaPemFile, const char* cliCertPemFile, + const char* cliPrivKeyPemFile, const char* cliPubKeyPemFile, + const char* svrCaPemFile, const char* svrCertPemFile, + const char* svrPrivKeyPemFile, const char* svrPubKeyPemFile) +{ + callback_functions client_cbf; + callback_functions server_cbf; + + XMEMSET(&client_cbf, 0, sizeof(client_cbf)); + XMEMSET(&server_cbf, 0, sizeof(server_cbf)); + + if (tlsVer == WOLFSSL_TLSV1_3) { + #ifdef WOLFSSL_TLS13 + server_cbf.method = wolfTLSv1_3_server_method; + client_cbf.method = wolfTLSv1_3_client_method; + #endif + } + else if (tlsVer == WOLFSSL_TLSV1_2) { + #ifndef WOLFSSL_NO_TLS12 + server_cbf.method = wolfTLSv1_2_server_method; + client_cbf.method = wolfTLSv1_2_client_method; + #endif + } + if (server_cbf.method == NULL) { + /* not enabled */ + return; + } + + /* Setup the keys for the TLS test */ + client_cbf.certPemFile = cliCertPemFile; + client_cbf.keyPemFile = cliPubKeyPemFile; + client_cbf.caPemFile = cliCaPemFile; + + server_cbf.certPemFile = svrCertPemFile; + server_cbf.keyPemFile = svrPubKeyPemFile; + server_cbf.caPemFile = svrCaPemFile; + + /* Setup a crypto callback with pointer to private key file for testing */ + client_cbf.devId = 1; + wc_CryptoCb_RegisterDevice(client_cbf.devId, test_CryptoCb_Func, + (void*)cliPrivKeyPemFile); + server_cbf.devId = 2; + wc_CryptoCb_RegisterDevice(server_cbf.devId, test_CryptoCb_Func, + (void*)svrPrivKeyPemFile); + + /* Perform TLS server and client test */ + /* First test is at WOLFSSL_CTX level */ + test_wolfSSL_client_server(&client_cbf, &server_cbf); + /* Check for success */ + AssertIntEQ(server_cbf.return_code, TEST_SUCCESS); + AssertIntEQ(client_cbf.return_code, TEST_SUCCESS); + + /* Second test is a WOLFSSL object level */ + client_cbf.loadToSSL = 1; server_cbf.loadToSSL = 1; + test_wolfSSL_client_server(&client_cbf, &server_cbf); + + /* Check for success */ + AssertIntEQ(server_cbf.return_code, TEST_SUCCESS); + AssertIntEQ(client_cbf.return_code, TEST_SUCCESS); + + /* Un register the devId's */ + wc_CryptoCb_UnRegisterDevice(client_cbf.devId); + client_cbf.devId = INVALID_DEVID; + wc_CryptoCb_UnRegisterDevice(server_cbf.devId); + server_cbf.devId = INVALID_DEVID; +} +#endif /* WOLF_CRYPTO_CB && HAVE_IO_TESTS_DEPENDENCIES */ + +static void test_wc_CryptoCb(void) +{ +#ifdef WOLF_CRYPTO_CB + /* TODO: Add crypto callback API tests */ + +#ifdef HAVE_IO_TESTS_DEPENDENCIES + #ifndef NO_RSA + /* RSA */ + test_wc_CryptoCb_TLS(WOLFSSL_TLSV1_3, + svrCertFile, cliCertFile, cliKeyFile, cliKeyPubFile, + cliCertFile, svrCertFile, svrKeyFile, svrKeyPubFile); + test_wc_CryptoCb_TLS(WOLFSSL_TLSV1_2, + svrCertFile, cliCertFile, cliKeyFile, cliKeyPubFile, + cliCertFile, svrCertFile, svrKeyFile, svrKeyPubFile); + #endif + + #ifdef HAVE_ECC + /* ECC */ + test_wc_CryptoCb_TLS(WOLFSSL_TLSV1_3, + caEccCertFile, cliEccCertFile, cliEccKeyFile, cliEccKeyPubFile, + cliEccCertFile, eccCertFile, eccKeyFile, eccKeyPubFile); + test_wc_CryptoCb_TLS(WOLFSSL_TLSV1_2, + caEccCertFile, cliEccCertFile, cliEccKeyFile, cliEccKeyPubFile, + cliEccCertFile, eccCertFile, eccKeyFile, eccKeyPubFile); + #endif + + #ifdef HAVE_ED25519 + /* ED25519 */ + test_wc_CryptoCb_TLS(WOLFSSL_TLSV1_3, + caEdCertFile, cliEdCertFile, cliEdKeyFile, cliEdKeyPubFile, + cliEdCertFile, edCertFile, edKeyFile, edKeyPubFile); + test_wc_CryptoCb_TLS(WOLFSSL_TLSV1_2, + caEdCertFile, cliEdCertFile, cliEdKeyFile, cliEdKeyPubFile, + cliEdCertFile, edCertFile, edKeyFile, edKeyPubFile); + #endif +#endif /* HAVE_IO_TESTS_DEPENDENCIES */ +#endif /* WOLF_CRYPTO_CB */ +} + /*----------------------------------------------------------------------------* | Main *----------------------------------------------------------------------------*/ @@ -50616,6 +51026,8 @@ void ApiTest(void) test_wolfSSL_CTX_LoadCRL(); + test_wc_CryptoCb(); + AssertIntEQ(test_ForceZero(), 0); AssertIntEQ(test_wolfSSL_Cleanup(), WOLFSSL_SUCCESS); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index d9170ed87..5cb64e3cb 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -6382,7 +6382,7 @@ int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, word32* oidSz, return MEMORY_E; tmpIdx = 0; - if (wc_ed25519_init(ed25519) == 0) { + if (wc_ed25519_init_ex(ed25519, heap, INVALID_DEVID) == 0) { if (wc_Ed25519PrivateKeyDecode(key, &tmpIdx, ed25519, keySz) == 0) { *algoID = ED25519k; } @@ -13034,7 +13034,8 @@ static int ConfirmSignature(SignatureCtx* sigCtx, if (sigCtx->key.ed25519 == NULL) { ERROR_OUT(MEMORY_E, exit_cs); } - if ((ret = wc_ed25519_init(sigCtx->key.ed25519)) < 0) { + if ((ret = wc_ed25519_init_ex(sigCtx->key.ed25519, + sigCtx->heap, sigCtx->devId)) < 0) { goto exit_cs; } if ((ret = wc_ed25519_import_public(key, keySz, @@ -18771,7 +18772,6 @@ int PemToDer(const unsigned char* buff, long longSz, int type, /* map header if not found for type */ for (;;) { headerEnd = XSTRNSTR((char*)buff, header, sz); - if (headerEnd) { break; } @@ -18806,7 +18806,14 @@ int PemToDer(const unsigned char* buff, long longSz, int type, } #endif else { + #ifdef WOLF_CRYPTO_CB + /* allow loading a public key for use with crypto callbacks */ + type = PUBLICKEY_TYPE; + header = BEGIN_PUB_KEY; + footer = END_PUB_KEY; + #else break; + #endif } } else if (type == PUBLICKEY_TYPE) { @@ -18907,18 +18914,30 @@ int PemToDer(const unsigned char* buff, long longSz, int type, /* eat end of line characters */ headerEnd = SkipEndOfLineChars(headerEnd, bufferEnd); - if (type == PRIVATEKEY_TYPE) { + if (keyFormat) { /* keyFormat is Key_Sum enum */ - if (keyFormat) { + if (type == PRIVATEKEY_TYPE) { + #ifndef NO_RSA + if (header == BEGIN_RSA_PRIV) + *keyFormat = RSAk; + #endif #ifdef HAVE_ECC if (header == BEGIN_EC_PRIV) *keyFormat = ECDSAk; #endif - #if !defined(NO_DSA) + #ifndef NO_DSA if (header == BEGIN_DSA_PRIV) *keyFormat = DSAk; #endif } + #ifdef WOLF_CRYPTO_CB + else if (type == PUBLICKEY_TYPE) { + #ifndef NO_RSA + if (header == BEGIN_RSA_PUB) + *keyFormat = RSAk; + #endif + } + #endif } #ifdef WOLFSSL_ENCRYPTED_KEYS @@ -18993,7 +19012,6 @@ int PemToDer(const unsigned char* buff, long longSz, int type, return 0; } - #ifdef WOLFSSL_ENCRYPTED_KEYS if (encrypted_key || header == BEGIN_ENC_PRIV_KEY) { int passwordSz = NAME_SZ; @@ -19112,8 +19130,8 @@ int wc_PemToDer(const unsigned char* buff, long longSz, int type, ret = ToTraditional(der->buffer, der->length); if (ret > 0) { der->length = ret; - ret = 0; } + ret = 0; /* ignore error removing PKCS8 header */ } #endif return ret; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 0966ea9c0..cfb8d9af3 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -12021,8 +12021,7 @@ WOLFSSL_TEST_SUBROUTINE int memory_test(void) #if !defined(USE_CERT_BUFFERS_256) && !defined(NO_ASN) #if defined(HAVE_ECC) && defined(WOLFSSL_CERT_GEN) #ifndef NO_RSA - /* eccKeyPubFile is used in a test that requires RSA. */ - static const char* eccKeyPubFile = CERT_ROOT "ecc-keyPub.der"; + static const char* eccKeyPubFileDer = CERT_ROOT "ecc-keyPub.der"; #endif static const char* eccCaKeyFile = CERT_ROOT "ca-ecc-key.der"; static const char* eccCaCertFile = CERT_ROOT "ca-ecc-cert.pem"; @@ -14542,7 +14541,7 @@ static int rsa_ecc_certgen_test(WC_RNG* rng, byte* tmp) XMEMCPY(tmp, ecc_key_pub_der_256, sizeof_ecc_key_pub_der_256); bytes3 = sizeof_ecc_key_pub_der_256; #else - file3 = XFOPEN(eccKeyPubFile, "rb"); + file3 = XFOPEN(eccKeyPubFileDer, "rb"); if (!file3) { ERROR_OUT(-7855, exit_rsa); } diff --git a/wolfssl/test.h b/wolfssl/test.h index 8a16bdb4e..c5160b53e 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -335,23 +335,29 @@ #define caCertFile "certs/ca-cert.pem" #define eccCertFile "certs/server-ecc.pem" #define eccKeyFile "certs/ecc-key.pem" +#define eccKeyPubFile "certs/ecc-keyPub.pem" #define eccRsaCertFile "certs/server-ecc-rsa.pem" #define svrCertFile "certs/server-cert.pem" #define svrKeyFile "certs/server-key.pem" +#define svrKeyPubFile "certs/server-keyPub.pem" #define cliCertFile "certs/client-cert.pem" #define cliCertDerFile "certs/client-cert.der" #define cliCertFileExt "certs/client-cert-ext.pem" #define cliCertDerFileExt "certs/client-cert-ext.der" #define cliKeyFile "certs/client-key.pem" +#define cliKeyPubFile "certs/client-keyPub.pem" #define dhParamFile "certs/dh2048.pem" #define cliEccKeyFile "certs/ecc-client-key.pem" +#define cliEccKeyPubFile "certs/ecc-client-keyPub.pem" #define cliEccCertFile "certs/client-ecc-cert.pem" #define caEccCertFile "certs/ca-ecc-cert.pem" #define crlPemDir "certs/crl" #define edCertFile "certs/ed25519/server-ed25519-cert.pem" #define edKeyFile "certs/ed25519/server-ed25519-priv.pem" +#define edKeyPubFile "certs/ed25519/server-ed25519-key.pem" #define cliEdCertFile "certs/ed25519/client-ed25519.pem" #define cliEdKeyFile "certs/ed25519/client-ed25519-priv.pem" +#define cliEdKeyPubFile "certs/ed25519/client-ed25519-key.pem" #define caEdCertFile "certs/ed25519/ca-ed25519.pem" #define ed448CertFile "certs/ed448/server-ed448-cert.pem" #define ed448KeyFile "certs/ed448/server-ed448-priv.pem" @@ -367,23 +373,29 @@ #define caCertFile "./certs/ca-cert.pem" #define eccCertFile "./certs/server-ecc.pem" #define eccKeyFile "./certs/ecc-key.pem" +#define eccKeyPubFile "./certs/ecc-keyPub.pem" #define eccRsaCertFile "./certs/server-ecc-rsa.pem" #define svrCertFile "./certs/server-cert.pem" #define svrKeyFile "./certs/server-key.pem" +#define svrKeyPubFile "./certs/server-keyPub.pem" #define cliCertFile "./certs/client-cert.pem" #define cliCertDerFile "./certs/client-cert.der" #define cliCertFileExt "./certs/client-cert-ext.pem" #define cliCertDerFileExt "./certs/client-cert-ext.der" #define cliKeyFile "./certs/client-key.pem" +#define cliKeyPubFile "./certs/client-keyPub.pem" #define dhParamFile "./certs/dh2048.pem" #define cliEccKeyFile "./certs/ecc-client-key.pem" +#define cliEccKeyPubFile "./certs/ecc-client-keyPub.pem" #define cliEccCertFile "./certs/client-ecc-cert.pem" #define caEccCertFile "./certs/ca-ecc-cert.pem" #define crlPemDir "./certs/crl" #define edCertFile "./certs/ed25519/server-ed25519-cert.pem" #define edKeyFile "./certs/ed25519/server-ed25519-priv.pem" +#define edKeyPubFile "./certs/ed25519/server-ed25519-key.pem" #define cliEdCertFile "./certs/ed25519/client-ed25519.pem" #define cliEdKeyFile "./certs/ed25519/client-ed25519-priv.pem" +#define cliEdKeyPubFile "./certs/ed25519/client-ed25519-key.pem" #define caEdCertFile "./certs/ed25519/ca-ed25519.pem" #define ed448CertFile "./certs/ed448/server-ed448-cert.pem" #define ed448KeyFile "./certs/ed448/server-ed448-priv.pem" @@ -443,7 +455,13 @@ typedef struct callback_functions { ssl_callback ssl_ready; ssl_callback on_result; WOLFSSL_CTX* ctx; + const char* caPemFile; + const char* certPemFile; + const char* keyPemFile; + int devId; + int return_code; unsigned char isSharedCtx:1; + unsigned char loadToSSL:1; } callback_functions; typedef struct func_args {