From 8e9810e87e6049fb3cb54a1b06551862225f50f2 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Tue, 5 Mar 2024 11:02:45 +1000 Subject: [PATCH] ssl.c: Move functions out to separate files Moved E[CD][25519||448] APIs to pk.c Move public key PEM APIs to pk.c. Move wolfSSL loading and using of private keys and certificates to ssl_load.c Move PKCS#7 and PKCS#12 APIs to ssl_p7p12.c. Move session and session cache APIs to ssl_sess.c. Other minor fixes. --- .../components/wolfssl/CMakeLists.txt | 3 + .../components/wolfssl/CMakeLists.txt | 3 + .../components/wolfssl/CMakeLists.txt | 3 + .../components/wolfssl/CMakeLists.txt | 3 + .../components/wolfssl/CMakeLists.txt | 3 + IDE/Espressif/ESP-IDF/libs/CMakeLists.txt | 3 + .../wolfssl_new_azsphere/CMakeLists.txt | 3 + certs/dh-priv-2048.der | Bin 0 -> 554 bytes certs/dh-priv-2048.pem | 14 + certs/dh-pub-2048.der | Bin 0 -> 553 bytes certs/dh-pub-2048.pem | 14 + certs/dsa2048.pem | 20 + certs/include.am | 7 +- examples/client/client.c | 1 + src/include.am | 3 + src/pk.c | 2606 ++- src/ssl.c | 14405 ++-------------- src/ssl_bn.c | 2 +- src/ssl_load.c | 5783 +++++++ src/ssl_misc.c | 213 +- src/ssl_p7p12.c | 2122 +++ src/ssl_sess.c | 4535 +++++ src/x509.c | 21 + tests/api.c | 1218 +- wolfcrypt/src/asn.c | 17 +- wolfssl/internal.h | 4 +- wolfssl/ssl.h | 16 +- wolfssl/wolfcrypt/asn.h | 5 +- wolfssl/wolfcrypt/ecc.h | 4 + 29 files changed, 17234 insertions(+), 13797 deletions(-) create mode 100644 certs/dh-priv-2048.der create mode 100644 certs/dh-priv-2048.pem create mode 100644 certs/dh-pub-2048.der create mode 100644 certs/dh-pub-2048.pem create mode 100644 certs/dsa2048.pem create mode 100644 src/ssl_load.c create mode 100644 src/ssl_p7p12.c create mode 100644 src/ssl_sess.c diff --git a/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/CMakeLists.txt b/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/CMakeLists.txt index e129a64ef..4ac276736 100644 --- a/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/CMakeLists.txt +++ b/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/CMakeLists.txt @@ -384,7 +384,10 @@ else() "\"${WOLFSSL_ROOT}/src/ssl_bn.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_certman.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_crypto.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_load.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_misc.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_p7p12.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_sess.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/x509.c\"" "\"${WOLFSSL_ROOT}/src/x509_str.c\"" "\"${WOLFSSL_ROOT}/wolfcrypt/src/evp.c\"" diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/CMakeLists.txt b/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/CMakeLists.txt index e129a64ef..4ac276736 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/CMakeLists.txt +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/CMakeLists.txt @@ -384,7 +384,10 @@ else() "\"${WOLFSSL_ROOT}/src/ssl_bn.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_certman.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_crypto.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_load.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_misc.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_p7p12.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_sess.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/x509.c\"" "\"${WOLFSSL_ROOT}/src/x509_str.c\"" "\"${WOLFSSL_ROOT}/wolfcrypt/src/evp.c\"" diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/CMakeLists.txt b/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/CMakeLists.txt index 615142bac..39bce20c6 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/CMakeLists.txt +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/CMakeLists.txt @@ -384,7 +384,10 @@ else() "\"${WOLFSSL_ROOT}/src/ssl_bn.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_certman.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_crypto.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_load.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_misc.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_p7p12.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_sess.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/x509.c\"" "\"${WOLFSSL_ROOT}/src/x509_str.c\"" "\"${WOLFSSL_ROOT}/wolfcrypt/src/evp.c\"" diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/CMakeLists.txt b/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/CMakeLists.txt index e129a64ef..4ac276736 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/CMakeLists.txt +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/CMakeLists.txt @@ -384,7 +384,10 @@ else() "\"${WOLFSSL_ROOT}/src/ssl_bn.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_certman.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_crypto.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_load.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_misc.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_p7p12.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_sess.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/x509.c\"" "\"${WOLFSSL_ROOT}/src/x509_str.c\"" "\"${WOLFSSL_ROOT}/wolfcrypt/src/evp.c\"" diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/CMakeLists.txt b/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/CMakeLists.txt index e129a64ef..4ac276736 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/CMakeLists.txt +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/CMakeLists.txt @@ -384,7 +384,10 @@ else() "\"${WOLFSSL_ROOT}/src/ssl_bn.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_certman.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_crypto.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_load.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_misc.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_p7p12.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_sess.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/x509.c\"" "\"${WOLFSSL_ROOT}/src/x509_str.c\"" "\"${WOLFSSL_ROOT}/wolfcrypt/src/evp.c\"" diff --git a/IDE/Espressif/ESP-IDF/libs/CMakeLists.txt b/IDE/Espressif/ESP-IDF/libs/CMakeLists.txt index ab9cb25f4..b63775e14 100644 --- a/IDE/Espressif/ESP-IDF/libs/CMakeLists.txt +++ b/IDE/Espressif/ESP-IDF/libs/CMakeLists.txt @@ -75,7 +75,10 @@ set(COMPONENT_SRCEXCLUDE "./src/ssl_bn.c" # included by ssl.c "./src/ssl_certman.c" # included by ssl.c "./src/ssl_crypto.c" # included by ssl.c + "./src/ssl_load.c" # included by ssl.c "./src/ssl_misc.c" # included by ssl.c + "./src/ssl_p7p12.c" # included by ssl.c + "./src/ssl_sess.c" # included by ssl.c "./src/x509.c" "./src/x509_str.c" "./wolfcrypt/src/evp.c" diff --git a/IDE/MSVS-2019-AZSPHERE/wolfssl_new_azsphere/CMakeLists.txt b/IDE/MSVS-2019-AZSPHERE/wolfssl_new_azsphere/CMakeLists.txt index 902050c27..18c3633b0 100644 --- a/IDE/MSVS-2019-AZSPHERE/wolfssl_new_azsphere/CMakeLists.txt +++ b/IDE/MSVS-2019-AZSPHERE/wolfssl_new_azsphere/CMakeLists.txt @@ -41,7 +41,10 @@ list( REMOVE_ITEM SSL_SOURCES ../../../src/ssl_asn1.c ) list( REMOVE_ITEM SSL_SOURCES ../../../src/ssl_bn.c ) list( REMOVE_ITEM SSL_SOURCES ../../../src/ssl_certman.c ) list( REMOVE_ITEM SSL_SOURCES ../../../src/ssl_crypto.c ) +list( REMOVE_ITEM SSL_SOURCES ../../../src/ssl_load.c ) list( REMOVE_ITEM SSL_SOURCES ../../../src/ssl_misc.c ) +list( REMOVE_ITEM SSL_SOURCES ../../../src/ssl_p7p12.c ) +list( REMOVE_ITEM SSL_SOURCES ../../../src/ssl_sess.c ) aux_source_directory( ${CRYPTO_SRC_DIR} CRYPTO_SOURCES ) list( REMOVE_ITEM CRYPTO_SOURCES ../../../wolfcrypt/src/evp.c ) list( REMOVE_ITEM CRYPTO_SOURCES ../../../wolfcrypt/src/misc.c ) diff --git a/certs/dh-priv-2048.der b/certs/dh-priv-2048.der new file mode 100644 index 0000000000000000000000000000000000000000..f74c6414326250c8ef17bef474e593efc9b58fbe GIT binary patch literal 554 zcmV+_0@eL6f&wN20RS+90T%`dDuzgg_YDC90Wg9A2m*ou0RXU}2nL)86S`RjJiIW~ z^#H+7M5os8O2#E89O%-PQwm&>-J-&jgui{VM4y||!HUJca$Kk9k>=E&a|eZ6W=O|y z`n2u>$vv7%+C9NWJ{f7z7e)u8O`j{47ddS(jVkk$({<0Fb>{Mt9~y84ssw{qF#Fne zlQ>Z5C;emYJmt5@39fHYHI9VNN&x8+ep)ftGyEYFcFYzq+YJ20Vy88@@3*k5z&7^T z$wo-|K#%|{8>(#M8p8_%o*TkOGL$NI?P9)7O?Ka&Ch0tA8q1OkEq0B94&Eq9#1 zmRFPh?A}kJ4)Q*b1N&t{Eo33>sU7MTP}nmi9>pG}+5meH9J1dpK;kw14MJbiEhc3q zFEs@;l%8N3eUlSrHq@qq?TJ!k0~b+&u}Ml18+eCf?p$CRM1B2NUC=+WpJI0Y?oMx` zto_k;gSoQm)Z_?hI!xg<%T2`Yw2hW8Bt0|79C0SE$u0RaH8p$G%gl!U*1vP7So(!q+wzH(fr=aJ^rpK}L=TV_bdaQd|F z0?9p^O4>caMm`y7(HBMsqfMVHmKQl~FpVnnl+$(3pmpZ*k{=py1*!ytS1|k9c9S?z z=qLSS?mXqU$O*1*P&JN(&Po935`J1S*E9Sf6L!oNFxw3L#bT#5xbL^HtiU$**~vyo z`9P2WD;uh8;~K*Y1D+egM&w9NB6DxUU(}k`Fb7E1jF79;_VMFL(^yNUxy>oRXdehm zV}>tWYu2^~W%s7s0B38v!>K`o`^Wmo;vRml06&ug0RjVp0R{j9f&l>lfu8$4NWv3Y z)$qf_licY|9;DX>E2RRm-T2Ha=^MCp1jCRTF*3axE$^lLDT9_;WjGU%_!^K$48TU9 zG&RJJHV(rQxl%5LRSnf>Je^iZS*Dz6P`kJvQTAH}lod8pW?Dj;6>JS=aL+AKqY)nl zctY>UX)S__&ma<5Ekv9ky`cZp;i5kesI+XYXZ^kArfO5 rt8oEuG+xQ967O3CN!L|)?SpORlZldc|oi1aWYpeOs literal 0 HcmV?d00001 diff --git a/certs/dh-pub-2048.pem b/certs/dh-pub-2048.pem new file mode 100644 index 000000000..48b3e3ff5 --- /dev/null +++ b/certs/dh-pub-2048.pem @@ -0,0 +1,14 @@ +-----BEGIN PUBLIC KEY----- +MIICJTCCARcGCSqGSIb3DQEDATCCAQgCggEBALChCAacCBO6WQY8vDDV9QDBT0Sn +1u9KxiUnHOjSllMKXJHdosKUhL99skSfm9LBisW+clyn55Hm1J9zB4VbZkjHcPq0 +7gLJPZpK2j3BRj4ZadEXRgejTZ8rlhc5bTCNKvOU03XPoHXm8pIfGnAFqgSDVzD7 +2naTOFDoJ/1j7jzlt8gJrm9QNY6EzkoA6RJ+WjHXM/whE3bMFjDbDPzFYqc1uO+3 +sKzANvbZyUZI+UCQACsbqmzjGsMLA54bwkbkSE4ic2/DX9Sa1jAHSNaMkKvU9vHj +SNNYS6a5zSm/aB8IS2OGL1xr1rYGZfem3ABna7vDqUGD+8f6yOIefq8AP5MCAQID +ggEGAAKCAQEAgZ77PUjCE1nV8MPEk9zpTR6k1wYrpQKy3fjMK+kbuHUEw5AaMTK9 +Gi3vpfwpg5ZaZTgTkPgakEcMwEagNDXEjzYOwxK5Ui6FVQ3VaDydVkhZppxpULu4 +H1H2WwWUFTZTZlpCmhVsDWZwzy1RoxEfBnhC78hpLYKLzyASWC1EnCC9oP/U4aI/ +D6i0bK1pXxPGFrML5jRkVpQReCkLI/aOgeTNUAcJC+USxIPSXpdPYl81zsWRgawP +bd2saVqE9DqJVSpoRY9yh1JoFqAagANNQL1x3sohEmMZq3EBbzReyawVW6Cbe5mb +LMtSN/UWqN/NwbYNcVj/GxFuoutVnS5jmw== +-----END PUBLIC KEY----- diff --git a/certs/dsa2048.pem b/certs/dsa2048.pem new file mode 100644 index 000000000..f21cc19fc --- /dev/null +++ b/certs/dsa2048.pem @@ -0,0 +1,20 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIDPwIBAAKCAQEAzI7JoNWaJxzaUt/HwOYGpD6KZknQWTNRacScXmSFx/Gr1dli +rP2h4BtX/5bvDJ/IRIfrXJHQRkIJUGojy4lvVelqEamoMqszDVG1eVG0q6IlEY3l +JL7Y8Z1OEm+sRFSAqbSBaE5EDrg5876DCHSixnrXan0KiFeDSNzPXm/uaAz3/wME +kKr3B5j4Z1qDI2ZHYMNDbgORrChmy/DTBcgJl7WuAV6AO51P3j6U/suCsLH8kYsd +iu7GBh83kUjS+GxdYBODp4Gsyo3QagQK6j4iThPxDbtga828XIejZytCoZ/NOVi+ +VbGThM6yEE7kw5+yU2EBKaqWyyBgQh26dUtjwQIVAOelOdRqN16VBjkHdwrroAPr +eIKbAoIBAQCa1ExxL+z6MrKAfmFKa18YdkPDabpBx6cdeQHsrzSHZ08pgKg7h/bo +oejNGxyGOPbRDEYuyODJMCbVLH/BCL/MWoKO1NRJqqL65sGd8NmWsP8MWzOOBt2d +KKnpgEE72HqUIY9W8aK0K4kcdP9+kdwfkROYr8cG0kyQor3aFrplsC1ohzxuJY2Q +x7wNqUMDyb7PhW/bB3uM+LHCSRBpY1Y3xTDS+3Ga6IIHLj6VUPNzzzRb1asCFfLM +11LFKNhBGVVvuF/xmbPH2bNx9C3fIlk1hts5yhtNNZAZazHjyMYJv3ztAbSy9W7a +Y0E85jpyLWVI9gfNkoSLHacxa9bw+9n0AoIBAGZLu7fJSJUNWqYtoX/fH2dt7VJL +FmwXxq74asRX7S+z8CpVq7rK6hfoNXzlMQ1KlfxDb5c8XGesvmd/6U6qSLOSoXZ1 +6gQ0f4czLSS2KZfjBHeTiRPbG5O4LJAaCTsm2VnzKglY3KwltKlFO6I6bGGEv2jU +6pvFKUhgFRA1LEQdtZrurMFo6Ee3QTQ5mvilIOkkxCxYP0xBMDoUbo3qrbqbQ9OY +L4PYFGfo+NVPrOA7v6dUFl5JZCZUpGtpfLqKg9kuZQqiJ++ZmQjXtZ+gAe9+F7+D +ay7dwDk4I2i0dmvlyvd87sBS4t2tWTpCBkWwx8F3BbIMMkBGqtp5dwRx33oCFQCY +7rlRNz51ExMGj5TT5ukAy2Jtmg== +-----END DSA PRIVATE KEY----- diff --git a/certs/include.am b/certs/include.am index de8d2edf0..dd87e3265 100644 --- a/certs/include.am +++ b/certs/include.am @@ -73,7 +73,12 @@ EXTRA_DIST += \ certs/x942dh2048.der \ certs/x942dh2048.pem \ certs/fpki-cert.der \ - certs/rid-cert.der + certs/rid-cert.der \ + certs/dh-priv-2048.der \ + certs/dh-priv-2048.pem \ + certs/dh-pub-2048.der \ + certs/dh-pub-2048.pem \ + certs/dsa2048.pem EXTRA_DIST += \ certs/ca-key.der \ diff --git a/examples/client/client.c b/examples/client/client.c index 6a133f3dd..7c2aa674d 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -2166,6 +2166,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) (void)usePqc; (void)pqcAlg; (void)opensslPsk; + (void)fileFormat; StackTrap(); /* Reinitialize the global myVerifyAction. */ diff --git a/src/include.am b/src/include.am index 0125d17a0..9affbe345 100644 --- a/src/include.am +++ b/src/include.am @@ -21,7 +21,10 @@ EXTRA_DIST += src/ssl_asn1.c EXTRA_DIST += src/ssl_bn.c EXTRA_DIST += src/ssl_certman.c EXTRA_DIST += src/ssl_crypto.c +EXTRA_DIST += src/ssl_load.c EXTRA_DIST += src/ssl_misc.c +EXTRA_DIST += src/ssl_p7p12.c +EXTRA_DIST += src/ssl_sess.c EXTRA_DIST += src/x509.c EXTRA_DIST += src/x509_str.c diff --git a/src/pk.c b/src/pk.c index 65202c886..0947d8c2f 100644 --- a/src/pk.c +++ b/src/pk.c @@ -25,7 +25,7 @@ #include - #include +#include #ifndef WC_NO_RNG #include #endif @@ -49,14 +49,6 @@ #include #endif -#if defined(OPENSSL_EXTRA) && !defined(NO_BIO) && defined(WOLFSSL_KEY_GEN) && \ - (defined(HAVE_ECC) || (!defined(NO_DSA) && !defined(HAVE_SELFTEST))) -/* Forward declaration for wolfSSL_PEM_write_bio_DSA_PUBKEY. - * Implementation in ssl.c. - */ -static int pem_write_bio_pubkey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key); -#endif - /******************************************************************************* * COMMON FUNCTIONS ******************************************************************************/ @@ -167,8 +159,7 @@ static int pem_read_bio_key(WOLFSSL_BIO* bio, wc_pem_password_cb* cb, /* Write left over data back to BIO if not a file BIO */ if ((ret > 0) && ((memSz - ret) > 0) && (bio->type != WOLFSSL_BIO_FILE)) { - int res; - res = wolfSSL_BIO_write(bio, mem + ret, memSz - ret); + int res = wolfSSL_BIO_write(bio, mem + ret, memSz - ret); if (res != memSz - ret) { WOLFSSL_ERROR_MSG("Unable to write back excess data"); if (res < 0) { @@ -180,7 +171,7 @@ static int pem_read_bio_key(WOLFSSL_BIO* bio, wc_pem_password_cb* cb, } } if (alloced) { - XFREE(mem, NULL, DYNAMIC_TYPE_OPENSSL); + XFREE(mem, NULL, DYNAMIC_TYPE_TMP_BUFFER); } } @@ -229,33 +220,36 @@ static int pem_read_file_key(XFILE fp, wc_pem_password_cb* cb, void* pass, * @param [in] heap Heap hint for dynamic memory allocation. * @param [out] out Allocated buffer containing PEM. * @param [out] outSz Size of PEM encoding. - * @return WOLFSSL_FAILURE on error. - * @return WOLFSSL_SUCCESS on success. + * @return 1 on success. + * @return 0 on error. */ static int der_to_pem_alloc(const unsigned char* der, int derSz, int type, void* heap, byte** out, int* outSz) { - int ret = WOLFSSL_SUCCESS; + int ret = 1; int pemSz; byte* pem = NULL; (void)heap; + /* Convert DER to PEM - to get size. */ pemSz = wc_DerToPem(der, (word32)derSz, NULL, 0, type); if (pemSz < 0) { - ret = WOLFSSL_FAILURE; + ret = 0; } - if (ret == WOLFSSL_SUCCESS) { + if (ret == 1) { + /* Allocate memory for PEM to be encoded into. */ pem = (byte*)XMALLOC((size_t)pemSz, heap, DYNAMIC_TYPE_TMP_BUFFER); if (pem == NULL) { - ret = WOLFSSL_FAILURE; + ret = 0; } } - if ((ret == WOLFSSL_SUCCESS) && (wc_DerToPem(der, (word32)derSz, pem, - (word32)pemSz, type) < 0)) { - ret = WOLFSSL_FAILURE; + /* Convert DER to PEM. */ + if ((ret == 1) && (wc_DerToPem(der, (word32)derSz, pem, (word32)pemSz, + type) < 0)) { + ret = 0; XFREE(pem, heap, DYNAMIC_TYPE_TMP_BUFFER); pem = NULL; } @@ -272,8 +266,8 @@ static int der_to_pem_alloc(const unsigned char* der, int derSz, int type, * @param [in] derSz Size of DER data in bytes. * @param [in, out] bio BIO object to write with. * @param [in] type Type of key being encoded. - * @return WOLFSSL_FAILURE on error. - * @return WOLFSSL_SUCCESS on success. + * @return 1 on success. + * @return 0 on error. */ static int der_write_to_bio_as_pem(const unsigned char* der, int derSz, WOLFSSL_BIO* bio, int type) @@ -283,11 +277,11 @@ static int der_write_to_bio_as_pem(const unsigned char* der, int derSz, byte* pem = NULL; ret = der_to_pem_alloc(der, derSz, type, bio->heap, &pem, &pemSz); - if (ret == WOLFSSL_SUCCESS) { + if (ret == 1) { int len = wolfSSL_BIO_write(bio, pem, pemSz); if (len != pemSz) { WOLFSSL_ERROR_MSG("Unable to write full PEM to BIO"); - ret = WOLFSSL_FAILURE; + ret = 0; } } @@ -308,8 +302,8 @@ static int der_write_to_bio_as_pem(const unsigned char* der, int derSz, * @param [in] fp File pointer to write with. * @param [in] type Type of key being encoded. * @param [in] heap Heap hint for dynamic memory allocation. - * @return WOLFSSL_FAILURE on error. - * @return WOLFSSL_SUCCESS on success. + * @return 1 on success. + * @return 0 on error. */ static int der_write_to_file_as_pem(const unsigned char* der, int derSz, XFILE fp, int type, void* heap) @@ -319,11 +313,11 @@ static int der_write_to_file_as_pem(const unsigned char* der, int derSz, byte* pem = NULL; ret = der_to_pem_alloc(der, derSz, type, heap, &pem, &pemSz); - if (ret == WOLFSSL_SUCCESS) { + if (ret == 1) { int len = (int)XFWRITE(pem, 1, (size_t)pemSz, fp); if (len != pemSz) { WOLFSSL_ERROR_MSG("Unable to write full PEM to BIO"); - ret = WOLFSSL_FAILURE; + ret = 0; } } @@ -333,9 +327,153 @@ static int der_write_to_file_as_pem(const unsigned char* der, int derSz, #endif #endif +#if defined(WOLFSSL_KEY_GEN) && defined(WOLFSSL_PEM_TO_DER) +/* Encrypt private key into PEM format. + * + * DER is encrypted in place. + * + * @param [in] der DER encoding of private key. + * @param [in] derSz Size of DER in bytes. + * @param [in] cipher EVP cipher. + * @param [in] passwd Password to use with encryption. + * @param [in] passedSz Size of password in bytes. + * @param [out] cipherInfo PEM cipher information lines. + * @param [in] maxDerSz Maximum size of DER buffer. + * @return 1 on success. + * @return 0 on error. + */ +int EncryptDerKey(byte *der, int *derSz, const EVP_CIPHER* cipher, + unsigned char* passwd, int passwdSz, byte **cipherInfo, int maxDerSz) +{ + int ret = 0; + int paddingSz = 0; + word32 idx; + word32 cipherInfoSz; +#ifdef WOLFSSL_SMALL_STACK + EncryptedInfo* info = NULL; +#else + EncryptedInfo info[1]; +#endif + + WOLFSSL_ENTER("EncryptDerKey"); + + /* Validate parameters. */ + if ((der == NULL) || (derSz == NULL) || (cipher == NULL) || + (passwd == NULL) || (cipherInfo == NULL)) { + ret = BAD_FUNC_ARG; + } + + #ifdef WOLFSSL_SMALL_STACK + if (ret == 0) { + /* Allocate encrypted info. */ + info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL, + DYNAMIC_TYPE_ENCRYPTEDINFO); + if (info == NULL) { + WOLFSSL_MSG("malloc failed"); + ret = 0; + } + } + #endif + if (ret == 0) { + /* Clear the encrypted info and set name. */ + XMEMSET(info, 0, sizeof(EncryptedInfo)); + XSTRNCPY(info->name, cipher, NAME_SZ - 1); + info->name[NAME_SZ - 1] = '\0'; /* null term */ + + /* Get encrypted info from name. */ + ret = wc_EncryptedInfoGet(info, info->name); + if (ret != 0) { + WOLFSSL_MSG("unsupported cipher"); + } + } + + if (ret == 0) { + /* Generate a random salt. */ + if (wolfSSL_RAND_bytes(info->iv, info->ivSz) != 1) { + WOLFSSL_MSG("generate iv failed"); + ret = -1; + } + } + + if (ret == 0) { + /* Calculate padding size - always a padding block. */ + paddingSz = info->ivSz - ((*derSz) % info->ivSz); + /* Check der is big enough. */ + if (maxDerSz < (*derSz) + paddingSz) { + WOLFSSL_MSG("not enough DER buffer allocated"); + ret = BAD_FUNC_ARG; + } + } + if (ret == 0) { + /* Set padding bytes to padding length. */ + XMEMSET(der + (*derSz), (byte)paddingSz, paddingSz); + /* Add padding to DER size. */ + (*derSz) += (int)paddingSz; + + /* Encrypt DER buffer. */ + ret = wc_BufferKeyEncrypt(info, der, *derSz, passwd, passwdSz, WC_MD5); + if (ret != 0) { + WOLFSSL_MSG("encrypt key failed"); + } + } + + if (ret == 0) { + /* Create cipher info : 'cipher_name,Salt(hex)' */ + cipherInfoSz = (word32)(2 * info->ivSz + XSTRLEN(info->name) + 2); + /* Allocate memory for PEM encryption lines. */ + *cipherInfo = (byte*)XMALLOC(cipherInfoSz, NULL, DYNAMIC_TYPE_STRING); + if (*cipherInfo == NULL) { + WOLFSSL_MSG("malloc failed"); + ret = MEMORY_E; + } + } + if (ret == 0) { + /* Copy in name and add on comma. */ + XSTRLCPY((char*)*cipherInfo, info->name, cipherInfoSz); + XSTRLCAT((char*)*cipherInfo, ",", cipherInfoSz); + + /* Find end of string. */ + idx = (word32)XSTRLEN((char*)*cipherInfo); + /* Calculate remaining bytes. */ + cipherInfoSz -= idx; + + /* Encode IV into PEM encryption lines. */ + ret = Base16_Encode(info->iv, info->ivSz, *cipherInfo + idx, + &cipherInfoSz); + if (ret != 0) { + WOLFSSL_MSG("Base16_Encode failed"); + XFREE(*cipherInfo, NULL, DYNAMIC_TYPE_STRING); + *cipherInfo = NULL; + } + } + +#ifdef WOLFSSL_SMALL_STACK + /* Free dynamically allocated info. */ + XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); +#endif + return ret == 0; +} +#endif /* WOLFSSL_KEY_GEN || WOLFSSL_PEM_TO_DER */ + + #if defined(WOLFSSL_KEY_GEN) && \ (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) && \ (!defined(NO_RSA) || defined(HAVE_ECC)) +/* Encrypt the DER in PEM format. + * + * @param [in] der DER encoded private key. + * @param [in] derSz Size of DER in bytes. + * @param [in] cipher EVP cipher. + * @param [in] passwd Password to use in encryption. + * @param [in] passwdSz Size of password in bytes. + * @param [in] type PEM type of write out. + * @param [in] heap Dynamic memory hint. + * @param [out] out Allocated buffer containing PEM encoding. + * heap was NULL and dynamic type is DYNAMIC_TYPE_KEY. + * @param [out] outSz Size of PEM encoding in bytes. + * @return 1 on success. + * @return 0 on failure. + */ static int der_to_enc_pem_alloc(unsigned char* der, int derSz, const EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz, int type, void* heap, byte** out, int* outSz) @@ -736,8 +874,11 @@ static int wolfssl_print_number(WOLFSSL_BIO* bio, mp_int* num, const char* name, #endif /* XSNPRINTF && !NO_BIO && !NO_RSA */ -#if !defined(NO_RSA) || (!defined(NO_DH) && !defined(NO_CERTS) && \ - defined(HAVE_FIPS) && !FIPS_VERSION_GT(2,0)) || defined(HAVE_ECC) +#endif /* OPENSSL_EXTRA */ + +#if !defined(NO_CERTS) || (defined(OPENSSL_EXTRA) && (!defined(NO_RSA) || \ + (!defined(NO_DH) && defined(HAVE_FIPS) && !FIPS_VERSION_GT(2,0)) || \ + defined(HAVE_ECC))) /* Uses the DER SEQUENCE to determine size of DER data. * @@ -765,9 +906,7 @@ static int wolfssl_der_length(const unsigned char* seq, int len) return ret; } -#endif /* !NO_RSA */ - -#endif /* OPENSSL_EXTRA */ +#endif /******************************************************************************* * START OF RSA API @@ -1787,7 +1926,7 @@ int wolfSSL_PEM_write_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa) ret = 0; } if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, - PUBLICKEY_TYPE) != WOLFSSL_SUCCESS)) { + PUBLICKEY_TYPE) != 1)) { ret = 0; } @@ -1832,7 +1971,7 @@ static int wolfssl_pem_write_rsa_public_key(XFILE fp, WOLFSSL_RSA* rsa, ret = 0; } if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, type, - rsa->heap) != WOLFSSL_SUCCESS)) { + rsa->heap) != 1)) { ret = 0; } @@ -5577,99 +5716,115 @@ WOLFSSL_DSA* wolfSSL_d2i_DSAparams(WOLFSSL_DSA** dsa, const unsigned char** der, * Returns 1 or 0 */ int wolfSSL_PEM_write_bio_DSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_DSA* dsa, - const EVP_CIPHER* cipher, - unsigned char* passwd, int len, - wc_pem_password_cb* cb, void* arg) + const EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, + wc_pem_password_cb* cb, void* arg) { - int ret = 0, der_max_len = 0, derSz = 0; - byte *derBuf; - WOLFSSL_EVP_PKEY* pkey; + int ret = 1; + byte *pem = NULL; + int pLen = 0; WOLFSSL_ENTER("wolfSSL_PEM_write_bio_DSAPrivateKey"); - if (bio == NULL || dsa == NULL) { + (void)cb; + (void)arg; + + /* Validate parameters. */ + if ((bio == NULL) || (dsa == NULL)) { WOLFSSL_MSG("Bad Function Arguments"); - return 0; + ret = 0; } - pkey = wolfSSL_EVP_PKEY_new_ex(bio->heap); - if (pkey == NULL) { - WOLFSSL_MSG("wolfSSL_EVP_PKEY_new_ex failed"); - return 0; + if (ret == 1) { + ret = wolfSSL_PEM_write_mem_DSAPrivateKey(dsa, cipher, passwd, passwdSz, + &pem, &pLen); } - pkey->type = EVP_PKEY_DSA; - pkey->dsa = dsa; - pkey->ownDsa = 0; - - /* 4 > size of pub, priv, p, q, g + ASN.1 additional information */ - der_max_len = MAX_DSA_PRIVKEY_SZ; - - derBuf = (byte*)XMALLOC((size_t)der_max_len, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (derBuf == NULL) { - WOLFSSL_MSG("Malloc failed"); - wolfSSL_EVP_PKEY_free(pkey); - return 0; + /* Write PEM to BIO. */ + if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) != pLen)) { + WOLFSSL_ERROR_MSG("DSA private key BIO write failed"); + ret = 0; } - /* convert key to der format */ - derSz = wc_DsaKeyToDer((DsaKey*)dsa->internal, derBuf, (word32)der_max_len); - if (derSz < 0) { - WOLFSSL_MSG("wc_DsaKeyToDer failed"); - XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - wolfSSL_EVP_PKEY_free(pkey); - return 0; - } - - pkey->pkey.ptr = (char*)XMALLOC((size_t)derSz, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (pkey->pkey.ptr == NULL) { - WOLFSSL_MSG("key malloc failed"); - XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - wolfSSL_EVP_PKEY_free(pkey); - return 0; - } - - /* add der info to the evp key */ - pkey->pkey_sz = derSz; - XMEMCPY(pkey->pkey.ptr, derBuf, (size_t)derSz); - XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - - ret = wolfSSL_PEM_write_bio_PrivateKey(bio, pkey, cipher, passwd, len, - cb, arg); - wolfSSL_EVP_PKEY_free(pkey); - + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); return ret; } #ifndef HAVE_SELFTEST +/* Encode the DSA public key as DER. + * + * @param [in] key DSA key to encode. + * @param [out] der Pointer through which buffer is returned. + * @param [in] heap Heap hint. + * @return Size of encoding on success. + * @return 0 on error. + */ +static int wolfssl_dsa_key_to_pubkey_der(WOLFSSL_DSA* key, unsigned char** der, + void* heap) +{ + int sz; + unsigned char* buf = NULL; + + /* Use maximum encoded size to allocate. */ + sz = MAX_DSA_PUBKEY_SZ; + /* Allocate memory to hold encoding. */ + buf = (byte*)XMALLOC((size_t)sz, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + WOLFSSL_MSG("malloc failed"); + sz = 0; + } + if (sz > 0) { + /* Encode public key to DER using wolfSSL. */ + sz = wc_DsaKeyToPublicDer((DsaKey*)key->internal, buf, sz); + if (sz < 0) { + WOLFSSL_MSG("wc_DsaKeyToPublicDer failed"); + sz = 0; + } + } + + /* Return buffer on success. */ + if (sz > 0) { + *der = buf; + } + else { + /* Dispose of any dynamically allocated data not returned. */ + XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER); + } + + return sz; +} + /* Takes a DSA public key and writes it out to a WOLFSSL_BIO * Returns 1 or 0 */ int wolfSSL_PEM_write_bio_DSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_DSA* dsa) { - int ret = 0; - WOLFSSL_EVP_PKEY* pkey; + int ret = 1; + unsigned char* derBuf = NULL; + int derSz = 0; + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_DSA_PUBKEY"); - if (bio == NULL || dsa == NULL) { - WOLFSSL_MSG("Bad function arguments"); + /* Validate parameters. */ + if ((bio == NULL) || (dsa == NULL)) { + WOLFSSL_MSG("Bad Function Arguments"); return 0; } - pkey = wolfSSL_EVP_PKEY_new_ex(bio->heap); - if (pkey == NULL) { - WOLFSSL_MSG("wolfSSL_EVP_PKEY_new_ex failed"); - return 0; + /* Encode public key in EC key as DER. */ + derSz = wolfssl_dsa_key_to_pubkey_der(dsa, &derBuf, bio->heap); + if (derSz == 0) { + ret = 0; } - pkey->type = EVP_PKEY_DSA; - pkey->dsa = dsa; - pkey->ownDsa = 0; + /* Write out to BIO the PEM encoding of the DSA public key. */ + if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, + PUBLICKEY_TYPE) != 1)) { + ret = 0; + } + + /* Dispose of any dynamically allocated data. */ + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - ret = pem_write_bio_pubkey(bio, pkey); - wolfSSL_EVP_PKEY_free(pkey); return ret; } #endif /* HAVE_SELFTEST */ @@ -7455,7 +7610,7 @@ static WOLFSSL_DH *wolfssl_dhparams_read_pem(WOLFSSL_DH **dh, } if (memAlloced) { /* PEM data no longer needed. */ - XFREE(pem, NULL, DYNAMIC_TYPE_PEM); + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); } if (!err) { @@ -7681,7 +7836,7 @@ int wolfSSL_PEM_write_DHparams(XFILE fp, WOLFSSL_DH* dh) } } if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, - DH_PARAM_TYPE, NULL) != WOLFSSL_SUCCESS)) { + DH_PARAM_TYPE, NULL) != 1)) { ret = 0; } @@ -12076,12 +12231,9 @@ int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, * EC key PEM APIs */ -#if (defined(WOLFSSL_KEY_GEN) && !defined(NO_FILESYSTEM)) || \ - (!defined(NO_BIO) && (defined(WOLFSSL_KEY_GEN) || \ - defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT))) +#ifdef HAVE_ECC_KEY_EXPORT +#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_FILESYSTEM) || !defined(NO_BIO)) /* Encode the EC public key as DER. - * - * Also used by pem_write_pubkey(). * * @param [in] key EC key to encode. * @param [out] der Pointer through which buffer is returned. @@ -12176,6 +12328,7 @@ int wolfSSL_PEM_write_EC_PUBKEY(XFILE fp, WOLFSSL_EC_KEY* key) return ret; } #endif +#endif #ifndef NO_BIO /* Read a PEM encoded EC public key from a BIO. @@ -12302,7 +12455,7 @@ WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_ECPrivateKey(WOLFSSL_BIO* bio, } #endif /* !NO_BIO */ -#if defined(WOLFSSL_KEY_GEN) +#if defined(WOLFSSL_KEY_GEN) && defined(HAVE_ECC_KEY_EXPORT) #ifndef NO_BIO /* Write out the EC public key as PEM to the BIO. * @@ -12331,7 +12484,7 @@ int wolfSSL_PEM_write_bio_EC_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec) ret = 0; } - /* Write out to BIO the PEM encoding of the EC private key. */ + /* Write out to BIO the PEM encoding of the EC public key. */ if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, ECC_PUBLICKEY_TYPE) != 1)) { ret = 0; @@ -12534,7 +12687,7 @@ int wolfSSL_PEM_write_ECPrivateKey(XFILE fp, WOLFSSL_EC_KEY *ec, } #endif /* NO_FILESYSTEM */ -#endif /* defined(WOLFSSL_KEY_GEN) */ +#endif /* WOLFSSL_KEY_GEN && HAVE_ECC_KEY_EXPORT */ /* * EC key print APIs @@ -13116,7 +13269,7 @@ int wolfSSL_EC_KEY_generate_key(WOLFSSL_EC_KEY *key) /* Create a random number generator. */ rng = wolfssl_make_rng(tmpRng, &initTmpRng); if (rng == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key failed to set RNG"); + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key failed to make RNG"); res = 0; } } @@ -13892,5 +14045,2234 @@ int wolfSSL_ECDH_compute_key(void *out, size_t outLen, * END OF EC API ******************************************************************************/ +/******************************************************************************* + * START OF EC25519 API + ******************************************************************************/ + +#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE25519) + +/* Generate an EC25519 key pair. + * + * Output keys are in little endian format. + * + * @param [out] priv EC25519 private key data. + * @param [in, out] privSz On in, the size of priv in bytes. + * On out, the length of the private key data in bytes. + * @param [out] pub EC25519 public key data. + * @param [in, out] pubSz On in, the size of pub in bytes. + * On out, the length of the public key data in bytes. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC25519_generate_key(unsigned char *priv, unsigned int *privSz, + unsigned char *pub, unsigned int *pubSz) +{ +#ifdef WOLFSSL_KEY_GEN + int res = 1; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG *tmpRng = NULL; +#else + WC_RNG tmpRng[1]; +#endif + curve25519_key key; + + WOLFSSL_ENTER("wolfSSL_EC25519_generate_key"); + + /* Validate parameters. */ + if ((priv == NULL) || (privSz == NULL) || (*privSz < CURVE25519_KEYSIZE) || + (pub == NULL) || (pubSz == NULL) || (*pubSz < CURVE25519_KEYSIZE)) { + WOLFSSL_MSG("Bad arguments"); + res = 0; + } + + if (res) { + /* Create a random number generator. */ + rng = wolfssl_make_rng(tmpRng, &initTmpRng); + if (rng == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key failed to make RNG"); + res = 0; + } + } + + /* Initialize a Curve25519 key. */ + if (res && (wc_curve25519_init(&key) != 0)) { + WOLFSSL_MSG("wc_curve25519_init failed"); + res = 0; + } + if (res) { + /* Make a Curve25519 key pair. */ + int ret = wc_curve25519_make_key(rng, CURVE25519_KEYSIZE, &key); + if (ret != MP_OKAY) { + WOLFSSL_MSG("wc_curve25519_make_key failed"); + res = 0; + } + if (res) { + /* Export Curve25519 key pair to buffers. */ + ret = wc_curve25519_export_key_raw_ex(&key, priv, privSz, pub, + pubSz, EC25519_LITTLE_ENDIAN); + if (ret != MP_OKAY) { + WOLFSSL_MSG("wc_curve25519_export_key_raw_ex failed"); + res = 0; + } + } + + /* Dispose of key. */ + wc_curve25519_free(&key); + } + + if (initTmpRng) { + wc_FreeRng(rng); + #ifdef WOLFSSL_SMALL_STACK + XFREE(rng, NULL, DYNAMIC_TYPE_RNG); + #endif + } + + return res; +#else + WOLFSSL_MSG("No Key Gen built in"); + + (void)priv; + (void)privSz; + (void)pub; + (void)pubSz; + + return 0; +#endif /* WOLFSSL_KEY_GEN */ +} + +/* Compute a shared secret from private and public EC25519 keys. + * + * Input and output keys are in little endian format + * + * @param [out] shared Shared secret buffer. + * @param [in, out] sharedSz On in, the size of shared in bytes. + * On out, the length of the secret in bytes. + * @param [in] priv EC25519 private key data. + * @param [in] privSz Length of the private key data in bytes. + * @param [in] pub EC25519 public key data. + * @param [in] pubSz Length of the public key data in bytes. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC25519_shared_key(unsigned char *shared, unsigned int *sharedSz, + const unsigned char *priv, unsigned int privSz, const unsigned char *pub, + unsigned int pubSz) +{ +#ifdef WOLFSSL_KEY_GEN + int res = 1; + curve25519_key privkey; + curve25519_key pubkey; + + WOLFSSL_ENTER("wolfSSL_EC25519_shared_key"); + + /* Validate parameters. */ + if ((shared == NULL) || (sharedSz == NULL) || + (*sharedSz < CURVE25519_KEYSIZE) || (priv == NULL) || + (privSz < CURVE25519_KEYSIZE) || (pub == NULL) || + (pubSz < CURVE25519_KEYSIZE)) { + WOLFSSL_MSG("Bad arguments"); + res = 0; + } + + /* Initialize private key object. */ + if (res && (wc_curve25519_init(&privkey) != 0)) { + WOLFSSL_MSG("wc_curve25519_init privkey failed"); + res = 0; + } + if (res) { + /* Initialize public key object. */ + if (wc_curve25519_init(&pubkey) != MP_OKAY) { + WOLFSSL_MSG("wc_curve25519_init pubkey failed"); + res = 0; + } + if (res) { + /* Import our private key. */ + int ret = wc_curve25519_import_private_ex(priv, privSz, &privkey, + EC25519_LITTLE_ENDIAN); + if (ret != 0) { + WOLFSSL_MSG("wc_curve25519_import_private_ex failed"); + res = 0; + } + + if (res) { + /* Import peer's public key. */ + ret = wc_curve25519_import_public_ex(pub, pubSz, &pubkey, + EC25519_LITTLE_ENDIAN); + if (ret != 0) { + WOLFSSL_MSG("wc_curve25519_import_public_ex failed"); + res = 0; + } + } + if (res) { + /* Compute shared secret. */ + ret = wc_curve25519_shared_secret_ex(&privkey, &pubkey, shared, + sharedSz, EC25519_LITTLE_ENDIAN); + if (ret != 0) { + WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed"); + res = 0; + } + } + + wc_curve25519_free(&pubkey); + } + wc_curve25519_free(&privkey); + } + + return res; +#else + WOLFSSL_MSG("No Key Gen built in"); + + (void)shared; + (void)sharedSz; + (void)priv; + (void)privSz; + (void)pub; + (void)pubSz; + + return 0; +#endif /* WOLFSSL_KEY_GEN */ +} +#endif /* OPENSSL_EXTRA && HAVE_CURVE25519 */ + +/******************************************************************************* + * END OF EC25519 API + ******************************************************************************/ + +/******************************************************************************* + * START OF ED25519 API + ******************************************************************************/ + +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) +/* Generate an ED25519 key pair. + * + * Output keys are in little endian format. + * + * @param [out] priv ED25519 private key data. + * @param [in, out] privSz On in, the size of priv in bytes. + * On out, the length of the private key data in bytes. + * @param [out] pub ED25519 public key data. + * @param [in, out] pubSz On in, the size of pub in bytes. + * On out, the length of the public key data in bytes. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_ED25519_generate_key(unsigned char *priv, unsigned int *privSz, + unsigned char *pub, unsigned int *pubSz) +{ +#if defined(WOLFSSL_KEY_GEN) && defined(HAVE_ED25519_KEY_EXPORT) + int res = 1; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG *tmpRng = NULL; +#else + WC_RNG tmpRng[1]; +#endif + ed25519_key key; + + WOLFSSL_ENTER("wolfSSL_ED25519_generate_key"); + + /* Validate parameters. */ + if ((priv == NULL) || (privSz == NULL) || + (*privSz < ED25519_PRV_KEY_SIZE) || (pub == NULL) || + (pubSz == NULL) || (*pubSz < ED25519_PUB_KEY_SIZE)) { + WOLFSSL_MSG("Bad arguments"); + res = 0; + } + + if (res) { + /* Create a random number generator. */ + rng = wolfssl_make_rng(tmpRng, &initTmpRng); + if (rng == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key failed to make RNG"); + res = 0; + } + } + + /* Initialize an Ed25519 key. */ + if (res && (wc_ed25519_init(&key) != 0)) { + WOLFSSL_MSG("wc_ed25519_init failed"); + res = 0; + } + if (res) { + /* Make an Ed25519 key pair. */ + int ret = wc_ed25519_make_key(rng, ED25519_KEY_SIZE, &key); + if (ret != 0) { + WOLFSSL_MSG("wc_ed25519_make_key failed"); + res = 0; + } + if (res) { + /* Export Curve25519 key pair to buffers. */ + ret = wc_ed25519_export_key(&key, priv, privSz, pub, pubSz); + if (ret != 0) { + WOLFSSL_MSG("wc_ed25519_export_key failed"); + res = 0; + } + } + + wc_ed25519_free(&key); + } + + if (initTmpRng) { + wc_FreeRng(rng); + #ifdef WOLFSSL_SMALL_STACK + XFREE(rng, NULL, DYNAMIC_TYPE_RNG); + #endif + } + + return res; +#else +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); +#else + WOLFSSL_MSG("No ED25519 key export built in"); +#endif + + (void)priv; + (void)privSz; + (void)pub; + (void)pubSz; + + return 0; +#endif /* WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_EXPORT */ +} + +/* Sign a message with Ed25519 using the private key. + * + * Input and output keys are in little endian format. + * Priv is a buffer containing private and public part of key. + * + * @param [in] msg Message to be signed. + * @param [in] msgSz Length of message in bytes. + * @param [in] priv ED25519 private key data. + * @param [in] privSz Length in bytes of private key data. + * @param [out] sig Signature buffer. + * @param [in, out] sigSz On in, the length of the siganture buffer in bytes. + * On out, the length of the signature in bytes. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_ED25519_sign(const unsigned char *msg, unsigned int msgSz, + const unsigned char *priv, unsigned int privSz, unsigned char *sig, + unsigned int *sigSz) +{ +#if defined(HAVE_ED25519_SIGN) && defined(WOLFSSL_KEY_GEN) && \ + defined(HAVE_ED25519_KEY_IMPORT) + ed25519_key key; + int res = 1; + + WOLFSSL_ENTER("wolfSSL_ED25519_sign"); + + /* Validate parameters. */ + if ((priv == NULL) || (privSz != ED25519_PRV_KEY_SIZE) || + (msg == NULL) || (sig == NULL) || (sigSz == NULL) || + (*sigSz < ED25519_SIG_SIZE)) { + WOLFSSL_MSG("Bad arguments"); + res = 0; + } + + /* Initialize Ed25519 key. */ + if (res && (wc_ed25519_init(&key) != 0)) { + WOLFSSL_MSG("wc_curve25519_init failed"); + res = 0; + } + if (res) { + /* Import private and public key. */ + int ret = wc_ed25519_import_private_key(priv, privSz / 2, + priv + (privSz / 2), ED25519_PUB_KEY_SIZE, &key); + if (ret != 0) { + WOLFSSL_MSG("wc_ed25519_import_private failed"); + res = 0; + } + + if (res) { + /* Sign message with Ed25519. */ + ret = wc_ed25519_sign_msg(msg, msgSz, sig, sigSz, &key); + if (ret != 0) { + WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed"); + res = 0; + } + } + + wc_ed25519_free(&key); + } + + return res; +#else +#if !defined(HAVE_ED25519_SIGN) + WOLFSSL_MSG("No ED25519 sign built in"); +#elif !defined(WOLFSSL_KEY_GEN) + WOLFSSL_MSG("No Key Gen built in"); +#elif !defined(HAVE_ED25519_KEY_IMPORT) + WOLFSSL_MSG("No ED25519 Key import built in"); +#endif + + (void)msg; + (void)msgSz; + (void)priv; + (void)privSz; + (void)sig; + (void)sigSz; + + return 0; +#endif /* HAVE_ED25519_SIGN && WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_IMPORT */ +} + +/* Verify a message with Ed25519 using the public key. + * + * Input keys are in little endian format. + * + * @param [in] msg Message to be verified. + * @param [in] msgSz Length of message in bytes. + * @param [in] pub ED25519 public key data. + * @param [in] privSz Length in bytes of public key data. + * @param [in] sig Signature buffer. + * @param [in] sigSz Length of the signature in bytes. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_ED25519_verify(const unsigned char *msg, unsigned int msgSz, + const unsigned char *pub, unsigned int pubSz, const unsigned char *sig, + unsigned int sigSz) +{ +#if defined(HAVE_ED25519_VERIFY) && defined(WOLFSSL_KEY_GEN) && \ + defined(HAVE_ED25519_KEY_IMPORT) + ed25519_key key; + int res = 1; + + WOLFSSL_ENTER("wolfSSL_ED25519_verify"); + + /* Validate parameters. */ + if ((pub == NULL) || (pubSz != ED25519_PUB_KEY_SIZE) || (msg == NULL) || + (sig == NULL) || (sigSz != ED25519_SIG_SIZE)) { + WOLFSSL_MSG("Bad arguments"); + res = 0; + } + + /* Initialize Ed25519 key. */ + if (res && (wc_ed25519_init(&key) != 0)) { + WOLFSSL_MSG("wc_curve25519_init failed"); + res = 0; + } + if (res) { + /* Import public key. */ + int ret = wc_ed25519_import_public(pub, pubSz, &key); + if (ret != 0) { + WOLFSSL_MSG("wc_ed25519_import_public failed"); + res = 0; + } + + if (res) { + int check = 0; + + /* Verify signature with message and public key. */ + ret = wc_ed25519_verify_msg((byte*)sig, sigSz, msg, msgSz, &check, + &key); + /* Check for errors in verification process. */ + if (ret != 0) { + WOLFSSL_MSG("wc_ed25519_verify_msg failed"); + res = 0; + } + /* Check signature is valid. */ + else if (!check) { + WOLFSSL_MSG("wc_ed25519_verify_msg failed (signature invalid)"); + res = 0; + } + } + + wc_ed25519_free(&key); + } + + return res; +#else +#if !defined(HAVE_ED25519_VERIFY) + WOLFSSL_MSG("No ED25519 verify built in"); +#elif !defined(WOLFSSL_KEY_GEN) + WOLFSSL_MSG("No Key Gen built in"); +#elif !defined(HAVE_ED25519_KEY_IMPORT) + WOLFSSL_MSG("No ED25519 Key import built in"); +#endif + + (void)msg; + (void)msgSz; + (void)pub; + (void)pubSz; + (void)sig; + (void)sigSz; + + return 0; +#endif /* HAVE_ED25519_VERIFY && WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_IMPORT */ +} + +#endif /* OPENSSL_EXTRA && HAVE_ED25519 */ + +/******************************************************************************* + * END OF ED25519 API + ******************************************************************************/ + +/******************************************************************************* + * START OF EC448 API + ******************************************************************************/ + +#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE448) +/* Generate an EC448 key pair. + * + * Output keys are in little endian format. + * + * @param [out] priv EC448 private key data. + * @param [in, out] privSz On in, the size of priv in bytes. + * On out, the length of the private key data in bytes. + * @param [out] pub EC448 public key data. + * @param [in, out] pubSz On in, the size of pub in bytes. + * On out, the length of the public key data in bytes. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC448_generate_key(unsigned char *priv, unsigned int *privSz, + unsigned char *pub, unsigned int *pubSz) +{ +#ifdef WOLFSSL_KEY_GEN + int res = 1; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG *tmpRng = NULL; +#else + WC_RNG tmpRng[1]; +#endif + curve448_key key; + + WOLFSSL_ENTER("wolfSSL_EC448_generate_key"); + + /* Validate parameters. */ + if ((priv == NULL) || (privSz == NULL) || (*privSz < CURVE448_KEY_SIZE) || + (pub == NULL) || (pubSz == NULL) || (*pubSz < CURVE448_KEY_SIZE)) { + WOLFSSL_MSG("Bad arguments"); + res = 0; + } + + if (res) { + /* Create a random number generator. */ + rng = wolfssl_make_rng(tmpRng, &initTmpRng); + if (rng == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key failed to make RNG"); + res = 0; + } + } + + /* Initialize a Curve448 key. */ + if (res && (wc_curve448_init(&key) != 0)) { + WOLFSSL_MSG("wc_curve448_init failed"); + res = 0; + } + if (res) { + /* Make a Curve448 key pair. */ + int ret = wc_curve448_make_key(rng, CURVE448_KEY_SIZE, &key); + if (ret != 0) { + WOLFSSL_MSG("wc_curve448_make_key failed"); + res = 0; + } + if (res) { + /* Export Curve448 key pair to buffers. */ + ret = wc_curve448_export_key_raw_ex(&key, priv, privSz, pub, pubSz, + EC448_LITTLE_ENDIAN); + if (ret != 0) { + WOLFSSL_MSG("wc_curve448_export_key_raw_ex failed"); + res = 0; + } + } + + /* Dispose of key. */ + wc_curve448_free(&key); + } + + if (initTmpRng) { + wc_FreeRng(rng); + #ifdef WOLFSSL_SMALL_STACK + XFREE(rng, NULL, DYNAMIC_TYPE_RNG); + #endif + } + + return res; +#else + WOLFSSL_MSG("No Key Gen built in"); + + (void)priv; + (void)privSz; + (void)pub; + (void)pubSz; + + return 0; +#endif /* WOLFSSL_KEY_GEN */ +} + +/* Compute a shared secret from private and public EC448 keys. + * + * Input and output keys are in little endian format + * + * @param [out] shared Shared secret buffer. + * @param [in, out] sharedSz On in, the size of shared in bytes. + * On out, the length of the secret in bytes. + * @param [in] priv EC448 private key data. + * @param [in] privSz Length of the private key data in bytes. + * @param [in] pub EC448 public key data. + * @param [in] pubSz Length of the public key data in bytes. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC448_shared_key(unsigned char *shared, unsigned int *sharedSz, + const unsigned char *priv, unsigned int privSz, + const unsigned char *pub, unsigned int pubSz) +{ +#ifdef WOLFSSL_KEY_GEN + int res = 1; + curve448_key privkey; + curve448_key pubkey; + + WOLFSSL_ENTER("wolfSSL_EC448_shared_key"); + + /* Validate parameters. */ + if ((shared == NULL) || (sharedSz == NULL) || + (*sharedSz < CURVE448_KEY_SIZE) || (priv == NULL) || + (privSz < CURVE448_KEY_SIZE) || (pub == NULL) || + (pubSz < CURVE448_KEY_SIZE)) { + WOLFSSL_MSG("Bad arguments"); + res = 0; + } + + /* Initialize private key object. */ + if (res && (wc_curve448_init(&privkey) != 0)) { + WOLFSSL_MSG("wc_curve448_init privkey failed"); + res = 0; + } + if (res) { + /* Initialize public key object. */ + if (wc_curve448_init(&pubkey) != MP_OKAY) { + WOLFSSL_MSG("wc_curve448_init pubkey failed"); + res = 0; + } + if (res) { + /* Import our private key. */ + int ret = wc_curve448_import_private_ex(priv, privSz, &privkey, + EC448_LITTLE_ENDIAN); + if (ret != 0) { + WOLFSSL_MSG("wc_curve448_import_private_ex failed"); + res = 0; + } + + if (res) { + /* Import peer's public key. */ + ret = wc_curve448_import_public_ex(pub, pubSz, &pubkey, + EC448_LITTLE_ENDIAN); + if (ret != 0) { + WOLFSSL_MSG("wc_curve448_import_public_ex failed"); + res = 0; + } + } + if (res) { + /* Compute shared secret. */ + ret = wc_curve448_shared_secret_ex(&privkey, &pubkey, shared, + sharedSz, EC448_LITTLE_ENDIAN); + if (ret != 0) { + WOLFSSL_MSG("wc_curve448_shared_secret_ex failed"); + res = 0; + } + } + + wc_curve448_free(&pubkey); + } + wc_curve448_free(&privkey); + } + + return res; +#else + WOLFSSL_MSG("No Key Gen built in"); + + (void)shared; + (void)sharedSz; + (void)priv; + (void)privSz; + (void)pub; + (void)pubSz; + + return 0; +#endif /* WOLFSSL_KEY_GEN */ +} +#endif /* OPENSSL_EXTRA && HAVE_CURVE448 */ + +/******************************************************************************* + * END OF EC448 API + ******************************************************************************/ + +/******************************************************************************* + * START OF ED448 API + ******************************************************************************/ + +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED448) +/* Generate an ED448 key pair. + * + * Output keys are in little endian format. + * + * @param [out] priv ED448 private key data. + * @param [in, out] privSz On in, the size of priv in bytes. + * On out, the length of the private key data in bytes. + * @param [out] pub ED448 public key data. + * @param [in, out] pubSz On in, the size of pub in bytes. + * On out, the length of the public key data in bytes. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_ED448_generate_key(unsigned char *priv, unsigned int *privSz, + unsigned char *pub, unsigned int *pubSz) +{ +#if defined(WOLFSSL_KEY_GEN) && defined(HAVE_ED448_KEY_EXPORT) + int res = 1; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG *tmpRng = NULL; +#else + WC_RNG tmpRng[1]; +#endif + ed448_key key; + + WOLFSSL_ENTER("wolfSSL_ED448_generate_key"); + + /* Validate parameters. */ + if ((priv == NULL) || (privSz == NULL) || + (*privSz < ED448_PRV_KEY_SIZE) || (pub == NULL) || + (pubSz == NULL) || (*pubSz < ED448_PUB_KEY_SIZE)) { + WOLFSSL_MSG("Bad arguments"); + res = 0; + } + + if (res) { + /* Create a random number generator. */ + rng = wolfssl_make_rng(tmpRng, &initTmpRng); + if (rng == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key failed to make RNG"); + res = 0; + } + } + + /* Initialize an Ed448 key. */ + if (res && (wc_ed448_init(&key) != 0)) { + WOLFSSL_MSG("wc_ed448_init failed"); + res = 0; + } + if (res) { + /* Make an Ed448 key pair. */ + int ret = wc_ed448_make_key(rng, ED448_KEY_SIZE, &key); + if (ret != 0) { + WOLFSSL_MSG("wc_ed448_make_key failed"); + res = 0; + } + if (res) { + /* Export Curve448 key pair to buffers. */ + ret = wc_ed448_export_key(&key, priv, privSz, pub, pubSz); + if (ret != 0) { + WOLFSSL_MSG("wc_ed448_export_key failed"); + res = 0; + } + } + + wc_ed448_free(&key); + } + + if (initTmpRng) { + wc_FreeRng(rng); + #ifdef WOLFSSL_SMALL_STACK + XFREE(rng, NULL, DYNAMIC_TYPE_RNG); + #endif + } + + return res; +#else +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); +#else + WOLFSSL_MSG("No ED448 key export built in"); +#endif + + (void)priv; + (void)privSz; + (void)pub; + (void)pubSz; + + return 0; +#endif /* WOLFSSL_KEY_GEN && HAVE_ED448_KEY_EXPORT */ +} + +/* Sign a message with Ed448 using the private key. + * + * Input and output keys are in little endian format. + * Priv is a buffer containing private and public part of key. + * + * @param [in] msg Message to be signed. + * @param [in] msgSz Length of message in bytes. + * @param [in] priv ED448 private key data. + * @param [in] privSz Length in bytes of private key data. + * @param [out] sig Signature buffer. + * @param [in, out] sigSz On in, the length of the siganture buffer in bytes. + * On out, the length of the signature in bytes. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_ED448_sign(const unsigned char *msg, unsigned int msgSz, + const unsigned char *priv, unsigned int privSz, unsigned char *sig, + unsigned int *sigSz) +{ +#if defined(HAVE_ED448_SIGN) && defined(WOLFSSL_KEY_GEN) && \ + defined(HAVE_ED448_KEY_IMPORT) + ed448_key key; + int res = 1; + + WOLFSSL_ENTER("wolfSSL_ED448_sign"); + + /* Validate parameters. */ + if ((priv == NULL) || (privSz != ED448_PRV_KEY_SIZE) || + (msg == NULL) || (sig == NULL) || (sigSz == NULL) || + (*sigSz < ED448_SIG_SIZE)) { + WOLFSSL_MSG("Bad arguments"); + res = 0; + } + + /* Initialize Ed448 key. */ + if (res && (wc_ed448_init(&key) != 0)) { + WOLFSSL_MSG("wc_curve448_init failed"); + res = 0; + } + if (res) { + /* Import private and public key. */ + int ret = wc_ed448_import_private_key(priv, privSz / 2, + priv + (privSz / 2), ED448_PUB_KEY_SIZE, &key); + if (ret != 0) { + WOLFSSL_MSG("wc_ed448_import_private failed"); + res = 0; + } + + if (res) { + /* Sign message with Ed448 - no context. */ + ret = wc_ed448_sign_msg(msg, msgSz, sig, sigSz, &key, NULL, 0); + if (ret != 0) { + WOLFSSL_MSG("wc_curve448_shared_secret_ex failed"); + res = 0; + } + } + + wc_ed448_free(&key); + } + + return res; +#else +#if !defined(HAVE_ED448_SIGN) + WOLFSSL_MSG("No ED448 sign built in"); +#elif !defined(WOLFSSL_KEY_GEN) + WOLFSSL_MSG("No Key Gen built in"); +#elif !defined(HAVE_ED448_KEY_IMPORT) + WOLFSSL_MSG("No ED448 Key import built in"); +#endif + + (void)msg; + (void)msgSz; + (void)priv; + (void)privSz; + (void)sig; + (void)sigSz; + + return 0; +#endif /* HAVE_ED448_SIGN && WOLFSSL_KEY_GEN && HAVE_ED448_KEY_IMPORT */ +} + +/* Verify a message with Ed448 using the public key. + * + * Input keys are in little endian format. + * + * @param [in] msg Message to be verified. + * @param [in] msgSz Length of message in bytes. + * @param [in] pub ED448 public key data. + * @param [in] privSz Length in bytes of public key data. + * @param [in] sig Signature buffer. + * @param [in] sigSz Length of the signature in bytes. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_ED448_verify(const unsigned char *msg, unsigned int msgSz, + const unsigned char *pub, unsigned int pubSz, const unsigned char *sig, + unsigned int sigSz) +{ +#if defined(HAVE_ED448_VERIFY) && defined(WOLFSSL_KEY_GEN) && \ + defined(HAVE_ED448_KEY_IMPORT) + ed448_key key; + int res = 1; + + WOLFSSL_ENTER("wolfSSL_ED448_verify"); + + /* Validate parameters. */ + if ((pub == NULL) || (pubSz != ED448_PUB_KEY_SIZE) || (msg == NULL) || + (sig == NULL) || (sigSz != ED448_SIG_SIZE)) { + WOLFSSL_MSG("Bad arguments"); + res = 0; + } + + /* Initialize Ed448 key. */ + if (res && (wc_ed448_init(&key) != 0)) { + WOLFSSL_MSG("wc_curve448_init failed"); + res = 0; + } + if (res) { + /* Import public key. */ + int ret = wc_ed448_import_public(pub, pubSz, &key); + if (ret != 0) { + WOLFSSL_MSG("wc_ed448_import_public failed"); + res = 0; + } + + if (res) { + int check = 0; + + /* Verify signature with message and public key - no context. */ + ret = wc_ed448_verify_msg((byte*)sig, sigSz, msg, msgSz, &check, + &key, NULL, 0); + /* Check for errors in verification process. */ + if (ret != 0) { + WOLFSSL_MSG("wc_ed448_verify_msg failed"); + res = 0; + } + /* Check signature is valid. */ + else if (!check) { + WOLFSSL_MSG("wc_ed448_verify_msg failed (signature invalid)"); + res = 0; + } + } + + wc_ed448_free(&key); + } + + return res; +#else +#if !defined(HAVE_ED448_VERIFY) + WOLFSSL_MSG("No ED448 verify built in"); +#elif !defined(WOLFSSL_KEY_GEN) + WOLFSSL_MSG("No Key Gen built in"); +#elif !defined(HAVE_ED448_KEY_IMPORT) + WOLFSSL_MSG("No ED448 Key import built in"); +#endif + + (void)msg; + (void)msgSz; + (void)pub; + (void)pubSz; + (void)sig; + (void)sigSz; + + return 0; +#endif /* HAVE_ED448_VERIFY && WOLFSSL_KEY_GEN && HAVE_ED448_KEY_IMPORT */ +} +#endif /* OPENSSL_EXTRA && HAVE_ED448 */ + +/******************************************************************************* + * END OF ED448 API + ******************************************************************************/ + +/******************************************************************************* + * START OF GENERIC PUBLIC KEY PEM APIs + ******************************************************************************/ + +#ifdef OPENSSL_EXTRA +/* Sets default callback password for PEM. + * + * @param [out] buf Buffer to hold password. + * @param [in] num Number of characters in buffer. + * @param [in] rwFlag Read/write flag. Ignored. + * @param [in] userData User data - assumed to be default password. + * @return Password size on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_def_callback(char* buf, int num, int rwFlag, void* userData) +{ + int sz = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_def_callback"); + + (void)rwFlag; + + /* We assume that the user passes a default password as userdata */ + if ((buf != NULL) && (userData != NULL)) { + sz = (int)XSTRLEN((const char*)userData); + sz = min(sz, num); + XMEMCPY(buf, userData, sz); + } + else { + WOLFSSL_MSG("Error, default password cannot be created."); + } + + return sz; +} + +#ifndef NO_BIO +/* Writes a public key to a WOLFSSL_BIO encoded in PEM format. + * + * @param [in] bio BIO to write to. + * @param [in] key Public key to write in PEM format. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_bio_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PUBKEY"); + + if ((bio != NULL) && (key != NULL)) { + switch (key->type) { +#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) + case EVP_PKEY_RSA: + ret = wolfSSL_PEM_write_bio_RSA_PUBKEY(bio, key->rsa); + break; +#endif /* WOLFSSL_KEY_GEN && !NO_RSA */ +#if !defined(NO_DSA) && !defined(HAVE_SELFTEST) && \ + (defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN)) + case EVP_PKEY_DSA: + ret = wolfSSL_PEM_write_bio_DSA_PUBKEY(bio, key->dsa); + break; +#endif /* !NO_DSA && !HAVE_SELFTEST && (WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN) */ +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && \ + defined(WOLFSSL_KEY_GEN) + case EVP_PKEY_EC: + ret = wolfSSL_PEM_write_bio_EC_PUBKEY(bio, key->ecc); + break; +#endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT */ +#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) + case EVP_PKEY_DH: + /* DH public key not supported. */ + WOLFSSL_MSG("Writing DH PUBKEY not supported!"); + break; +#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ + default: + /* Key type not supported. */ + WOLFSSL_MSG("Unknown Key type!"); + break; + } + } + + return ret; +} + +/* Writes a private key to a WOLFSSL_BIO encoded in PEM format. + * + * @param [in] bio BIO to write to. + * @param [in] key Public key to write in PEM format. + * @param [in] cipher Encryption cipher to use. + * @param [in] passwd Password to use when encrypting. + * @param [in] len Length of password. + * @param [in] cb Password callback. + * @param [in] arg Password callback arguement. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int len, + wc_pem_password_cb* cb, void* arg) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PrivateKey"); + + (void)cipher; + (void)passwd; + (void)len; + (void)cb; + (void)arg; + + /* Validate parameters. */ + if ((bio == NULL) || (key == NULL)) { + WOLFSSL_MSG("Bad Function Arguments"); + ret = 0; + } + + if (ret == 1) { + #ifdef WOLFSSL_KEY_GEN + switch (key->type) { + #ifndef NO_RSA + case EVP_PKEY_RSA: + /* Write using RSA specific API. */ + ret = wolfSSL_PEM_write_bio_RSAPrivateKey(bio, key->rsa, + cipher, passwd, len, cb, arg); + break; + #endif + #ifndef NO_DSA + case EVP_PKEY_DSA: + /* Write using DSA specific API. */ + ret = wolfSSL_PEM_write_bio_DSAPrivateKey(bio, key->dsa, + cipher, passwd, len, cb, arg); + break; + #endif + #ifdef HAVE_ECC + case EVP_PKEY_EC: + #if defined(HAVE_ECC_KEY_EXPORT) + /* Write using EC specific API. */ + ret = wolfSSL_PEM_write_bio_ECPrivateKey(bio, key->ecc, + cipher, passwd, len, cb, arg); + #else + ret = der_write_to_bio_as_pem((byte*)key->pkey.ptr, + key->pkey_sz, bio, EC_PRIVATEKEY_TYPE); + #endif + break; + #endif + #ifndef NO_DH + case EVP_PKEY_DH: + /* Write using generic API with DH type. */ + ret = der_write_to_bio_as_pem((byte*)key->pkey.ptr, + key->pkey_sz, bio, DH_PRIVATEKEY_TYPE); + break; + #endif + default: + WOLFSSL_MSG("Unknown Key type!"); + ret = 0; + break; + } + #else + int type = 0; + + switch (key->type) { + #ifndef NO_DSA + case EVP_PKEY_DSA: + type = DSA_PRIVATEKEY_TYPE; + break; + #endif + #ifdef HAVE_ECC + case EVP_PKEY_EC: + type = ECC_PRIVATEKEY_TYPE; + break; + #endif + #ifndef NO_DH + case EVP_PKEY_DH: + type = DH_PRIVATEKEY_TYPE; + break; + #endif + #ifndef NO_RSA + case EVP_PKEY_RSA: + type = PRIVATEKEY_TYPE; + break; + #endif + default: + ret = 0; + break; + } + if (ret == 1) { + /* Write using generic API with generic type. */ + ret = der_write_to_bio_as_pem((byte*)key->pkey.ptr, key->pkey_sz, + bio, type); + } + #endif + } + + return ret; +} +#endif /* !NO_BIO */ + +#ifndef NO_BIO +/* Create a private key object from the data in the BIO. + * + * @param [in] bio BIO to read from. + * @param [in, out] key Public key object. Object used if passed in. + * @param [in] cb Password callback. + * @param [in] arg Password callback arguement. + * @return A WOLFSSL_EVP_PKEY object on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_bio_PUBKEY(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY **key, wc_pem_password_cb *cb, void *arg) +{ + int err = 0; + WOLFSSL_EVP_PKEY* pkey = NULL; + DerBuffer* der = NULL; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PUBKEY"); + + if (bio == NULL) { + err = 1; + } + + /* Read the PEM public key from the BIO and convert to DER. */ + if ((!err) && (pem_read_bio_key(bio, cb, arg, PUBLICKEY_TYPE, NULL, + &der) < 0)) { + err = 1; + } + + if (!err) { + const unsigned char* ptr = der->buffer; + + /* Use key passed in if set. */ + if ((key != NULL) && (*key != NULL)) { + pkey = *key; + } + + /* Convert DER data to a public key object. */ + if (wolfSSL_d2i_PUBKEY(&pkey, &ptr, der->length) == NULL) { + WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); + pkey = NULL; + err = 1; + } + } + + /* Return the key if possible. */ + if ((!err) && (key != NULL) && (pkey != NULL)) { + *key = pkey; + } + /* Dispose of the DER encoding. */ + FreeDer(&der); + + WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PUBKEY", 0); + + return pkey; +} + +/* Create a private key object from the data in the BIO. + * + * @param [in] bio BIO to read from. + * @param [in, out] key Private key object. Object used if passed in. + * @param [in] cb Password callback. + * @param [in] arg Password callback arguement. + * @return A WOLFSSL_EVP_PKEY object on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_bio_PrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** key, wc_pem_password_cb* cb, void* arg) +{ + int err = 0; + WOLFSSL_EVP_PKEY* pkey = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PrivateKey"); + + /* Validate parameters. */ + if (bio == NULL) { + err = 1; + } + + /* Read the PEM private key from the BIO and convert to DER. */ + if ((!err) && (pem_read_bio_key(bio, cb, arg, PRIVATEKEY_TYPE, &keyFormat, + &der) < 0)) { + err = 1; + } + + if (!err) { + const unsigned char* ptr = der->buffer; + int type = -1; + + /* Set key type based on format returned. */ + switch (keyFormat) { + /* No key format set - default to RSA. */ + case 0: + case RSAk: + type = EVP_PKEY_RSA; + break; + case DSAk: + type = EVP_PKEY_DSA; + break; + case ECDSAk: + type = EVP_PKEY_EC; + break; + case DHk: + type = EVP_PKEY_DH; + break; + default: + break; + } + + /* Use key passed in if set. */ + if ((key != NULL) && (*key != NULL)) { + pkey = *key; + } + + /* Convert DER data to a private key object. */ + if (wolfSSL_d2i_PrivateKey(type, &pkey, &ptr, der->length) == NULL) { + WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); + pkey = NULL; + err = 1; + } + } + + /* Return the key if possible. */ + if ((!err) && (key != NULL) && (pkey != NULL)) { + *key = pkey; + } + /* Dispose of the DER encoding. */ + FreeDer(&der); + + WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PrivateKey", err); + + return pkey; +} +#endif /* !NO_BIO */ + +#if !defined(NO_FILESYSTEM) +/* Create a private key object from the data in a file. + * + * @param [in] fp File pointer. + * @param [in, out] key Public key object. Object used if passed in. + * @param [in] cb Password callback. + * @param [in] arg Password callback arguement. + * @return A WOLFSSL_EVP_PKEY object on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PUBKEY(XFILE fp, WOLFSSL_EVP_PKEY **key, + wc_pem_password_cb *cb, void *arg) +{ + int err = 0; + WOLFSSL_EVP_PKEY* pkey = NULL; + DerBuffer* der = NULL; + + WOLFSSL_ENTER("wolfSSL_PEM_read_PUBKEY"); + + /* Validate parameters. */ + if (fp == XBADFILE) { + err = 1; + } + + /* Read the PEM public key from the file and convert to DER. */ + if ((!err) && ((pem_read_file_key(fp, cb, arg, PUBLICKEY_TYPE, NULL, + &der) < 0) || (der == NULL))) { + err = 1; + } + if (!err) { + const unsigned char* ptr = der->buffer; + + /* Use key passed in if set. */ + if ((key != NULL) && (*key != NULL)) { + pkey = *key; + } + + /* Convert DER data to a public key object. */ + if (wolfSSL_d2i_PUBKEY(&pkey, &ptr, der->length) == NULL) { + WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); + pkey = NULL; + err = 1; + } + } + + /* Return the key if possible. */ + if ((!err) && (key != NULL) && (pkey != NULL)) { + *key = pkey; + } + /* Dispose of the DER encoding. */ + FreeDer(&der); + + WOLFSSL_LEAVE("wolfSSL_PEM_read_PUBKEY", 0); + + return pkey; +} + +#ifndef NO_CERTS +/* Create a private key object from the data in a file. + * + * @param [in] fp File pointer. + * @param [in, out] key Private key object. Object used if passed in. + * @param [in] cb Password callback. + * @param [in] arg Password callback arguement. + * @return A WOLFSSL_EVP_PKEY object on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY **key, + wc_pem_password_cb *cb, void *arg) +{ + int err = 0; + WOLFSSL_EVP_PKEY* pkey = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_PrivateKey"); + + /* Validate parameters. */ + if (fp == XBADFILE) { + err = 1; + } + + /* Read the PEM private key from the file and convert to DER. */ + if ((!err) && (pem_read_file_key(fp, cb, arg, PRIVATEKEY_TYPE, &keyFormat, + &der)) < 0) { + err = 1; + } + + if (!err) { + const unsigned char* ptr = der->buffer; + int type = -1; + + /* Set key type based on format returned. */ + switch (keyFormat) { + /* No key format set - default to RSA. */ + case 0: + case RSAk: + type = EVP_PKEY_RSA; + break; + case DSAk: + type = EVP_PKEY_DSA; + break; + case ECDSAk: + type = EVP_PKEY_EC; + break; + case DHk: + type = EVP_PKEY_DH; + break; + default: + break; + } + + /* Use key passed in if set. */ + if ((key != NULL) && (*key != NULL)) { + pkey = *key; + } + + /* Convert DER data to a private key object. */ + if (wolfSSL_d2i_PrivateKey(type, &pkey, &ptr, der->length) == NULL) { + WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); + pkey = NULL; + err = 1; + } + } + + /* Return the key if possible. */ + if ((!err) && (key != NULL) && (pkey != NULL)) { + *key = pkey; + } + /* Dispose of the DER encoding. */ + FreeDer(&der); + + WOLFSSL_LEAVE("wolfSSL_PEM_read_PrivateKey", 0); + + return pkey; +} +#endif /* !NO_CERTS */ +#endif /* !NO_FILESYSTEM */ + +#ifndef NO_CERTS + +#if !defined(NO_BIO) || !defined(NO_FILESYSTEM) +#define PEM_BEGIN "-----BEGIN " +#define PEM_BEGIN_SZ 11 +#define PEM_END "-----END " +#define PEM_END_SZ 9 +#define PEM_HDR_FIN "-----" +#define PEM_HDR_FIN_SZ 5 +#define PEM_HDR_FIN_EOL_NEWLINE "-----\n" +#define PEM_HDR_FIN_EOL_NULL_TERM "-----\0" +#define PEM_HDR_FIN_EOL_SZ 6 + +/* Find strings and return middle offsets. + * + * Find first string in pem as a prefix and then locate second string as a + * postfix. + * len returning with 0 indicates not found. + * + * @param [in] pem PEM data. + * @param [in] pemLen Length of PEM data. + * @param [in] idx Current index. + * @param [in] prefix First string to find. + * @param [in] postfix Second string to find after first. + * @param [out] start Start index of data between strings. + * @param [out] len Length of data between strings. + */ +static void pem_find_pattern(char* pem, int pemLen, int idx, const char* prefix, + const char* postfix, int* start, int* len) +{ + int prefixLen = (int)XSTRLEN(prefix); + int postfixLen = (int)XSTRLEN(postfix); + + *start = *len = 0; + /* Find prefix part. */ + for (; idx < pemLen - prefixLen; idx++) { + if ((pem[idx] == prefix[0]) && + (XMEMCMP(pem + idx, prefix, prefixLen) == 0)) { + idx += prefixLen; + *start = idx; + break; + } + } + /* Find postfix part. */ + for (; idx < pemLen - postfixLen; idx++) { + if ((pem[idx] == postfix[0]) && + (XMEMCMP(pem + idx, postfix, postfixLen) == 0)) { + *len = idx - *start; + break; + } + } +} + +/* Parse out content type name, any encryption headers and DER encoding. + * + * @param [in] pem PEM data. + * @param [in] pemLen Length of PEM data. + * @param [out] name Name of content type. + * @param [out] header Encryption headers. + * @param [out] data DER encoding from PEM. + * @param [out] len Length of DER data. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + * @return ASN_NO_PEM_HEADER when no header found or different names found. + */ +static int pem_read_data(char* pem, int pemLen, char **name, char **header, + unsigned char **data, long *len) +{ + int ret = 0; + int start; + int nameLen; + int startHdr = 0; + int hdrLen = 0; + int startEnd = 0; + int endLen; + + *name = NULL; + *header = NULL; + + /* Find header. */ + pem_find_pattern(pem, pemLen, 0, PEM_BEGIN, PEM_HDR_FIN, &start, &nameLen); + /* Allocate memory for header name. */ + *name = (char*)XMALLOC(nameLen + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (*name == NULL) { + ret = MEMORY_E; + } + if (ret == 0) { + /* Put in header name. */ + (*name)[nameLen] = '\0'; + if (nameLen == 0) { + ret = ASN_NO_PEM_HEADER; + } + else { + XMEMCPY(*name, pem + start, nameLen); + } + } + if (ret == 0) { + /* Find encryption headers after header. */ + start += nameLen + PEM_HDR_FIN_SZ; + pem_find_pattern(pem, pemLen, start, "\n", "\n\n", &startHdr, &hdrLen); + if (hdrLen > 0) { + /* Include first of two '\n' characters. */ + hdrLen++; + } + /* Allocate memory for encryption header string. */ + *header = (char*)XMALLOC(hdrLen + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (*header == NULL) { + ret = MEMORY_E; + } + } + if (ret == 0) { + /* Put in encryption header string. */ + (*header)[hdrLen] = '\0'; + if (hdrLen > 0) { + XMEMCPY(*header, pem + startHdr, hdrLen); + start = startHdr + hdrLen + 1; + } + + /* Find footer. */ + pem_find_pattern(pem, pemLen, start, PEM_END, PEM_HDR_FIN, &startEnd, + &endLen); + /* Validate header name and footer name are the same. */ + if ((endLen != nameLen) || + (XMEMCMP(*name, pem + startEnd, nameLen) != 0)) { + ret = ASN_NO_PEM_HEADER; + } + } + if (ret == 0) { + unsigned char* der = (unsigned char*)pem; + word32 derLen; + + /* Convert PEM body to DER. */ + derLen = startEnd - PEM_END_SZ - start; + ret = Base64_Decode(der + start, derLen, der, &derLen); + if (ret == 0) { + /* Return the DER data. */ + *data = der; + *len = derLen; + } + } + + return ret; +} + +/* Encode the DER data in PEM foramt into a newly allocated buffer. + * + * @param [in] name Header/footer name. + * @param [in] header Encryption header. + * @param [in] data DER data. + * @param [in] len Length of DER data. + * @param [out] pemOut PEM encoded data. + * @param [out] pemOutLen Length of PEM encoded data. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int pem_write_data(const char *name, const char *header, + const unsigned char *data, long len, char** pemOut, word32* pemOutLen) +{ + int ret = 0; + int nameLen; + int headerLen; + char* pem = NULL; + word32 pemLen; + word32 derLen = (word32)len; + byte* p; + + nameLen = (int)XSTRLEN(name); + headerLen = (int)XSTRLEN(header); + + /* DER encode for PEM. */ + pemLen = (derLen + 2) / 3 * 4; + pemLen += (pemLen + 63) / 64; + /* Header */ + pemLen += PEM_BEGIN_SZ + nameLen + PEM_HDR_FIN_EOL_SZ; + if (headerLen > 0) { + /* Encryption lines plus extra carriage return. */ + pemLen += headerLen + 1; + } + /* Trailer */ + pemLen += PEM_END_SZ + nameLen + PEM_HDR_FIN_EOL_SZ; + + pem = (char*)XMALLOC(pemLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (pem == NULL) { + ret = MEMORY_E; + } + p = (byte*)pem; + + if (ret == 0) { + /* Add header. */ + XMEMCPY(p, PEM_BEGIN, PEM_BEGIN_SZ); + p += PEM_BEGIN_SZ; + XMEMCPY(p, name, nameLen); + p += nameLen; + XMEMCPY(p, PEM_HDR_FIN_EOL_NEWLINE, PEM_HDR_FIN_EOL_SZ); + p += PEM_HDR_FIN_EOL_SZ; + + if (headerLen > 0) { + /* Add encryption header. */ + XMEMCPY(p, header, headerLen); + p += headerLen; + /* Blank line after a header and before body. */ + *(p++) = '\n'; + } + + /* Add DER data as PEM. */ + pemLen -= (word32)((size_t)p - (size_t)pem); + ret = Base64_Encode(data, derLen, p, &pemLen); + } + if (ret == 0) { + p += pemLen; + + /* Add trailer. */ + XMEMCPY(p, PEM_END, PEM_END_SZ); + p += PEM_END_SZ; + XMEMCPY(p, name, nameLen); + p += nameLen; + XMEMCPY(p, PEM_HDR_FIN_EOL_NEWLINE, PEM_HDR_FIN_EOL_SZ); + p += PEM_HDR_FIN_EOL_SZ; + + /* Return buffer and length of data. */ + *pemOut = pem; + *pemOutLen = (word32)((size_t)p - (size_t)pem); + } + + return ret; +} +#endif /* !NO_BIO || !NO_FILESYSTEM */ + +#ifndef NO_BIO +/* Read PEM encoded data from a BIO. + * + * Reads the entire contents in. + * + * @param [in] bio BIO to read from. + * @param [out] name Name of content type. + * @param [out] header Encryption headers. + * @param [out] data DER encoding from PEM. + * @param [out] len Length of DER data. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_read_bio(WOLFSSL_BIO* bio, char **name, char **header, + unsigned char **data, long *len) +{ + int res = 1; + char* pem = NULL; + int pemLen = 0; + int memAlloced = 1; + + /* Validate parameters. */ + if ((bio == NULL) || (name == NULL) || (header == NULL) || (data == NULL) || + (len == NULL)) { + res = 0; + } + + /* Load all the data from the BIO. */ + if ((res == 1) && (wolfssl_read_bio(bio, &pem, &pemLen, &memAlloced) != + 0)) { + res = 0; + } + if ((res == 1) && (!memAlloced)) { + /* Need to return allocated memory - make sure it is allocated. */ + char* p = (char*)XMALLOC(pemLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (p == NULL) { + res = 0; + } + else { + /* Copy the data into new buffer. */ + XMEMCPY(p, pem, pemLen); + pem = p; + } + } + + /* Read the PEM data. */ + if ((res == 1) && (pem_read_data(pem, pemLen, name, header, data, len) != + 0)) { + /* Dispose of any allocated memory. */ + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(*name, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(*header, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *name = NULL; + *header = NULL; + res = 0; + } + + return res; +} + +/* Encode the DER data in PEM foramt into a BIO. + * + * @param [in] bio BIO to write to. + * @param [in] name Header/footer name. + * @param [in] header Encryption header. + * @param [in] data DER data. + * @param [in] len Length of DER data. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + */ +int wolfSSL_PEM_write_bio(WOLFSSL_BIO* bio, const char *name, + const char *header, const unsigned char *data, long len) +{ + int err = 0; + char* pem = NULL; + word32 pemLen = 0; + + /* Validate parameters. */ + if ((bio == NULL) || (name == NULL) || (header == NULL) || (data == NULL)) { + err = 1; + } + + /* Encode into a buffer. */ + if ((!err) && (pem_write_data(name, header, data, len, &pem, &pemLen) != + 0)) { + pemLen = 0; + err = 1; + } + + /* Write PEM into BIO. */ + if ((!err) && (wolfSSL_BIO_write(bio, pem, pemLen) != (int)pemLen)) { + pemLen = 0; + } + + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return pemLen; +} +#endif /* !NO_BIO */ + +#if !defined(NO_FILESYSTEM) +/* Read PEM encoded data from a file. + * + * Reads the entire contents in. + * + * @param [in] bio BIO to read from. + * @param [out] name Name of content type. + * @param [out] header Encryption headers. + * @param [out] data DER encoding from PEM. + * @param [out] len Length of DER data. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_read(XFILE fp, char **name, char **header, unsigned char **data, + long *len) +{ + int res = 1; + char* pem = NULL; + int pemLen = 0; + + /* Validate parameters. */ + if ((fp == XBADFILE) || (name == NULL) || (header == NULL) || + (data == NULL) || (len == NULL)) { + res = 0; + } + + /* Load all the data from the file. */ + if ((res == 1) && (wolfssl_read_file(fp, &pem, &pemLen) != 0)) { + res = 0; + } + + /* Read the PEM data. */ + if ((res == 1) && (pem_read_data(pem, pemLen, name, header, data, len) != + 0)) { + /* Dispose of any allocated memory. */ + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(*name, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(*header, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *name = NULL; + *header = NULL; + res = 0; + } + + return res; +} + +/* Encode the DER data in PEM foramt into a file. + * + * @param [in] fp File pointer to write to. + * @param [in] name Header/footer name. + * @param [in] header Encryption header. + * @param [in] data DER data. + * @param [in] len Length of DER data. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + */ +int wolfSSL_PEM_write(XFILE fp, const char *name, const char *header, + const unsigned char *data, long len) +{ + int err = 0; + char* pem = NULL; + word32 pemLen = 0; + + /* Validate parameters. */ + if ((fp == XBADFILE) || (name == NULL) || (header == NULL) || + (data == NULL)) { + err = 1; + } + + /* Encode into a buffer. */ + if ((!err) && (pem_write_data(name, header, data, len, &pem, &pemLen) != + 0)) { + pemLen = 0; + err = 1; + } + + /* Write PEM to a file. */ + if ((!err) && (XFWRITE(pem, 1, pemLen, fp) != pemLen)) { + pemLen = 0; + } + + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return pemLen; +} +#endif + +/* Get EVP cipher info from encryption header string. + * + * @param [in] header Encryption header. + * @param [out] cipher EVP Cipher info. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_get_EVP_CIPHER_INFO(const char* header, EncryptedInfo* cipher) +{ + int res = 1; + + /* Validate parameters. */ + if ((header == NULL) || (cipher == NULL)) { + res = 0; + } + + if (res == 1) { + XMEMSET(cipher, 0, sizeof(*cipher)); + + if (wc_EncryptedInfoParse(cipher, &header, XSTRLEN(header)) != 0) { + res = 0; + } + } + + return res; +} + +/* Apply cipher to DER data. + * + * @param [in] cipher EVP cipher info. + * @param [in, out] data On in, encrypted DER data. + * On out, unencrypted DER data. + * @param [in, out] len On in, length of encrypted DER data. + * On out, length of unencrypted DER data. + * @param [in] cb Password callback. + * @param [in] ctx Context for password callback. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_do_header(EncryptedInfo* cipher, unsigned char* data, long* len, + wc_pem_password_cb* cb, void* ctx) +{ + int ret = 1; + char password[NAME_SZ]; + int passwordSz = 0; + + /* Validate parameters. */ + if ((cipher == NULL) || (data == NULL) || (len == NULL) || (cb == NULL)) { + ret = 0; + } + + if (ret == 1) { + /* Get password and length. */ + passwordSz = cb(password, sizeof(password), PEM_PASS_READ, ctx); + if (passwordSz < 0) { + ret = 0; + } + } + + if (ret == 1) { + /* Decrypt the data using password and MD5. */ + if (wc_BufferKeyDecrypt(cipher, data, (word32)*len, (byte*)password, + passwordSz, WC_MD5) != 0) { + ret = WOLFSSL_FAILURE; + } + } + + if (passwordSz > 0) { + /* Ensure password is erased from memory. */ + ForceZero(password, passwordSz); + } + + return ret; +} + +#endif /* !NO_CERTS */ +#endif /* OPENSSL_EXTRA */ + +#ifdef OPENSSL_ALL +#if !defined(NO_PWDBASED) && defined(HAVE_PKCS8) + +#if !defined(NO_BIO) || (!defined(NO_FILESYSTEM) && \ + !defined(NO_STDIO_FILESYSTEM)) +/* Encrypt the key into a buffer using PKCS$8 and a password. + * + * @param [in] pkey Private key to encrypt. + * @param [in] enc EVP cipher. + * @param [in] passwd Password to encrypt with. + * @param [in] passwdSz Number of bytes in password. + * @param [in] key Buffer to hold encrypted key. + * @param [in, out] keySz On in, size of buffer in bytes. + * On out, size of encrypted key in bytes. + * @return 0 on success. + * @return BAD_FUNC_ARG when EVP cipher not supported. + */ +static int pem_pkcs8_encrypt(WOLFSSL_EVP_PKEY* pkey, + const WOLFSSL_EVP_CIPHER* enc, char* passwd, int passwdSz, byte* key, + word32* keySz) +{ + int ret; + WC_RNG rng; + + /* Initialize a new random number generator. */ + ret = wc_InitRng(&rng); + if (ret == 0) { + int encAlgId = 0; + + /* Convert EVP cipher to a support encryption id. */ + #ifndef NO_DES3 + if (enc == EVP_DES_CBC) { + encAlgId = DESb; + } + else if (enc == EVP_DES_EDE3_CBC) { + encAlgId = DES3b; + } + else + #endif +#if !defined(NO_AES) && defined(HAVE_AES_CBC) + #ifdef WOLFSSL_AES_128 + if (enc == EVP_AES_128_CBC) { + encAlgId = AES128CBCb; + } + else + #endif + #ifdef WOLFSSL_AES_256 + if (enc == EVP_AES_256_CBC) { + encAlgId = AES256CBCb; + } + else + #endif +#endif + { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + /* Encrypt private into buffer. */ + ret = TraditionalEnc((byte*)pkey->pkey.ptr, pkey->pkey_sz, + key, keySz, passwd, passwdSz, PKCS5, PBES2, encAlgId, + NULL, 0, WC_PKCS12_ITT_DEFAULT, &rng, NULL); + if (ret > 0) { + *keySz = ret; + } + } + /* Dispose of random number generator. */ + wc_FreeRng(&rng); + } + + return ret; +} + +/* Encode private key in PKCS#8 format. + * + * @param [in] pkey Private key. + * @param [out] key Buffer to hold encoding. + * @param [in, out] keySz On in, size of buffer in bytes. + * @param On out, size of encoded key in bytes. + * @return 0 on success. + */ +static int pem_pkcs8_encode(WOLFSSL_EVP_PKEY* pkey, byte* key, word32* keySz) +{ + int ret = 0; + int algId; + const byte* curveOid; + word32 oidSz; + + /* Get the details of the private key. */ +#ifdef HAVE_ECC + if (pkey->type == EVP_PKEY_EC) { + /* ECC private and get curve OID information. */ + algId = ECDSAk; + ret = wc_ecc_get_oid(pkey->ecc->group->curve_oid, &curveOid, + &oidSz); + } + else +#endif + if (pkey->type == EVP_PKEY_RSA) { + /* RSA private has no curve information. */ + algId = RSAk; + curveOid = NULL; + oidSz = 0; + } + else { + ret = NOT_COMPILED_IN; + } + + if (ret >= 0) { + /* Encode private key in PKCS#8 format. */ + ret = wc_CreatePKCS8Key(key, keySz, (byte*)pkey->pkey.ptr, + pkey->pkey_sz, algId, curveOid, oidSz); + } + + return ret; +} + +/* Write PEM encoded, PKCS#8 formatted private key to BIO. + * + * @param [out] pem Buffer holding PEM encoding. + * @param [out] pemSz Size of data in buffer in bytes. + * @param [in] pkey Private key to write. + * @param [in] enc Encryption information to use. May be NULL. + * @param [in] passwd Pasword to use when encrypting. May be NULL. + * @param [in] passwdSz Size of password in bytes. + * @param [in] cb Password callback. Used when passwd is NULL. May be + * NULL. + * @param [in] ctx Context for password callback. + * @return Length of PEM encoding on success. + * @return 0 on failure. + */ +static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, + WOLFSSL_EVP_PKEY* pkey, const WOLFSSL_EVP_CIPHER* enc, char* passwd, + int passwdSz, wc_pem_password_cb* cb, void* ctx) +{ + int res = 1; + int ret = 0; + char password[NAME_SZ]; + byte* key = NULL; + word32 keySz; + int type = PKCS8_PRIVATEKEY_TYPE; + + /* Validate parameters. */ + if (pkey == NULL) { + res = 0; + } + + if (res == 1) { + /* Guestimate key size and PEM size. */ + if (pem_pkcs8_encode(pkey, NULL, &keySz) != LENGTH_ONLY_E) { + res = 0; + } + } + if (res == 1) { + if (enc != NULL) { + /* Add on enough for extra DER data when encrypting. */ + keySz += 128; + } + /* PEM encoding size from DER size. */ + *pemSz = (keySz + 2) / 3 * 4; + *pemSz += (*pemSz + 63) / 64; + /* Header and footer. */ + if (enc != NULL) { + /* Name is: 'ENCRYPTED PRIVATE KEY'. */ + *pemSz += 74; + } + else { + /* Name is: 'PRIVATE KEY'. */ + *pemSz += 54; + } + + /* Allocate enough memory to hold PEM encoded encrypted key. */ + *pem = (byte*)XMALLOC(*pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (*pem == NULL) { + res = 0; + } + else { + /* Use end of PEM buffer for key data. */ + key = *pem + *pemSz - keySz; + } + } + + if ((res == 1) && (enc != NULL)) { + /* Set type for PEM. */ + type = PKCS8_ENC_PRIVATEKEY_TYPE; + + if (passwd == NULL) { + /* Get the password by using callback. */ + passwdSz = cb(password, sizeof(password), 1, ctx); + if (passwdSz < 0) { + res = 0; + } + passwd = password; + } + + if (res == 1) { + /* Encrypt the private key. */ + ret = pem_pkcs8_encrypt(pkey, enc, passwd, passwdSz, key, &keySz); + if (ret <= 0) { + res = 0; + } + } + + /* Zeroize the password from memory. */ + if ((password == passwd) && (passwdSz > 0)) { + ForceZero(password, passwdSz); + } + } + else if ((res == 1) && (enc == NULL)) { + /* Set type for PEM. */ + type = PKCS8_PRIVATEKEY_TYPE; + + /* Encode private key in PKCS#8 format. */ + ret = pem_pkcs8_encode(pkey, key, &keySz); + if (ret < 0) { + res = 0; + } + } + + if (res == 1) { + /* Encode PKCS#8 formatted key to PEM. */ + ret = wc_DerToPemEx(key, keySz, *pem, *pemSz, NULL, type); + if (ret < 0) { + res = 0; + } + else { + *pemSz = ret; + } + } + + /* Return appropriate return code. */ + return (res == 0) ? 0 : ret; + +} +#endif /* !NO_BIO || (!NO_FILESYSTEM && !NO_STDIO_FILESYSTEM) */ + +#ifndef NO_BIO +/* Write PEM encoded, PKCS#8 formatted private key to BIO. + * + * TODO: OpenSSL returns 1 and 0 only. + * + * @param [in] bio BIO to write to. + * @param [in] pkey Private key to write. + * @param [in] enc Encryption information to use. May be NULL. + * @param [in] passwd Pasword to use when encrypting. May be NULL. + * @param [in] passwdSz Size of password in bytes. + * @param [in] cb Password callback. Used when passwd is NULL. May be + * NULL. + * @param [in] ctx Context for password callback. + * @return Length of PEM encoding on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_bio_PKCS8PrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY* pkey, const WOLFSSL_EVP_CIPHER* enc, char* passwd, + int passwdSz, wc_pem_password_cb* cb, void* ctx) +{ + byte* pem = NULL; + int pemSz; + int res = 1; + + /* Validate parameters. */ + if (bio == NULL) { + res = 0; + } + if (res == 1) { + /* Write private key to memory. */ + res = pem_write_mem_pkcs8privatekey(&pem, &pemSz, pkey, enc, passwd, + passwdSz, cb, ctx); + } + + /* Write encoded key to BIO. */ + if ((res >= 1) && (wolfSSL_BIO_write(bio, pem, pemSz) != pemSz)) { + res = 0; + } + + /* Dispose of dynamically allocated memory (pem and key). */ + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return res; +} +#endif /* !NO_BIO */ + +#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) +/* Write PEM encoded, PKCS#8 formatted private key to BIO. + * + * TODO: OpenSSL returns 1 and 0 only. + * + * @param [in] f File pointer. + * @param [in] pkey Private key to write. + * @param [in] enc Encryption information to use. May be NULL. + * @param [in] passwd Pasword to use when encrypting. May be NULL. + * @param [in] passwdSz Size of password in bytes. + * @param [in] cb Password callback. Used when passwd is NULL. May be + * NULL. + * @param [in] ctx Context for password callback. + * @return Length of PEM encoding on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_PKCS8PrivateKey(XFILE f, WOLFSSL_EVP_PKEY* pkey, + const WOLFSSL_EVP_CIPHER* enc, char* passwd, int passwdSz, + wc_pem_password_cb* cb, void* ctx) +{ + byte* pem = NULL; + int pemSz; + int res = 1; + + /* Validate parameters. */ + if (f == XBADFILE) { + res = 0; + } + if (res == 1) { + /* Write private key to memory. */ + res = pem_write_mem_pkcs8privatekey(&pem, &pemSz, pkey, enc, passwd, + passwdSz, cb, ctx); + } + + /* Write encoded key to file. */ + if ((res >= 1) && (XFWRITE(pem, 1, pemSz, f) != (size_t)pemSz)) { + res = 0; + } + + /* Dispose of dynamically allocated memory (pem and key). */ + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return res; +} +#endif /* !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ + +#endif /* !NO_PWDBASED && HAVE_PKCS8 */ +#endif /* OPENSSL_ALL */ + +/******************************************************************************* + * END OF GENERIC PUBLIC KEY PEM APIs + ******************************************************************************/ + #endif /* !WOLFSSL_PK_INCLUDED */ diff --git a/src/ssl.c b/src/ssl.c index b19b2c7f2..119f31577 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -54,7 +54,8 @@ #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(WOLFSSL_STATIC_RSA) \ && !defined(WOLFSSL_STATIC_DH) && !defined(WOLFSSL_STATIC_PSK) \ && !defined(HAVE_CURVE25519) && !defined(HAVE_CURVE448) - #error "No cipher suites defined because DH disabled, ECC disabled, and no static suites defined. Please see top of README" + #error "No cipher suites defined because DH disabled, ECC disabled, " + "and no static suites defined. Please see top of README" #endif #ifdef WOLFSSL_CERT_GEN /* need access to Cert struct for creating certificate */ @@ -140,12 +141,6 @@ && !defined(WC_NO_RNG) #include #endif - #if defined(HAVE_FIPS) || defined(HAVE_SELFTEST) - #include - #endif - #if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) - #include - #endif /* OPENSSL_ALL && HAVE_PKCS7 */ #endif #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) @@ -163,25 +158,6 @@ #endif #endif /* !WOLFCRYPT_ONLY || OPENSSL_EXTRA */ -#ifdef WOLFSSL_SYS_CA_CERTS - -#ifdef _WIN32 - #include - #include - - /* mingw gcc does not support pragma comment, and the - * linking with crypt32 is handled in configure.ac */ - #if !defined(__MINGW32__) && !defined(__MINGW64__) - #pragma comment(lib, "crypt32") - #endif -#endif - -#if defined(__APPLE__) && defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) -#include -#endif - -#endif /* WOLFSSL_SYS_CA_CERTS */ - /* * OPENSSL_COMPATIBLE_DEFAULTS: * Enable default behaviour that is compatible with OpenSSL. For example @@ -218,6 +194,9 @@ #ifndef WOLFCRYPT_ONLY #define WOLFSSL_SSL_CERTMAN_INCLUDED #include "src/ssl_certman.c" + +#define WOLFSSL_SSL_SESS_INCLUDED +#include "src/ssl_sess.c" #endif #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ @@ -312,7 +291,8 @@ int wc_OBJ_sn2nid(const char *sn) static WC_RNG globalRNG; static int initGlobalRNG = 0; -static WC_MAYBE_UNUSED wolfSSL_Mutex globalRNGMutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(globalRNGMutex); +static WC_MAYBE_UNUSED wolfSSL_Mutex globalRNGMutex + WOLFSSL_MUTEX_INITIALIZER_CLAUSE(globalRNGMutex); #ifndef WOLFSSL_MUTEX_INITIALIZER static int globalRNGMutex_valid = 0; #endif @@ -411,7 +391,8 @@ WC_RNG* wolfssl_make_rng(WC_RNG* rng, int* local) * OPENSSL_EXTRA where RAND callbacks are not used */ #ifndef WOLFSSL_NO_OPENSSL_RAND_CB static const WOLFSSL_RAND_METHOD* gRandMethods = NULL; - static wolfSSL_Mutex gRandMethodMutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(gRandMethodMutex); + static wolfSSL_Mutex gRandMethodMutex + WOLFSSL_MUTEX_INITIALIZER_CLAUSE(gRandMethodMutex); #ifndef WOLFSSL_MUTEX_INITIALIZER static int gRandMethodsInit = 0; #endif @@ -460,9 +441,12 @@ const WOLF_EC_NIST_NAME kNistCurves[] = { {XSTR_SIZEOF("KYBER_LEVEL3"), "KYBER_LEVEL3", WOLFSSL_KYBER_LEVEL3}, {XSTR_SIZEOF("KYBER_LEVEL5"), "KYBER_LEVEL5", WOLFSSL_KYBER_LEVEL5}, #ifdef HAVE_LIBOQS - {XSTR_SIZEOF("P256_KYBER_LEVEL1"), "P256_KYBER_LEVEL1", WOLFSSL_P256_KYBER_LEVEL1}, - {XSTR_SIZEOF("P384_KYBER_LEVEL3"), "P384_KYBER_LEVEL3", WOLFSSL_P384_KYBER_LEVEL3}, - {XSTR_SIZEOF("P521_KYBER_LEVEL5"), "P521_KYBER_LEVEL5", WOLFSSL_P521_KYBER_LEVEL5}, + {XSTR_SIZEOF("P256_KYBER_LEVEL1"), "P256_KYBER_LEVEL1", + WOLFSSL_P256_KYBER_LEVEL1}, + {XSTR_SIZEOF("P384_KYBER_LEVEL3"), "P384_KYBER_LEVEL3", + WOLFSSL_P384_KYBER_LEVEL3}, + {XSTR_SIZEOF("P521_KYBER_LEVEL5"), "P521_KYBER_LEVEL5", + WOLFSSL_P521_KYBER_LEVEL5}, #endif #endif #ifdef WOLFSSL_SM2 @@ -1070,209 +1054,11 @@ int GetEchConfigsEx(WOLFSSL_EchConfig* configs, byte* output, word32* outputLen) #include #endif -#ifdef WOLFSSL_SESSION_EXPORT -/* Used to import a serialized TLS session. - * WARNING: buf contains sensitive information about the state and is best to be - * encrypted before storing if stored. - * - * @param ssl WOLFSSL structure to import the session into - * @param buf serialized session - * @param sz size of buffer 'buf' - * @return the number of bytes read from buffer 'buf' - */ -int wolfSSL_tls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz) -{ - if (ssl == NULL || buf == NULL) { - return BAD_FUNC_ARG; - } - return wolfSSL_session_import_internal(ssl, buf, sz, WOLFSSL_EXPORT_TLS); -} - - -/* Used to export a serialized TLS session. - * WARNING: buf contains sensitive information about the state and is best to be - * encrypted before storing if stored. - * - * @param ssl WOLFSSL structure to export the session from - * @param buf output of serialized session - * @param sz size in bytes set in 'buf' - * @return the number of bytes written into buffer 'buf' - */ -int wolfSSL_tls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) -{ - if (ssl == NULL || sz == NULL) { - return BAD_FUNC_ARG; - } - return wolfSSL_session_export_internal(ssl, buf, sz, WOLFSSL_EXPORT_TLS); -} - -#ifdef WOLFSSL_DTLS -int wolfSSL_dtls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz) -{ - WOLFSSL_ENTER("wolfSSL_session_import"); - - if (ssl == NULL || buf == NULL) { - return BAD_FUNC_ARG; - } - - /* sanity checks on buffer and protocol are done in internal function */ - return wolfSSL_session_import_internal(ssl, buf, sz, WOLFSSL_EXPORT_DTLS); -} - - -/* Sets the function to call for serializing the session. This function is - * called right after the handshake is completed. */ -int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, wc_dtls_export func) -{ - - WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_export"); - - /* purposefully allow func to be NULL */ - if (ctx == NULL) { - return BAD_FUNC_ARG; - } - - ctx->dtls_export = func; - - return WOLFSSL_SUCCESS; -} - - -/* Sets the function in WOLFSSL struct to call for serializing the session. This - * function is called right after the handshake is completed. */ -int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func) -{ - - WOLFSSL_ENTER("wolfSSL_dtls_set_export"); - - /* purposefully allow func to be NULL */ - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - ssl->dtls_export = func; - - return WOLFSSL_SUCCESS; -} - - -/* This function allows for directly serializing a session rather than using - * callbacks. It has less overhead by removing a temporary buffer and gives - * control over when the session gets serialized. When using callbacks the - * session is always serialized immediately after the handshake is finished. - * - * buf is the argument to contain the serialized session - * sz is the size of the buffer passed in - * ssl is the WOLFSSL struct to serialize - * returns the size of serialized session on success, 0 on no action, and - * negative value on error */ -int wolfSSL_dtls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) -{ - WOLFSSL_ENTER("wolfSSL_dtls_export"); - - if (ssl == NULL || sz == NULL) { - return BAD_FUNC_ARG; - } - - if (buf == NULL) { - *sz = MAX_EXPORT_BUFFER; - return 0; - } - - /* if not DTLS do nothing */ - if (!ssl->options.dtls) { - WOLFSSL_MSG("Currently only DTLS export is supported"); - return 0; - } - - /* copy over keys, options, and dtls state struct */ - return wolfSSL_session_export_internal(ssl, buf, sz, WOLFSSL_EXPORT_DTLS); -} - - -/* This function is similar to wolfSSL_dtls_export but only exports the portion - * of the WOLFSSL structure related to the state of the connection, i.e. peer - * sequence number, epoch, AEAD state etc. - * - * buf is the argument to contain the serialized state, if null then set "sz" to - * buffer size required - * sz is the size of the buffer passed in - * ssl is the WOLFSSL struct to serialize - * returns the size of serialized session on success, 0 on no action, and - * negative value on error */ -int wolfSSL_dtls_export_state_only(WOLFSSL* ssl, unsigned char* buf, - unsigned int* sz) -{ - WOLFSSL_ENTER("wolfSSL_dtls_export_state_only"); - - if (ssl == NULL || sz == NULL) { - return BAD_FUNC_ARG; - } - - if (buf == NULL) { - *sz = MAX_EXPORT_STATE_BUFFER; - return 0; - } - - /* if not DTLS do nothing */ - if (!ssl->options.dtls) { - WOLFSSL_MSG("Currently only DTLS export state is supported"); - return 0; - } - - /* copy over keys, options, and dtls state struct */ - return wolfSSL_dtls_export_state_internal(ssl, buf, *sz); -} - - -/* returns 0 on success */ -int wolfSSL_send_session(WOLFSSL* ssl) -{ - int ret; - byte* buf; - word32 bufSz = MAX_EXPORT_BUFFER; - - WOLFSSL_ENTER("wolfSSL_send_session"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - buf = (byte*)XMALLOC(bufSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - return MEMORY_E; - } - - /* if not DTLS do nothing */ - if (!ssl->options.dtls) { - XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - WOLFSSL_MSG("Currently only DTLS export is supported"); - return 0; - } - - /* copy over keys, options, and dtls state struct */ - ret = wolfSSL_session_export_internal(ssl, buf, &bufSz, WOLFSSL_EXPORT_DTLS); - if (ret < 0) { - XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - return ret; - } - - /* if no error ret has size of buffer */ - ret = ssl->dtls_export(ssl, buf, ret, NULL); - if (ret != WOLFSSL_SUCCESS) { - XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - return ret; - } - - XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - return 0; -} -#endif /* WOLFSSL_DTLS */ -#endif /* WOLFSSL_SESSION_EXPORT */ - /* prevent multiple mutex initializations */ static volatile WOLFSSL_GLOBAL int initRefCount = 0; -static WOLFSSL_GLOBAL wolfSSL_Mutex inits_count_mutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(inits_count_mutex); /* init ref count mutex */ +/* init ref count mutex */ +static WOLFSSL_GLOBAL wolfSSL_Mutex inits_count_mutex + WOLFSSL_MUTEX_INITIALIZER_CLAUSE(inits_count_mutex); #ifndef WOLFSSL_MUTEX_INITIALIZER static WOLFSSL_GLOBAL int inits_count_mutex_valid = 0; #endif @@ -1342,8 +1128,8 @@ WOLFSSL_CTX* wolfSSL_CTX_new_ex(WOLFSSL_METHOD* method, void* heap) wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); wolfSSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); if (wolfSSL_CTX_set_min_proto_version(ctx, - (method->version.major == DTLS_MAJOR) ? - DTLS1_VERSION : SSL3_VERSION) != WOLFSSL_SUCCESS || + (method->version.major == DTLS_MAJOR) ? + DTLS1_VERSION : SSL3_VERSION) != WOLFSSL_SUCCESS || #ifdef HAVE_ANON wolfSSL_CTX_allow_anon_cipher(ctx) != WOLFSSL_SUCCESS || #endif @@ -1613,8 +1399,8 @@ static int DupSSL(WOLFSSL* dup, WOLFSSL* ssl) #ifdef HAVE_ONE_TIME_AUTH #ifdef HAVE_POLY1305 if (ssl->auth.setup && ssl->auth.poly1305 != NULL) { - dup->auth.poly1305 = - (Poly1305*)XMALLOC(sizeof(Poly1305), dup->heap, DYNAMIC_TYPE_CIPHER); + dup->auth.poly1305 = (Poly1305*)XMALLOC(sizeof(Poly1305), dup->heap, + DYNAMIC_TYPE_CIPHER); if (dup->auth.poly1305 == NULL) return MEMORY_E; dup->auth.setup = 1; @@ -2221,10 +2007,12 @@ int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) static const WOLFSSL_SRTP_PROTECTION_PROFILE gSrtpProfiles[] = { /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 80-bits * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ - {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, (((128 + 112) * 2) / 8) }, + {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, + (((128 + 112) * 2) / 8) }, /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 32-bits * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ - {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, (((128 + 112) * 2) / 8) }, + {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, + (((128 + 112) * 2) / 8) }, /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 80-bits */ {"SRTP_NULL_SHA1_80", SRTP_NULL_SHA1_80, ((112 * 2) / 8)}, /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 32-bits */ @@ -2468,7 +2256,8 @@ int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, if (ret == 0) { XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); - XMEMSET(ssl->arrays->preMasterSecret + preMasterSz, 0, ENCRYPT_LEN - preMasterSz); + XMEMSET(ssl->arrays->preMasterSecret + preMasterSz, 0, + ENCRYPT_LEN - preMasterSz); ssl->arrays->preMasterSz = preMasterSz; XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); @@ -2719,7 +2508,8 @@ int wolfSSL_GetObjectSize(void) #ifdef WOLFSSL_SM4 printf("\tsizeof sm4 = %lu\n", (unsigned long)sizeof(Sm4)); #endif - printf("sizeof cipher specs = %lu\n", (unsigned long)sizeof(CipherSpecs)); + printf("sizeof cipher specs = %lu\n", (unsigned long) + sizeof(CipherSpecs)); printf("sizeof keys = %lu\n", (unsigned long)sizeof(Keys)); printf("sizeof Hashes(2) = %lu\n", (unsigned long)sizeof(Hashes)); #ifndef NO_MD5 @@ -2752,10 +2542,13 @@ int wolfSSL_GetObjectSize(void) #ifdef HAVE_ECC printf("sizeof ecc_key = %lu\n", (unsigned long)sizeof(ecc_key)); #endif - printf("sizeof WOLFSSL_CIPHER = %lu\n", (unsigned long)sizeof(WOLFSSL_CIPHER)); - printf("sizeof WOLFSSL_SESSION = %lu\n", (unsigned long)sizeof(WOLFSSL_SESSION)); + printf("sizeof WOLFSSL_CIPHER = %lu\n", (unsigned long) + sizeof(WOLFSSL_CIPHER)); + printf("sizeof WOLFSSL_SESSION = %lu\n", (unsigned long) + sizeof(WOLFSSL_SESSION)); printf("sizeof WOLFSSL = %lu\n", (unsigned long)sizeof(WOLFSSL)); - printf("sizeof WOLFSSL_CTX = %lu\n", (unsigned long)sizeof(WOLFSSL_CTX)); + printf("sizeof WOLFSSL_CTX = %lu\n", (unsigned long) + sizeof(WOLFSSL_CTX)); #endif return sizeof(WOLFSSL); @@ -2775,9 +2568,9 @@ int wolfSSL_METHOD_GetObjectSize(void) #ifdef WOLFSSL_STATIC_MEMORY -int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx, wolfSSL_method_func method, - unsigned char* buf, unsigned int sz, - int flag, int maxSz) +int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx, + wolfSSL_method_func method, unsigned char* buf, unsigned int sz, int flag, + int maxSz) { WOLFSSL_HEAP* heap; WOLFSSL_HEAP_HINT* hint; @@ -2925,7 +2718,8 @@ int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz) if (inSz > maxSize) return INPUT_SIZE_E; - return BuildMessage(ssl, NULL, 0, NULL, inSz, application_data, 0, 1, 0, CUR_ORDER); + return BuildMessage(ssl, NULL, 0, NULL, inSz, application_data, 0, 1, 0, + CUR_ORDER); } @@ -2986,138 +2780,6 @@ int wolfSSL_SetMinRsaKey_Sz(WOLFSSL* ssl, short keySz) #ifndef NO_DH -#ifdef OPENSSL_EXTRA -long wolfSSL_set_tmp_dh(WOLFSSL *ssl, WOLFSSL_DH *dh) -{ - int pSz, gSz; - byte *p, *g; - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_set_tmp_dh"); - - if (!ssl || !dh) - return BAD_FUNC_ARG; - - /* Get needed size for p and g */ - pSz = wolfSSL_BN_bn2bin(dh->p, NULL); - gSz = wolfSSL_BN_bn2bin(dh->g, NULL); - - if (pSz <= 0 || gSz <= 0) - return -1; - - p = (byte*)XMALLOC(pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - if (!p) - return MEMORY_E; - - g = (byte*)XMALLOC(gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - if (!g) { - XFREE(p, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - return MEMORY_E; - } - - pSz = wolfSSL_BN_bn2bin(dh->p, p); - gSz = wolfSSL_BN_bn2bin(dh->g, g); - - if (pSz >= 0 && gSz >= 0) /* Conversion successful */ - ret = wolfSSL_SetTmpDH(ssl, p, pSz, g, gSz); - - XFREE(p, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - XFREE(g, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - - return pSz > 0 && gSz > 0 ? ret : -1; -} -#endif /* OPENSSL_EXTRA */ - -/* server Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ -int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz, - const unsigned char* g, int gSz) -{ - WOLFSSL_ENTER("wolfSSL_SetTmpDH"); - - if (ssl == NULL || p == NULL || g == NULL) - return BAD_FUNC_ARG; - - if ((word16)pSz < ssl->options.minDhKeySz) - return DH_KEY_SIZE_E; - if ((word16)pSz > ssl->options.maxDhKeySz) - return DH_KEY_SIZE_E; - - /* this function is for server only */ - if (ssl->options.side == WOLFSSL_CLIENT_END) - return SIDE_ERROR; - - #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ - !defined(HAVE_SELFTEST) - ssl->options.dhKeyTested = 0; - ssl->options.dhDoKeyTest = 1; - #endif - - if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) { - XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - ssl->buffers.serverDH_P.buffer = NULL; - } - if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) { - XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - ssl->buffers.serverDH_G.buffer = NULL; - } - - ssl->buffers.weOwnDH = 1; /* SSL owns now */ - ssl->buffers.serverDH_P.buffer = (byte*)XMALLOC(pSz, ssl->heap, - DYNAMIC_TYPE_PUBLIC_KEY); - if (ssl->buffers.serverDH_P.buffer == NULL) - return MEMORY_E; - - ssl->buffers.serverDH_G.buffer = (byte*)XMALLOC(gSz, ssl->heap, - DYNAMIC_TYPE_PUBLIC_KEY); - if (ssl->buffers.serverDH_G.buffer == NULL) { - XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - ssl->buffers.serverDH_P.buffer = NULL; - return MEMORY_E; - } - - ssl->buffers.serverDH_P.length = pSz; - ssl->buffers.serverDH_G.length = gSz; - - XMEMCPY(ssl->buffers.serverDH_P.buffer, p, pSz); - XMEMCPY(ssl->buffers.serverDH_G.buffer, g, gSz); - - ssl->options.haveDH = 1; - - if (ssl->options.side != WOLFSSL_NEITHER_END) { - word16 havePSK; - word16 haveRSA; - int keySz = 0; - int ret; - - #ifndef NO_PSK - havePSK = ssl->options.havePSK; - #else - havePSK = 0; - #endif - #ifdef NO_RSA - haveRSA = 0; - #else - haveRSA = 1; - #endif - #ifndef NO_CERTS - keySz = ssl->buffers.keySz; - #endif - ret = AllocateSuites(ssl); - if (ret != 0) - return ret; - InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, - ssl->options.haveDH, ssl->options.haveECDSAsig, - ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, - ssl->options.haveFalconSig, ssl->options.haveDilithiumSig, - ssl->options.useAnon, TRUE, ssl->options.side); - } - - WOLFSSL_LEAVE("wolfSSL_SetTmpDH", 0); - - return WOLFSSL_SUCCESS; -} - - #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ !defined(HAVE_SELFTEST) /* Enables or disables the session's DH key prime test. */ @@ -3138,82 +2800,6 @@ int wolfSSL_SetEnableDhKeyTest(WOLFSSL* ssl, int enable) } #endif - -/* server ctx Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX* ctx, const unsigned char* p, int pSz, - const unsigned char* g, int gSz) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetTmpDH"); - if (ctx == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG; - - if ((word16)pSz < ctx->minDhKeySz) - return DH_KEY_SIZE_E; - if ((word16)pSz > ctx->maxDhKeySz) - return DH_KEY_SIZE_E; - - #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ - !defined(HAVE_SELFTEST) - { - WC_RNG rng; - int error, freeKey = 0; - #ifdef WOLFSSL_SMALL_STACK - DhKey *checkKey = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); - if (checkKey == NULL) - return MEMORY_E; - #else - DhKey checkKey[1]; - #endif - - error = wc_InitRng(&rng); - if (!error) - error = wc_InitDhKey(checkKey); - if (!error) { - freeKey = 1; - error = wc_DhSetCheckKey(checkKey, - p, pSz, g, gSz, NULL, 0, 0, &rng); - } - if (freeKey) - wc_FreeDhKey(checkKey); - #ifdef WOLFSSL_SMALL_STACK - XFREE(checkKey, NULL, DYNAMIC_TYPE_DH); - #endif - wc_FreeRng(&rng); - if (error) - return error; - - ctx->dhKeyTested = 1; - } - #endif - - XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - ctx->serverDH_P.buffer = NULL; - XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - ctx->serverDH_G.buffer = NULL; - - ctx->serverDH_P.buffer = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - if (ctx->serverDH_P.buffer == NULL) - return MEMORY_E; - - ctx->serverDH_G.buffer = (byte*)XMALLOC(gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - if (ctx->serverDH_G.buffer == NULL) { - XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - ctx->serverDH_P.buffer = NULL; - return MEMORY_E; - } - - ctx->serverDH_P.length = pSz; - ctx->serverDH_G.length = gSz; - - XMEMCPY(ctx->serverDH_P.buffer, p, pSz); - XMEMCPY(ctx->serverDH_G.buffer, g, gSz); - - ctx->haveDH = 1; - - WOLFSSL_LEAVE("wolfSSL_CTX_SetTmpDH", 0); - return WOLFSSL_SUCCESS; -} - - int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) { if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) @@ -3909,7 +3495,8 @@ int wolfSSL_UseALPN(WOLFSSL* ssl, char *protocol_name_list, return MEMORY_ERROR; } - token = (char **)XMALLOC(sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1), ssl->heap, DYNAMIC_TYPE_ALPN); + token = (char **)XMALLOC(sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1), + ssl->heap, DYNAMIC_TYPE_ALPN); if (token == NULL) { XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); WOLFSSL_MSG("Memory failure"); @@ -4342,7 +3929,8 @@ int wolfSSL_set_SessionTicket(WOLFSSL* ssl, const byte* buf, } } else { /* Ticket requires dynamic ticket storage */ - if (ssl->session->ticketLen < bufSz) { /* is dyn buffer big enough */ + /* is dyn buffer big enough */ + if (ssl->session->ticketLen < bufSz) { if (ssl->session->ticketLenAlloc > 0) { XFREE(ssl->session->ticket, ssl->session->heap, DYNAMIC_TYPE_SESSION_TICK); @@ -5712,7 +5300,8 @@ int AddTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int verify) #endif XMEMCPY(peerCert->subjectNameHash, cert->subjectHash, SIGNER_DIGEST_SIZE); - peerCert->next = NULL; /* If Key Usage not set, all uses valid. */ + /* If Key Usage not set, all uses valid. */ + peerCert->next = NULL; cert->subjectCN = 0; #ifndef IGNORE_NAME_CONSTRAINTS cert->permittedNames = NULL; @@ -6032,191 +5621,6 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) #endif /* !NO_CERTS */ -#ifndef NO_SESSION_CACHE - - /* basic config gives a cache with 33 sessions, adequate for clients and - embedded servers - - TITAN_SESSION_CACHE allows just over 2 million sessions, for servers - with titanic amounts of memory with long session ID timeouts and high - levels of traffic. - - ENABLE_SESSION_CACHE_ROW_LOCK: Allows row level locking for increased - performance with large session caches - - HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load, - allows over 13,000 new sessions per minute or over 200 new sessions per - second - - BIG_SESSION_CACHE yields 20,027 sessions - - MEDIUM_SESSION_CACHE allows 1055 sessions, adequate for servers that - aren't under heavy load, basically allows 200 new sessions per minute - - SMALL_SESSION_CACHE only stores 6 sessions, good for embedded clients - or systems where the default of is too much RAM. - SessionCache takes about 2K, ClientCache takes about 3Kbytes - - MICRO_SESSION_CACHE only stores 1 session, good for embedded clients - or systems where memory is at a premium. - SessionCache takes about 400 bytes, ClientCache takes 576 bytes - - default SESSION_CACHE stores 33 sessions (no XXX_SESSION_CACHE defined) - SessionCache takes about 13K bytes, ClientCache takes 17K bytes - */ - #if defined(TITAN_SESSION_CACHE) - #define SESSIONS_PER_ROW 31 - #define SESSION_ROWS 64937 - #ifndef ENABLE_SESSION_CACHE_ROW_LOCK - #define ENABLE_SESSION_CACHE_ROW_LOCK - #endif - #elif defined(HUGE_SESSION_CACHE) - #define SESSIONS_PER_ROW 11 - #define SESSION_ROWS 5981 - #elif defined(BIG_SESSION_CACHE) - #define SESSIONS_PER_ROW 7 - #define SESSION_ROWS 2861 - #elif defined(MEDIUM_SESSION_CACHE) - #define SESSIONS_PER_ROW 5 - #define SESSION_ROWS 211 - #elif defined(SMALL_SESSION_CACHE) - #define SESSIONS_PER_ROW 2 - #define SESSION_ROWS 3 - #elif defined(MICRO_SESSION_CACHE) - #define SESSIONS_PER_ROW 1 - #define SESSION_ROWS 1 - #else - #define SESSIONS_PER_ROW 3 - #define SESSION_ROWS 11 - #endif - #define INVALID_SESSION_ROW (-1) - - #ifdef NO_SESSION_CACHE_ROW_LOCK - #undef ENABLE_SESSION_CACHE_ROW_LOCK - #endif - - typedef struct SessionRow { - int nextIdx; /* where to place next one */ - int totalCount; /* sessions ever on this row */ -#ifdef SESSION_CACHE_DYNAMIC_MEM - WOLFSSL_SESSION* Sessions[SESSIONS_PER_ROW]; - void* heap; -#else - WOLFSSL_SESSION Sessions[SESSIONS_PER_ROW]; -#endif - - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - /* not included in import/export */ - wolfSSL_RwLock row_lock; - int lock_valid; - #endif - } SessionRow; - #define SIZEOF_SESSION_ROW (sizeof(WOLFSSL_SESSION) + (sizeof(int) * 2)) - - static WOLFSSL_GLOBAL SessionRow SessionCache[SESSION_ROWS]; - - #if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) - static WOLFSSL_GLOBAL word32 PeakSessions; - #endif - - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - #define SESSION_ROW_RD_LOCK(row) wc_LockRwLock_Rd(&(row)->row_lock) - #define SESSION_ROW_WR_LOCK(row) wc_LockRwLock_Wr(&(row)->row_lock) - #define SESSION_ROW_UNLOCK(row) wc_UnLockRwLock(&(row)->row_lock); - #else - static WOLFSSL_GLOBAL wolfSSL_RwLock session_lock; /* SessionCache lock */ - static WOLFSSL_GLOBAL int session_lock_valid = 0; - #define SESSION_ROW_RD_LOCK(row) wc_LockRwLock_Rd(&session_lock) - #define SESSION_ROW_WR_LOCK(row) wc_LockRwLock_Wr(&session_lock) - #define SESSION_ROW_UNLOCK(row) wc_UnLockRwLock(&session_lock); - #endif - - #if !defined(NO_SESSION_CACHE_REF) && defined(NO_CLIENT_CACHE) - #error ClientCache is required when not using NO_SESSION_CACHE_REF - #endif - - #ifndef NO_CLIENT_CACHE - - #ifndef CLIENT_SESSIONS_MULTIPLIER - #ifdef NO_SESSION_CACHE_REF - #define CLIENT_SESSIONS_MULTIPLIER 1 - #else - /* ClientSession objects are lightweight (compared to - * WOLFSSL_SESSION) so to decrease chance that user will reuse - * the wrong session, increase the ClientCache size. This will - * make the entire ClientCache about the size of one - * WOLFSSL_SESSION object. */ - #define CLIENT_SESSIONS_MULTIPLIER 8 - #endif - #endif - #define CLIENT_SESSIONS_PER_ROW \ - (SESSIONS_PER_ROW * CLIENT_SESSIONS_MULTIPLIER) - #define CLIENT_SESSION_ROWS (SESSION_ROWS * CLIENT_SESSIONS_MULTIPLIER) - - #if CLIENT_SESSIONS_PER_ROW > 65535 - #error CLIENT_SESSIONS_PER_ROW too big - #endif - #if CLIENT_SESSION_ROWS > 65535 - #error CLIENT_SESSION_ROWS too big - #endif - - struct ClientSession { - word16 serverRow; /* SessionCache Row id */ - word16 serverIdx; /* SessionCache Idx (column) */ - word32 sessionIDHash; - }; - #ifndef WOLFSSL_CLIENT_SESSION_DEFINED - typedef struct ClientSession ClientSession; - #define WOLFSSL_CLIENT_SESSION_DEFINED - #endif - - typedef struct ClientRow { - int nextIdx; /* where to place next one */ - int totalCount; /* sessions ever on this row */ - ClientSession Clients[CLIENT_SESSIONS_PER_ROW]; - } ClientRow; - - static WOLFSSL_GLOBAL ClientRow ClientCache[CLIENT_SESSION_ROWS]; - /* Client Cache */ - /* uses session mutex */ - - static WOLFSSL_GLOBAL wolfSSL_Mutex clisession_mutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(clisession_mutex); /* ClientCache mutex */ - #ifndef WOLFSSL_MUTEX_INITIALIZER - static WOLFSSL_GLOBAL int clisession_mutex_valid = 0; - #endif - #endif /* !NO_CLIENT_CACHE */ - - void EvictSessionFromCache(WOLFSSL_SESSION* session) - { -#ifdef HAVE_EX_DATA - int save_ownExData = session->ownExData; - session->ownExData = 1; /* Make sure ex_data access doesn't lead back - * into the cache. */ -#endif -#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) - if (session->rem_sess_cb != NULL) { - session->rem_sess_cb(NULL, session); - session->rem_sess_cb = NULL; - } -#endif - ForceZero(session->masterSecret, SECRET_LEN); - XMEMSET(session->sessionID, 0, ID_LEN); - session->sessionIDSz = 0; -#ifdef HAVE_SESSION_TICKET - if (session->ticketLenAlloc > 0) { - XFREE(session->ticket, NULL, DYNAMIC_TYPE_SESSION_TICK); - session->ticket = session->staticTicket; - session->ticketLen = 0; - session->ticketLenAlloc = 0; - } -#endif -#ifdef HAVE_EX_DATA - session->ownExData = save_ownExData; -#endif - } - -#endif /* !NO_SESSION_CACHE */ - #if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) static int wolfSSL_RAND_InitMutex(void); #endif @@ -6258,13 +5662,13 @@ int wolfSSL_Init(void) return BAD_MUTEX_E; } - #if FIPS_VERSION_GE(5,1) +#if FIPS_VERSION_GE(5,1) if ((ret == WOLFSSL_SUCCESS) && (initRefCount == 0)) { ret = wolfCrypt_SetPrivateKeyReadEnable_fips(1, WC_KEYTYPE_ALL); if (ret == 0) ret = WOLFSSL_SUCCESS; } - #endif +#endif if ((ret == WOLFSSL_SUCCESS) && (initRefCount == 0)) { /* Initialize crypto for use with TLS connection */ @@ -6366,2152 +5770,11 @@ int wolfSSL_Init(void) } +#define WOLFSSL_SSL_LOAD_INCLUDED +#include + #ifndef NO_CERTS -/* process user cert chain to pass during the handshake */ -static int ProcessUserChain(WOLFSSL_CTX* ctx, const unsigned char* buff, - long sz, int format, int type, WOLFSSL* ssl, - long* used, EncryptedInfo* info, int verify) -{ - int ret = 0; - void* heap = wolfSSL_CTX_GetHeap(ctx, ssl); - - if ((type == CA_TYPE) && (ctx == NULL)) { - WOLFSSL_MSG("Need context for CA load"); - return BAD_FUNC_ARG; - } - - /* we may have a user cert chain, try to consume */ - if ((type == CERT_TYPE || type == CHAIN_CERT_TYPE || type == CA_TYPE) && - (info->consumed < sz)) { - #ifdef WOLFSSL_SMALL_STACK - byte staticBuffer[1]; /* force heap usage */ - #else - byte staticBuffer[FILE_BUFFER_SIZE]; /* tmp chain buffer */ - #endif - byte* chainBuffer = staticBuffer; - int dynamicBuffer = 0; - word32 bufferSz; - long consumed = info->consumed; - word32 idx = 0; - int gotOne = 0; - #ifdef WOLFSSL_TLS13 - int cnt = 0; - #endif - - /* Calculate max possible size, including max headers */ - bufferSz = (word32)(sz - consumed) + (CERT_HEADER_SZ * MAX_CHAIN_DEPTH); - if (bufferSz > sizeof(staticBuffer)) { - WOLFSSL_MSG("Growing Tmp Chain Buffer"); - /* will shrink to actual size */ - chainBuffer = (byte*)XMALLOC(bufferSz, heap, DYNAMIC_TYPE_FILE); - if (chainBuffer == NULL) { - return MEMORY_E; - } - dynamicBuffer = 1; - } - - WOLFSSL_MSG("Processing Cert Chain"); - while (consumed < sz) { - DerBuffer* part = NULL; - word32 remain = (word32)(sz - consumed); - info->consumed = 0; - - if (format == WOLFSSL_FILETYPE_PEM) { - #ifdef WOLFSSL_PEM_TO_DER - ret = PemToDer(buff + consumed, remain, type, &part, - heap, info, NULL); - #else - ret = NOT_COMPILED_IN; - #endif - } - else { - int length = remain; - if (format == WOLFSSL_FILETYPE_ASN1) { - /* get length of der (read sequence) */ - word32 inOutIdx = 0; - if (GetSequence(buff + consumed, &inOutIdx, &length, - remain) < 0) { - ret = ASN_NO_PEM_HEADER; - } - length += inOutIdx; /* include leading sequence */ - } - info->consumed = length; - if (ret == 0) { - ret = AllocDer(&part, length, type, heap); - if (ret == 0) { - XMEMCPY(part->buffer, buff + consumed, length); - } - } - } - if (ret == 0) { - gotOne = 1; -#ifdef WOLFSSL_TLS13 - cnt++; -#endif - if ((idx + part->length + CERT_HEADER_SZ) > bufferSz) { - WOLFSSL_MSG(" Cert Chain bigger than buffer. " - "Consider increasing MAX_CHAIN_DEPTH"); - ret = BUFFER_E; - } - else { - c32to24(part->length, &chainBuffer[idx]); - idx += CERT_HEADER_SZ; - XMEMCPY(&chainBuffer[idx], part->buffer, part->length); - idx += part->length; - consumed += info->consumed; - if (used) - *used += info->consumed; - } - - /* add CA's to certificate manager */ - if (ret == 0 && type == CA_TYPE) { - /* verify CA unless user set to no verify */ - ret = AddCA(ctx->cm, &part, WOLFSSL_USER_CA, verify); - if (ret == WOLFSSL_SUCCESS) { - ret = 0; /* converted success case */ - } - gotOne = 0; /* don't exit loop for CA type */ - } - } - - FreeDer(&part); - - if (ret == ASN_NO_PEM_HEADER && gotOne) { - WOLFSSL_MSG("We got one good cert, so stuff at end ok"); - break; - } - - if (ret < 0) { - WOLFSSL_MSG(" Error in Cert in Chain"); - if (dynamicBuffer) - XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE); - return ret; - } - WOLFSSL_MSG(" Consumed another Cert in Chain"); - } - WOLFSSL_MSG("Finished Processing Cert Chain"); - - /* only retain actual size used */ - ret = 0; - if (idx > 0) { - if (ssl) { - if (ssl->buffers.weOwnCertChain) { - FreeDer(&ssl->buffers.certChain); - } - ret = AllocDer(&ssl->buffers.certChain, idx, type, heap); - if (ret == 0) { - XMEMCPY(ssl->buffers.certChain->buffer, chainBuffer, - idx); - ssl->buffers.weOwnCertChain = 1; - } - #ifdef WOLFSSL_TLS13 - ssl->buffers.certChainCnt = cnt; - #endif - } else if (ctx) { - FreeDer(&ctx->certChain); - ret = AllocDer(&ctx->certChain, idx, type, heap); - if (ret == 0) { - XMEMCPY(ctx->certChain->buffer, chainBuffer, idx); - } - #ifdef WOLFSSL_TLS13 - ctx->certChainCnt = cnt; - #endif - } - } - - if (dynamicBuffer) - XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE); - } - - return ret; -} - -#ifndef NO_RSA -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION > 2)) -static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - int devId, int type) -{ - int ret; - - (void)devId; - (void)type; - - *idx = 0; - ret = wc_RsaPrivateKeyValidate(der->buffer, idx, keySz, der->length); -#ifdef WOLF_PRIVATE_KEY_ID - if ((ret != 0) && (devId != INVALID_DEVID - #ifdef HAVE_PK_CALLBACKS - || ((ssl == NULL) ? wolfSSL_CTX_IsPrivatePkSet(ctx) : - wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) - #endif - )) { - word32 nSz; - - /* if using crypto or PK callbacks, try public key decode */ - *idx = 0; - ret = wc_RsaPublicKeyDecode_ex(der->buffer, idx, der->length, NULL, - &nSz, NULL, NULL); - if (ret == 0) { - *keySz = (int)nSz; - } - } -#endif - if (ret != 0) { - #if !defined(HAVE_ECC) && !defined(HAVE_ED25519) && \ - !defined(HAVE_ED448) && !defined(HAVE_PQC) - WOLFSSL_MSG("RSA decode failed and other algorithms " - "not enabled to try"); - ret = WOLFSSL_BAD_FILE; - #else - if (*keyFormat == 0) { - /* Format unknown so keep trying. */ - ret = 0; /* continue trying other algorithms */ - } - #endif - } - else { - /* check that the size of the RSA key is enough */ - int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz; - if (*keySz < minRsaSz) { - ret = RSA_KEY_SIZE_E; - WOLFSSL_MSG("Private Key size too small"); - } - - if (ssl) { - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (type == ALT_PRIVATEKEY_TYPE) { - ssl->buffers.altKeyType = rsa_sa_algo; - ssl->buffers.altKeySz = *keySz; - } - else - #endif /* WOLFSSL_DUAL_ALG_CERTS */ - { - ssl->buffers.keyType = rsa_sa_algo; - ssl->buffers.keySz = *keySz; - } - } - else { - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (type == ALT_PRIVATEKEY_TYPE) { - ctx->altPrivateKeyType = rsa_sa_algo; - ctx->altPrivateKeySz = *keySz; - } - else - #endif /* WOLFSSL_DUAL_ALG_CERTS */ - { - ctx->privateKeyType = rsa_sa_algo; - ctx->privateKeySz = *keySz; - } - } - - *keyFormat = RSAk; - - if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { - ssl->options.haveStaticECC = 0; - *resetSuites = 1; - } - } - - return ret; -} -#else -static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - void* heap, int devId, int type) -{ - int ret; - - (void)type; - - /* make sure RSA key can be used */ -#ifdef WOLFSSL_SMALL_STACK - RsaKey* key; -#else - RsaKey key[1]; -#endif - -#ifdef WOLFSSL_SMALL_STACK - key = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA); - if (key == NULL) - return MEMORY_E; -#endif - - ret = wc_InitRsaKey_ex(key, heap, devId); - if (ret == 0) { - *idx = 0; - ret = wc_RsaPrivateKeyDecode(der->buffer, idx, key, der->length); - #ifdef WOLF_PRIVATE_KEY_ID - if (ret != 0 && (devId != INVALID_DEVID - #ifdef HAVE_PK_CALLBACKS - || ((ssl == NULL) ? wolfSSL_CTX_IsPrivatePkSet(ctx) : - wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) - #endif - )) { - /* if using crypto or PK 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) && !defined(HAVE_PQC) - WOLFSSL_MSG("RSA decode failed and other algorithms " - "not enabled to try"); - ret = WOLFSSL_BAD_FILE; - #else - if (*keyFormat == 0) { - /* Format unknown so keep trying. */ - ret = 0; /* continue trying other algorithms */ - } - #endif - } - else { - /* check that the size of the RSA key is enough */ - int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz; - *keySz = wc_RsaEncryptSize((RsaKey*)key); - if (*keySz < minRsaSz) { - ret = RSA_KEY_SIZE_E; - WOLFSSL_MSG("Private Key size too small"); - } - - if (ssl) { - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (type == ALT_PRIVATEKEY_TYPE) { - ssl->buffers.altKeyType = rsa_sa_algo; - ssl->buffers.altKeySz = *keySz; - } - else - #endif /* WOLFSSL_DUAL_ALG_CERTS */ - { - ssl->buffers.keyType = rsa_sa_algo; - ssl->buffers.keySz = *keySz; - } - } - else { - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (type == ALT_PRIVATEKEY_TYPE) { - ctx->altPrivateKeyType = rsa_sa_algo; - ctx->altPrivateKeySz = *keySz; - } - else - #endif /* WOLFSSL_DUAL_ALG_CERTS */ - { - ctx->privateKeyType = rsa_sa_algo; - ctx->privateKeySz = *keySz; - } - } - - *keyFormat = RSAk; - - if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { - ssl->options.haveStaticECC = 0; - *resetSuites = 1; - } - } - - wc_FreeRsaKey(key); - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(key, heap, DYNAMIC_TYPE_RSA); -#endif - - return ret; -} -#endif -#endif /* !NO_RSA */ - -#ifdef HAVE_ECC -static int ProcessBufferTryDecodeEcc(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - void* heap, int devId, int type) -{ - int ret = 0; - /* make sure ECC key can be used */ -#ifdef WOLFSSL_SMALL_STACK - ecc_key* key; -#else - ecc_key key[1]; -#endif - - (void)type; - -#ifdef WOLFSSL_SMALL_STACK - key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC); - if (key == NULL) - return MEMORY_E; -#endif - - if (wc_ecc_init_ex(key, heap, devId) == 0) { - *idx = 0; - ret = wc_EccPrivateKeyDecode(der->buffer, idx, key, der->length); - #ifdef WOLF_PRIVATE_KEY_ID - if (ret != 0 && (devId != INVALID_DEVID - #ifdef HAVE_PK_CALLBACKS - || ((ssl == NULL) ? wolfSSL_CTX_IsPrivatePkSet(ctx) : - wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) - #endif - )) { - /* if using crypto or PK 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; - *keySz = wc_ecc_size(key); - if (*keySz < minKeySz) { - WOLFSSL_MSG("ECC private key too small"); - ret = ECC_KEY_SIZE_E; - } - - *keyFormat = ECDSAk; - if (ssl) { - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (type == ALT_PRIVATEKEY_TYPE) { - ssl->buffers.altKeyType = ecc_dsa_sa_algo; - ssl->buffers.altKeySz = *keySz; - } - else - #endif /* WOLFSSL_DUAL_ALG_CERTS */ - { - ssl->options.haveStaticECC = 1; - #ifdef WOLFSSL_SM2 - if (key->dp->id == ECC_SM2P256V1) - ssl->buffers.keyType = sm2_sa_algo; - else - #endif - ssl->buffers.keyType = ecc_dsa_sa_algo; - ssl->buffers.keySz = *keySz; - } - } - else { - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (type == ALT_PRIVATEKEY_TYPE) { - ctx->altPrivateKeyType = ecc_dsa_sa_algo; - ctx->altPrivateKeySz = *keySz; - } - else - #endif /* WOLFSSL_DUAL_ALG_CERTS */ - { - ctx->haveStaticECC = 1; - #ifdef WOLFSSL_SM2 - if (key->dp->id == ECC_SM2P256V1) - ctx->privateKeyType = sm2_sa_algo; - else - #endif - ctx->privateKeyType = ecc_dsa_sa_algo; - ctx->privateKeySz = *keySz; - } - } - - if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { - *resetSuites = 1; - } - } - else if (*keyFormat == 0) { - ret = 0; /* continue trying other algorithms */ - } - - wc_ecc_free(key); - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(key, heap, DYNAMIC_TYPE_ECC); -#endif - return ret; -} -#endif /* HAVE_ECC */ - -#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) -static int ProcessBufferTryDecodeEd25519(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - void* heap, int devId) -{ - int ret; - /* make sure Ed25519 key can be used */ -#ifdef WOLFSSL_SMALL_STACK - ed25519_key* key; -#else - ed25519_key key[1]; -#endif - -#ifdef WOLFSSL_SMALL_STACK - key = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap, - DYNAMIC_TYPE_ED25519); - if (key == NULL) - return MEMORY_E; -#endif - - ret = wc_ed25519_init_ex(key, heap, devId); - if (ret == 0) { - *idx = 0; - ret = wc_Ed25519PrivateKeyDecode(der->buffer, idx, key, der->length); - #ifdef WOLF_PRIVATE_KEY_ID - if (ret != 0 && (devId != INVALID_DEVID - #ifdef HAVE_PK_CALLBACKS - || ((ssl == NULL) ? wolfSSL_CTX_IsPrivatePkSet(ctx) : - wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) - #endif - )) { - /* if using crypto or PK 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; - *keySz = ED25519_KEY_SIZE; - if (*keySz < minKeySz) { - WOLFSSL_MSG("ED25519 private key too small"); - ret = ECC_KEY_SIZE_E; - } - if (ret == 0) { - if (ssl) { - ssl->buffers.keyType = ed25519_sa_algo; - ssl->buffers.keySz = *keySz; - } - else { - ctx->privateKeyType = ed25519_sa_algo; - ctx->privateKeySz = *keySz; - } - - *keyFormat = ED25519k; - if (ssl != NULL) { -#if !defined(WOLFSSL_NO_CLIENT_AUTH) && !defined(NO_ED25519_CLIENT_AUTH) - /* ED25519 requires caching enabled for tracking message - * hash used in EdDSA_Update for signing */ - ssl->options.cacheMessages = 1; -#endif - if (ssl->options.side == WOLFSSL_SERVER_END) { - *resetSuites = 1; - } - } - } - } - else if (*keyFormat == 0) { - ret = 0; /* continue trying other algorithms */ - } - - wc_ed25519_free(key); - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(key, heap, DYNAMIC_TYPE_ED25519); -#endif - return ret; -} -#endif /* HAVE_ED25519 && HAVE_ED25519_KEY_IMPORT */ - -#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) -static int ProcessBufferTryDecodeEd448(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - void* heap, int devId) -{ - int ret; - /* make sure Ed448 key can be used */ -#ifdef WOLFSSL_SMALL_STACK - ed448_key* key = NULL; -#else - ed448_key key[1]; -#endif - -#ifdef WOLFSSL_SMALL_STACK - key = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, DYNAMIC_TYPE_ED448); - if (key == NULL) - return MEMORY_E; -#endif - - ret = wc_ed448_init_ex(key, heap, devId); - if (ret == 0) { - *idx = 0; - ret = wc_Ed448PrivateKeyDecode(der->buffer, idx, key, der->length); - #ifdef WOLF_PRIVATE_KEY_ID - if (ret != 0 && (devId != INVALID_DEVID - #ifdef HAVE_PK_CALLBACKS - || ((ssl == NULL) ? wolfSSL_CTX_IsPrivatePkSet(ctx) : - wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) - #endif - )) { - /* if using crypto or PK callbacks, try public key decode */ - *idx = 0; - ret = wc_Ed448PublicKeyDecode(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; - *keySz = ED448_KEY_SIZE; - if (*keySz < minKeySz) { - WOLFSSL_MSG("ED448 private key too small"); - ret = ECC_KEY_SIZE_E; - } - } - if (ret == 0) { - if (ssl) { - ssl->buffers.keyType = ed448_sa_algo; - ssl->buffers.keySz = *keySz; - } - else if (ctx) { - ctx->privateKeyType = ed448_sa_algo; - ctx->privateKeySz = *keySz; - } - - *keyFormat = ED448k; - 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; - } - } - } - else if (*keyFormat == 0) { - ret = 0; /* continue trying other algorithms */ - } - - wc_ed448_free(key); - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(key, heap, DYNAMIC_TYPE_ED448); -#endif - return ret; -} -#endif /* HAVE_ED448 && HAVE_ED448_KEY_IMPORT */ - -#if defined(HAVE_PQC) -#if defined(HAVE_FALCON) -static int ProcessBufferTryDecodeFalcon(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - void* heap, int type) -{ - int ret; - /* make sure Falcon key can be used */ - falcon_key* key = (falcon_key*)XMALLOC(sizeof(falcon_key), heap, - DYNAMIC_TYPE_FALCON); - (void) type; - if (key == NULL) { - return MEMORY_E; - } - ret = wc_falcon_init(key); - if (ret == 0) { - if (*keyFormat == FALCON_LEVEL1k) { - ret = wc_falcon_set_level(key, 1); - } - else if (*keyFormat == FALCON_LEVEL5k) { - ret = wc_falcon_set_level(key, 5); - } - else { - /* What if *keyformat is 0? We might want to do something more - * graceful here. */ - wc_falcon_free(key); - ret = ALGO_ID_E; - } - } - - if (ret == 0) { - *idx = 0; - ret = wc_falcon_import_private_only(der->buffer, der->length, key); - if (ret == 0) { - /* check for minimum key size and then free */ - int minKeySz = ssl ? ssl->options.minFalconKeySz : - ctx->minFalconKeySz; - *keySz = wc_falcon_size(key); - if (*keySz < minKeySz) { - WOLFSSL_MSG("Falcon private key too small"); - ret = FALCON_KEY_SIZE_E; - } - if (ssl) { -#ifdef WOLFSSL_DUAL_ALG_CERTS - if (type == ALT_PRIVATEKEY_TYPE) { - if (*keyFormat == FALCON_LEVEL1k) { - ssl->buffers.altKeyType = falcon_level1_sa_algo; - } - else { - ssl->buffers.altKeyType = falcon_level5_sa_algo; - } - ssl->buffers.altKeySz = *keySz; - } - else -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - { - if (*keyFormat == FALCON_LEVEL1k) { - ssl->buffers.keyType = falcon_level1_sa_algo; - } - else { - ssl->buffers.keyType = falcon_level5_sa_algo; - } - ssl->buffers.keySz = *keySz; - } - } - else { -#ifdef WOLFSSL_DUAL_ALG_CERTS - if (type == ALT_PRIVATEKEY_TYPE) { - if (*keyFormat == FALCON_LEVEL1k) { - ctx->altPrivateKeyType = falcon_level1_sa_algo; - } - else { - ctx->altPrivateKeyType = falcon_level5_sa_algo; - } - ctx->altPrivateKeySz = *keySz; - } - else -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - { - if (*keyFormat == FALCON_LEVEL1k) { - ctx->privateKeyType = falcon_level1_sa_algo; - } - else { - ctx->privateKeyType = falcon_level5_sa_algo; - } - ctx->privateKeySz = *keySz; - } - } - - if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { - *resetSuites = 1; - } - } - else if (*keyFormat == 0) { - ret = 0; /* continue trying other algorithms */ - } - - wc_falcon_free(key); - } - XFREE(key, heap, DYNAMIC_TYPE_FALCON); - return ret; -} -#endif - -#if defined(HAVE_DILITHIUM) -static int ProcessBufferTryDecodeDilithium(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - void* heap, int type) -{ - int ret; - /* make sure Dilithium key can be used */ - dilithium_key* key = (dilithium_key*)XMALLOC(sizeof(dilithium_key), heap, - DYNAMIC_TYPE_DILITHIUM); - (void) type; - if (key == NULL) { - return MEMORY_E; - } - ret = wc_dilithium_init(key); - if (ret == 0) { - if (*keyFormat == DILITHIUM_LEVEL2k) { - ret = wc_dilithium_set_level(key, 2); - } - else if (*keyFormat == DILITHIUM_LEVEL3k) { - ret = wc_dilithium_set_level(key, 3); - } - else if (*keyFormat == DILITHIUM_LEVEL5k) { - ret = wc_dilithium_set_level(key, 5); - } - else { - /* What if *keyformat is 0? We might want to do something more - * graceful here. */ - wc_dilithium_free(key); - ret = ALGO_ID_E; - } - } - - if (ret == 0) { - *idx = 0; - ret = wc_dilithium_import_private_only(der->buffer, der->length, key); - if (ret == 0) { - /* check for minimum key size and then free */ - int minKeySz = ssl ? ssl->options.minDilithiumKeySz : - ctx->minDilithiumKeySz; - *keySz = wc_dilithium_size(key); - if (*keySz < minKeySz) { - WOLFSSL_MSG("Dilithium private key too small"); - ret = DILITHIUM_KEY_SIZE_E; - } - if (ssl) { -#ifdef WOLFSSL_DUAL_ALG_CERTS - if (type == ALT_PRIVATEKEY_TYPE) { - if (*keyFormat == DILITHIUM_LEVEL2k) { - ssl->buffers.altKeyType = dilithium_level2_sa_algo; - } - else if (*keyFormat == DILITHIUM_LEVEL3k) { - ssl->buffers.altKeyType = dilithium_level3_sa_algo; - } - else if (*keyFormat == DILITHIUM_LEVEL5k) { - ssl->buffers.altKeyType = dilithium_level5_sa_algo; - } - ssl->buffers.altKeySz = *keySz; - } - else -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - { - if (*keyFormat == DILITHIUM_LEVEL2k) { - ssl->buffers.keyType = dilithium_level2_sa_algo; - } - else if (*keyFormat == DILITHIUM_LEVEL3k) { - ssl->buffers.keyType = dilithium_level3_sa_algo; - } - else if (*keyFormat == DILITHIUM_LEVEL5k) { - ssl->buffers.keyType = dilithium_level5_sa_algo; - } - ssl->buffers.keySz = *keySz; - } - } - else { -#ifdef WOLFSSL_DUAL_ALG_CERTS - if (type == ALT_PRIVATEKEY_TYPE) { - if (*keyFormat == DILITHIUM_LEVEL2k) { - ctx->altPrivateKeyType = dilithium_level2_sa_algo; - } - else if (*keyFormat == DILITHIUM_LEVEL3k) { - ctx->altPrivateKeyType = dilithium_level3_sa_algo; - } - else if (*keyFormat == DILITHIUM_LEVEL5k) { - ctx->altPrivateKeyType = dilithium_level5_sa_algo; - } - ctx->altPrivateKeySz = *keySz; - } - else -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - { - if (*keyFormat == DILITHIUM_LEVEL2k) { - ctx->privateKeyType = dilithium_level2_sa_algo; - } - else if (*keyFormat == DILITHIUM_LEVEL3k) { - ctx->privateKeyType = dilithium_level3_sa_algo; - } - else if (*keyFormat == DILITHIUM_LEVEL5k) { - ctx->privateKeyType = dilithium_level5_sa_algo; - } - ctx->privateKeySz = *keySz; - } - } - - if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { - *resetSuites = 1; - } - } - else if (*keyFormat == 0) { - ret = 0; /* continue trying other algorithms */ - } - - wc_dilithium_free(key); - } - XFREE(key, heap, DYNAMIC_TYPE_DILITHIUM); - - return ret; -} -#endif /* HAVE_DILITHIUM */ -#endif /* HAVE_PQC */ - -static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - void* heap, int devId, int type) -{ - int ret = 0; - - (void)heap; - (void)devId; - (void)type; - - if (ctx == NULL && ssl == NULL) - return BAD_FUNC_ARG; - if (!der || !keySz || !idx || !resetSuites || !keyFormat) - return BAD_FUNC_ARG; - -#ifndef NO_RSA - if ((*keyFormat == 0 || *keyFormat == RSAk)) { -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION > 2)) - ret = ProcessBufferTryDecodeRsa(ctx, ssl, der, keySz, idx, resetSuites, - keyFormat, devId, type); -#else - ret = ProcessBufferTryDecodeRsa(ctx, ssl, der, keySz, idx, resetSuites, - keyFormat, heap, devId, type); -#endif - if (ret != 0) - return ret; - } -#endif -#ifdef HAVE_ECC - if ((*keyFormat == 0) || (*keyFormat == ECDSAk) - #ifdef WOLFSSL_SM2 - || (*keyFormat == SM2k) - #endif - ) { - ret = ProcessBufferTryDecodeEcc(ctx, ssl, der, keySz, idx, resetSuites, - keyFormat, heap, devId, type); - if (ret != 0) - return ret; - } -#endif /* HAVE_ECC */ -#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) - if ((*keyFormat == 0 || *keyFormat == ED25519k)) { - ret = ProcessBufferTryDecodeEd25519(ctx, ssl, der, keySz, idx, - resetSuites, keyFormat, heap, devId); - if (ret != 0) - return ret; - } -#endif /* HAVE_ED25519 && HAVE_ED25519_KEY_IMPORT */ -#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) - if ((*keyFormat == 0 || *keyFormat == ED448k)) { - ret = ProcessBufferTryDecodeEd448(ctx, ssl, der, keySz, idx, - resetSuites, keyFormat, heap, devId); - if (ret != 0) - return ret; - } -#endif /* HAVE_ED448 && HAVE_ED448_KEY_IMPORT */ -#if defined(HAVE_PQC) -#if defined(HAVE_FALCON) - if (((*keyFormat == 0) || (*keyFormat == FALCON_LEVEL1k) || - (*keyFormat == FALCON_LEVEL5k))) { - ret = ProcessBufferTryDecodeFalcon(ctx, ssl, der, keySz, idx, - resetSuites, keyFormat, heap, type); - if (ret != 0) - return ret; - } -#endif /* HAVE_FALCON */ -#if defined(HAVE_DILITHIUM) - if ((*keyFormat == 0) || - (*keyFormat == DILITHIUM_LEVEL2k) || - (*keyFormat == DILITHIUM_LEVEL3k) || - (*keyFormat == DILITHIUM_LEVEL5k)) { - ret = ProcessBufferTryDecodeDilithium(ctx, ssl, der, keySz, idx, - resetSuites, keyFormat, heap, type); - if (ret != 0) { - return ret; - } - } -#endif /* HAVE_DILITHIUM */ -#endif /* HAVE_PQC */ - return ret; -} - -/* process the buffer buff, length sz, into ctx of format and type - used tracks bytes consumed, userChain specifies a user cert chain - to pass during the handshake */ -int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, - long sz, int format, int type, WOLFSSL* ssl, - long* used, int userChain, int verify) -{ - DerBuffer* der = NULL; - int ret = 0; - int done = 0; - int keyFormat = 0; - int resetSuites = 0; - void* heap = wolfSSL_CTX_GetHeap(ctx, ssl); - int devId = wolfSSL_CTX_GetDevId(ctx, ssl); - word32 idx = 0; - int keySz = 0; -#if (defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)) || \ - defined(HAVE_PKCS8) - word32 algId = 0; -#endif -#ifdef WOLFSSL_SMALL_STACK - EncryptedInfo* info = NULL; -#else - EncryptedInfo info[1]; -#endif - - (void)devId; - (void)idx; - (void)keySz; - - if (used) - *used = sz; /* used bytes default to sz, PEM chain may shorten*/ - - /* check args */ - if (format != WOLFSSL_FILETYPE_ASN1 && format != WOLFSSL_FILETYPE_PEM) - return WOLFSSL_BAD_FILETYPE; - - if (ctx == NULL && ssl == NULL) - return BAD_FUNC_ARG; - - /* This API does not handle CHAIN_CERT_TYPE */ - if (type == CHAIN_CERT_TYPE) - return BAD_FUNC_ARG; - -#ifdef WOLFSSL_SMALL_STACK - info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), heap, - DYNAMIC_TYPE_ENCRYPTEDINFO); - if (info == NULL) - return MEMORY_E; -#endif - - XMEMSET(info, 0, sizeof(EncryptedInfo)); -#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED) - if (ctx) { - info->passwd_cb = ctx->passwd_cb; - info->passwd_userdata = ctx->passwd_userdata; - } -#endif - - if (format == WOLFSSL_FILETYPE_PEM) { - #ifdef WOLFSSL_PEM_TO_DER - ret = PemToDer(buff, sz, type, &der, heap, info, &keyFormat); - #else - ret = NOT_COMPILED_IN; - #endif - } - else { - /* ASN1 (DER) */ - int length = (int)sz; - word32 inOutIdx = 0; - /* get length of der (read sequence or octet string) */ - if (GetSequence(buff, &inOutIdx, &length, (word32)sz) >= 0) { - length += inOutIdx; /* include leading sequence */ - } - /* get length using octet string (allowed for private key types) */ - else if (type == PRIVATEKEY_TYPE && - GetOctetString(buff, &inOutIdx, &length, (word32)sz) >= 0) { - length += inOutIdx; /* include leading oct string */ - } - else { - ret = ASN_PARSE_E; - } - - info->consumed = length; - - if (ret == 0) { - ret = AllocDer(&der, (word32)length, type, heap); - if (ret == 0) { - XMEMCPY(der->buffer, buff, length); - } - - #ifdef HAVE_PKCS8 - /* if private key try and remove PKCS8 header */ - if (ret == 0 && type == PRIVATEKEY_TYPE) { - if ((ret = ToTraditional_ex(der->buffer, der->length, - &algId)) > 0) { - /* Found PKCS8 header */ - /* ToTraditional_ex moves buff and returns adjusted length */ - der->length = ret; - keyFormat = algId; - } - ret = 0; /* failures should be ignored */ - } - #endif - } - } - - if (used) { - *used = info->consumed; - } - - /* process user chain */ - if (ret >= 0) { - /* Chain should have server cert first, then intermediates, then root. - * First certificate in chain is processed below after ProcessUserChain - * and is loaded into ssl->buffers.certificate. - * Remainder are processed using ProcessUserChain and are loaded into - * ssl->buffers.certChain. */ - if (userChain) { - ret = ProcessUserChain(ctx, buff, sz, format, CHAIN_CERT_TYPE, ssl, - used, info, verify); - if (ret == ASN_NO_PEM_HEADER) { /* Additional chain is optional */ - unsigned long pemErr = 0; - CLEAR_ASN_NO_PEM_HEADER_ERROR(pemErr); - ret = 0; - } - } - } - - /* info is only used for private key with DER or PEM, so free now */ - if (ret < 0 || type != PRIVATEKEY_TYPE) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); - #endif - } - - /* check for error */ - if (ret < 0) { - FreeDer(&der); - done = 1; - } - - if (done == 1) { - /* No operation, just skip the next section */ - } - /* Handle DER owner */ - else if (type == CA_TYPE) { - if (ctx == NULL) { - WOLFSSL_MSG("Need context for CA load"); - FreeDer(&der); - return BAD_FUNC_ARG; - } - /* verify CA unless user set to no verify */ - ret = AddCA(ctx->cm, &der, WOLFSSL_USER_CA, verify); - done = 1; - } -#ifdef WOLFSSL_TRUST_PEER_CERT - else if (type == TRUSTED_PEER_TYPE) { - /* add trusted peer cert. der is freed within */ - if (ctx != NULL) - ret = AddTrustedPeer(ctx->cm, &der, verify); - else { - SSL_CM_WARNING(ssl); - ret = AddTrustedPeer(SSL_CM(ssl), &der, verify); - } - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Error adding trusted peer"); - } - done = 1; - } -#endif /* WOLFSSL_TRUST_PEER_CERT */ - else if (type == CERT_TYPE) { - if (ssl != NULL) { - /* Make sure previous is free'd */ - if (ssl->buffers.weOwnCert) { - FreeDer(&ssl->buffers.certificate); - #ifdef KEEP_OUR_CERT - wolfSSL_X509_free(ssl->ourCert); - ssl->ourCert = NULL; - #endif - } - ssl->buffers.certificate = der; - #ifdef KEEP_OUR_CERT - ssl->keepCert = 1; /* hold cert for ssl lifetime */ - #endif - ssl->buffers.weOwnCert = 1; - } - else if (ctx != NULL) { - FreeDer(&ctx->certificate); /* Make sure previous is free'd */ - #ifdef KEEP_OUR_CERT - if (ctx->ourCert) { - if (ctx->ownOurCert) - wolfSSL_X509_free(ctx->ourCert); - ctx->ourCert = NULL; - } - #endif - ctx->certificate = der; - } - } - else if (type == PRIVATEKEY_TYPE) { - if (ssl != NULL) { - /* Make sure previous is free'd */ - if (ssl->buffers.weOwnKey) { - ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); - FreeDer(&ssl->buffers.key); - } - ssl->buffers.keyId = 0; - ssl->buffers.keyLabel = 0; - ssl->buffers.keyDevId = INVALID_DEVID; - ssl->buffers.key = der; -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("SSL Buffers key", der->buffer, der->length); -#endif - ssl->buffers.weOwnKey = 1; - } - else if (ctx != NULL) { - if (ctx->privateKey != NULL && ctx->privateKey->buffer != NULL) { - ForceZero(ctx->privateKey->buffer, ctx->privateKey->length); - } - FreeDer(&ctx->privateKey); - ctx->privateKeyId = 0; - ctx->privateKeyLabel = 0; - ctx->privateKeyDevId = INVALID_DEVID; - ctx->privateKey = der; -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("CTX private key", der->buffer, der->length); -#endif - } - } -#ifdef WOLFSSL_DUAL_ALG_CERTS - else if (type == ALT_PRIVATEKEY_TYPE) { - if (ssl != NULL) { - /* Make sure previous is free'd */ - if (ssl->buffers.weOwnAltKey) { - ForceZero(ssl->buffers.altKey->buffer, - ssl->buffers.altKey->length); - FreeDer(&ssl->buffers.altKey); - } - ssl->buffers.altKeyId = 0; - ssl->buffers.altKeyLabel = 0; - ssl->buffers.altKeyDevId = INVALID_DEVID; - ssl->buffers.altKey = der; -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("SSL Buffers key", der->buffer, der->length); -#endif - ssl->buffers.weOwnAltKey = 1; - } - else if (ctx != NULL) { - if (ctx->altPrivateKey != NULL && - ctx->altPrivateKey->buffer != NULL) { - ForceZero(ctx->altPrivateKey->buffer, - ctx->altPrivateKey->length); - } - FreeDer(&ctx->altPrivateKey); - ctx->altPrivateKeyId = 0; - ctx->altPrivateKeyLabel = 0; - ctx->altPrivateKeyDevId = INVALID_DEVID; - ctx->altPrivateKey = der; -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("CTX private key", der->buffer, der->length); -#endif - } - } -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - else { - FreeDer(&der); - return WOLFSSL_BAD_CERTTYPE; - } - - if (done == 1) { - /* No operation, just skip the next section */ - } - else if (type == PRIVATEKEY_TYPE -#ifdef WOLFSSL_DUAL_ALG_CERTS - || type == ALT_PRIVATEKEY_TYPE -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - ) { - ret = ProcessBufferTryDecode(ctx, ssl, der, &keySz, &idx, &resetSuites, - &keyFormat, heap, devId, type); - - #if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED) - /* for WOLFSSL_FILETYPE_PEM, PemToDer manages the decryption */ - /* If private key type PKCS8 header wasn't already removed (algoId == 0) */ - if ((ret != 0 || keyFormat == 0) - && format != WOLFSSL_FILETYPE_PEM && info->passwd_cb && algId == 0) - { - int passwordSz = NAME_SZ; - #ifndef WOLFSSL_SMALL_STACK - char password[NAME_SZ]; - #else - char* password = (char*)XMALLOC(passwordSz, heap, DYNAMIC_TYPE_STRING); - if (password == NULL) { - XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); - FreeDer(&der); - return MEMORY_E; - } - #endif - /* get password */ - ret = info->passwd_cb(password, passwordSz, PEM_PASS_READ, - info->passwd_userdata); - if (ret >= 0) { - passwordSz = ret; - #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("ProcessBuffer password", password, passwordSz); - #endif - - /* PKCS8 decrypt */ - ret = ToTraditionalEnc(der->buffer, der->length, - password, passwordSz, &algId); - if (ret >= 0) { - ForceZero(der->buffer + ret, der->length - ret); - der->length = ret; - } - /* ignore failures and try parsing as unencrypted */ - - ForceZero(password, passwordSz); - } - - #ifdef WOLFSSL_SMALL_STACK - XFREE(password, heap, DYNAMIC_TYPE_STRING); - #elif defined(WOLFSSL_CHECK_MEM_ZERO) - wc_MemZero_Check(password, NAME_SZ); - #endif - ret = ProcessBufferTryDecode(ctx, ssl, der, &keySz, &idx, - &resetSuites, &keyFormat, heap, devId, type); - } - #endif /* WOLFSSL_ENCRYPTED_KEYS && !NO_PWDBASED */ - - if (ret != 0) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); - #endif - return ret; - } - if (keyFormat == 0) { -#ifdef OPENSSL_EXTRA - /* Reaching this point probably means that the - * decryption password is wrong */ - if (info->passwd_cb) - EVPerr(0, EVP_R_BAD_DECRYPT); -#endif - #ifdef WOLFSSL_SMALL_STACK - XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); - #endif - WOLFSSL_ERROR(WOLFSSL_BAD_FILE); - return WOLFSSL_BAD_FILE; - } - - #ifdef WOLFSSL_SMALL_STACK - XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); - #endif - - (void)devId; - } - else if (type == CERT_TYPE) { - #ifdef WOLFSSL_SMALL_STACK - DecodedCert* cert; - #else - DecodedCert cert[1]; - #endif - int keyType = 0; - - #ifdef WOLFSSL_SMALL_STACK - cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), heap, - DYNAMIC_TYPE_DCERT); - if (cert == NULL) - return MEMORY_E; - #endif - - WOLFSSL_MSG("Checking cert signature type"); - InitDecodedCert_ex(cert, der->buffer, der->length, heap, devId); - - if (DecodeToKey(cert, 0) < 0) { - WOLFSSL_MSG("Decode to key failed"); - FreeDecodedCert(cert); - #ifdef WOLFSSL_SMALL_STACK - XFREE(cert, heap, DYNAMIC_TYPE_DCERT); - #endif - return WOLFSSL_BAD_FILE; - } -#if defined(HAVE_RPK) - if (ssl) { - ssl->options.rpkState.isRPKLoaded = 0; - if (cert->isRPK) { - ssl->options.rpkState.isRPKLoaded = 1; - } - } - else if (ctx) { - ctx->rpkState.isRPKLoaded = 0; - if (cert->isRPK) { - ctx->rpkState.isRPKLoaded = 1; - } - } -#endif /* HAVE_RPK */ - - if (ssl) { - if (ssl->options.side == WOLFSSL_SERVER_END) - resetSuites = 1; - } - else if (ctx && ctx->method->side == WOLFSSL_SERVER_END) { - resetSuites = 1; - } - if (ssl && ssl->ctx->haveECDSAsig) { - WOLFSSL_MSG("SSL layer setting cert, CTX had ECDSA, turning off"); - ssl->options.haveECDSAsig = 0; /* may turn back on next */ - } - - switch (cert->signatureOID) { - case CTC_SHAwECDSA: - case CTC_SHA256wECDSA: - case CTC_SHA384wECDSA: - case CTC_SHA512wECDSA: - case CTC_ED25519: - case CTC_ED448: - #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) - case CTC_SM3wSM2: - #endif - WOLFSSL_MSG("ECDSA/ED25519/ED448 cert signature"); - if (ssl) - ssl->options.haveECDSAsig = 1; - else if (ctx) - ctx->haveECDSAsig = 1; - break; - case CTC_FALCON_LEVEL1: - case CTC_FALCON_LEVEL5: - WOLFSSL_MSG("Falcon cert signature"); - if (ssl) - ssl->options.haveFalconSig = 1; - else if (ctx) - ctx->haveFalconSig = 1; - break; - case CTC_DILITHIUM_LEVEL2: - case CTC_DILITHIUM_LEVEL3: - case CTC_DILITHIUM_LEVEL5: - WOLFSSL_MSG("Dilithium cert signature"); - if (ssl) - ssl->options.haveDilithiumSig = 1; - else if (ctx) - ctx->haveDilithiumSig = 1; - break; - default: - WOLFSSL_MSG("Not ECDSA cert signature"); - break; - } - - #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ - (defined(HAVE_PQC) && defined(HAVE_LIBOQS)) || !defined(NO_RSA) - if (ssl) { - #if defined(HAVE_ECC) || defined(HAVE_ED25519) || \ - (defined(HAVE_CURVE448) && defined(HAVE_ED448)) - ssl->pkCurveOID = cert->pkCurveOID; - #endif - #ifndef WC_STRICT_SIG - if (cert->keyOID == ECDSAk) { - ssl->options.haveECC = 1; - } - #ifndef NO_RSA - else if (cert->keyOID == RSAk) { - ssl->options.haveRSA = 1; - } - #ifdef WC_RSA_PSS - else if (cert->keyOID == RSAPSSk) { - ssl->options.haveRSA = 1; - } - #endif - #endif - #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) - else if (cert->keyOID == SM2k) { - ssl->options.haveECC = 1; - } - #endif - #ifdef HAVE_ED25519 - else if (cert->keyOID == ED25519k) { - ssl->options.haveECC = 1; - } - #endif - #ifdef HAVE_ED448 - else if (cert->keyOID == ED448k) { - ssl->options.haveECC = 1; - } - #endif - #ifdef HAVE_PQC - #ifdef HAVE_FALCON - else if (cert->keyOID == FALCON_LEVEL1k || - cert->keyOID == FALCON_LEVEL5k) { - ssl->options.haveFalconSig = 1; - } - #endif /* HAVE_FALCON */ - #ifdef HAVE_DILITHIUM - else if (cert->keyOID == DILITHIUM_LEVEL2k || - cert->keyOID == DILITHIUM_LEVEL3k || - cert->keyOID == DILITHIUM_LEVEL5k) { - ssl->options.haveDilithiumSig = 1; - } - #endif /* HAVE_DILITHIUM */ - #endif /* HAVE_PQC */ - #else - ssl->options.haveECC = ssl->options.haveECDSAsig; - #endif - } - else if (ctx) { - #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) - ctx->pkCurveOID = cert->pkCurveOID; - #endif - #ifndef WC_STRICT_SIG - if (cert->keyOID == ECDSAk) { - ctx->haveECC = 1; - } - #ifndef NO_RSA - else if (cert->keyOID == RSAk) { - ctx->haveRSA = 1; - } - #ifdef WC_RSA_PSS - else if (cert->keyOID == RSAPSSk) { - ctx->haveRSA = 1; - } - #endif - #endif - #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) - else if (cert->keyOID == SM2k) { - ctx->haveECC = 1; - } - #endif - #ifdef HAVE_ED25519 - else if (cert->keyOID == ED25519k) { - ctx->haveECC = 1; - } - #endif - #ifdef HAVE_ED448 - else if (cert->keyOID == ED448k) { - ctx->haveECC = 1; - } - #endif - #ifdef HAVE_PQC - #ifdef HAVE_FALCON - else if (cert->keyOID == FALCON_LEVEL1k || - cert->keyOID == FALCON_LEVEL5k) { - ctx->haveFalconSig = 1; - } - #endif /* HAVE_FALCON */ - #ifdef HAVE_DILITHIUM - else if (cert->keyOID == DILITHIUM_LEVEL2k || - cert->keyOID == DILITHIUM_LEVEL3k || - cert->keyOID == DILITHIUM_LEVEL5k) { - ctx->haveDilithiumSig = 1; - } - #endif /* HAVE_DILITHIUM */ - #endif /* HAVE_PQC */ - #else - ctx->haveECC = ctx->haveECDSAsig; - #endif - } - #endif - - /* check key size of cert unless specified not to */ - switch (cert->keyOID) { - #ifndef NO_RSA - #ifdef WC_RSA_PSS - case RSAPSSk: - #endif - case RSAk: - keyType = rsa_sa_algo; - /* Determine RSA key size by parsing public key */ - idx = 0; - ret = wc_RsaPublicKeyDecode_ex(cert->publicKey, &idx, - cert->pubKeySize, NULL, (word32*)&keySz, NULL, NULL); - if (ret < 0) - break; - - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minRsaKeySz < 0 || - keySz < (int)ssl->options.minRsaKeySz || - keySz > (RSA_MAX_SIZE / 8)) { - ret = RSA_KEY_SIZE_E; - WOLFSSL_MSG("Certificate RSA key size too small"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minRsaKeySz < 0 || - keySz < (int)ctx->minRsaKeySz || - keySz > (RSA_MAX_SIZE / 8)) { - ret = RSA_KEY_SIZE_E; - WOLFSSL_MSG("Certificate RSA key size too small"); - } - } - break; - #endif /* !NO_RSA */ - #ifdef HAVE_ECC - case ECDSAk: - keyType = ecc_dsa_sa_algo; - /* Determine ECC key size based on curve */ - #ifdef WOLFSSL_CUSTOM_CURVES - if (cert->pkCurveOID == 0 && cert->pkCurveSize != 0) { - keySz = cert->pkCurveSize * 8; - } - else - #endif - { - keySz = wc_ecc_get_curve_size_from_id( - wc_ecc_get_oid(cert->pkCurveOID, NULL, NULL)); - } - - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minEccKeySz < 0 || - keySz < (int)ssl->options.minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate ECC key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minEccKeySz < 0 || - keySz < (int)ctx->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate ECC key size error"); - } - } - break; - #endif /* HAVE_ECC */ - #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) - case SM2k: - keyType = sm2_sa_algo; - /* Determine ECC key size based on curve */ - keySz = wc_ecc_get_curve_size_from_id( - wc_ecc_get_oid(cert->pkCurveOID, NULL, NULL)); - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minEccKeySz < 0 || - keySz < (int)ssl->options.minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Ed key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minEccKeySz < 0 || - keySz < (int)ctx->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate ECC key size error"); - } - } - break; - #endif /* HAVE_ED25519 */ - #ifdef HAVE_ED25519 - case ED25519k: - keyType = ed25519_sa_algo; - /* ED25519 is fixed key size */ - keySz = ED25519_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minEccKeySz < 0 || - keySz < (int)ssl->options.minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Ed key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minEccKeySz < 0 || - keySz < (int)ctx->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate ECC key size error"); - } - } - break; - #endif /* HAVE_ED25519 */ - #ifdef HAVE_ED448 - case ED448k: - keyType = ed448_sa_algo; - /* ED448 is fixed key size */ - keySz = ED448_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minEccKeySz < 0 || - keySz < (int)ssl->options.minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Ed key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minEccKeySz < 0 || - keySz < (int)ctx->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate ECC key size error"); - } - } - break; - #endif /* HAVE_ED448 */ - #if defined(HAVE_PQC) - #if defined(HAVE_FALCON) - case FALCON_LEVEL1k: - keyType = falcon_level1_sa_algo; - /* Falcon is fixed key size */ - keySz = FALCON_LEVEL1_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minFalconKeySz < 0 || - keySz < (int)ssl->options.minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Falcon key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minFalconKeySz < 0 || - keySz < (int)ctx->minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Falcon key size error"); - } - } - break; - case FALCON_LEVEL5k: - keyType = falcon_level5_sa_algo; - /* Falcon is fixed key size */ - keySz = FALCON_LEVEL5_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minFalconKeySz < 0 || - keySz < (int)ssl->options.minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Falcon key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minFalconKeySz < 0 || - keySz < (int)ctx->minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Falcon key size error"); - } - } - break; - #endif /* HAVE_FALCON */ - #if defined(HAVE_DILITHIUM) - case DILITHIUM_LEVEL2k: - keyType = dilithium_level2_sa_algo; - /* Dilithium is fixed key size */ - keySz = DILITHIUM_LEVEL2_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minDilithiumKeySz < 0 || - keySz < (int)ssl->options.minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minDilithiumKeySz < 0 || - keySz < (int)ctx->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - break; - case DILITHIUM_LEVEL3k: - keyType = dilithium_level3_sa_algo; - /* Dilithium is fixed key size */ - keySz = DILITHIUM_LEVEL3_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minDilithiumKeySz < 0 || - keySz < (int)ssl->options.minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minDilithiumKeySz < 0 || - keySz < (int)ctx->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - break; - case DILITHIUM_LEVEL5k: - keyType = dilithium_level5_sa_algo; - /* Dilithium is fixed key size */ - keySz = DILITHIUM_LEVEL5_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minDilithiumKeySz < 0 || - keySz < (int)ssl->options.minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minDilithiumKeySz < 0 || - keySz < (int)ctx->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - break; - #endif /* HAVE_DILITHIUM */ - #endif /* HAVE_PQC */ - - default: - WOLFSSL_MSG("No key size check done on certificate"); - break; /* do no check if not a case for the key */ - } - - if (ssl != NULL) { - ssl->buffers.keyType = (byte)keyType; - ssl->buffers.keySz = keySz; - } - else if (ctx != NULL) { - ctx->privateKeyType = (byte)keyType; - ctx->privateKeySz = keySz; - } - - #ifdef WOLFSSL_DUAL_ALG_CERTS - keyType = 0; - keySz = 0; - /* check alternative key size of cert */ - switch (cert->sapkiOID) { - case 0: - if (cert->sapkiLen != 0) - ret = NOT_COMPILED_IN; - break; - #ifndef NO_RSA - #ifdef WC_RSA_PSS - case RSAPSSk: - #endif - case RSAk: - keyType = rsa_sa_algo; - /* Determine RSA key size by parsing public key */ - idx = 0; - ret = wc_RsaPublicKeyDecode_ex(cert->sapkiDer, &idx, - cert->sapkiLen, NULL, (word32*)&keySz, NULL, NULL); - if (ret < 0) - break; - - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minRsaKeySz < 0 || - keySz < (int)ssl->options.minRsaKeySz || - keySz > (RSA_MAX_SIZE / 8)) { - ret = RSA_KEY_SIZE_E; - WOLFSSL_MSG("Certificate RSA key size too small"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minRsaKeySz < 0 || - keySz < (int)ctx->minRsaKeySz || - keySz > (RSA_MAX_SIZE / 8)) { - ret = RSA_KEY_SIZE_E; - WOLFSSL_MSG("Certificate RSA key size too small"); - } - } - break; - #endif /* !NO_RSA */ - #ifdef HAVE_ECC - case ECDSAk: - { - #ifdef WOLFSSL_SMALL_STACK - ecc_key* temp_key = NULL; - #else - ecc_key temp_key[1]; - #endif - keyType = ecc_dsa_sa_algo; - - #ifdef WOLFSSL_SMALL_STACK - temp_key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, - DYNAMIC_TYPE_ECC); - if (temp_key == NULL) - ret = MEMORY_E; - #endif - - /* Determine ECC key size. We have to decode the sapki for - * that. */ - if (ret == 0) { - ret = wc_ecc_init_ex(temp_key, heap, INVALID_DEVID); - } - if (ret == 0) { - idx = 0; - ret = wc_EccPublicKeyDecode(cert->sapkiDer, &idx, temp_key, - cert->sapkiLen); - } - if (ret == 0) { - keySz = wc_ecc_size(temp_key); - } - wc_ecc_free(temp_key); - #ifdef WOLFSSL_SMALL_STACK - XFREE(temp_key, heap, DYNAMIC_TYPE_ECC); - #endif - - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minEccKeySz < 0 || - keySz < (int)ssl->options.minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate ECC key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minEccKeySz < 0 || - keySz < (int)ctx->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate ECC key size error"); - } - } - break; - } - #endif /* HAVE_ECC */ - #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) - case SM2k: - keyType = sm2_sa_algo; - /* Determine ECC key size based on curve */ - keySz = wc_ecc_get_curve_size_from_id( - wc_ecc_get_oid(cert->pkCurveOID, NULL, NULL)); - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minEccKeySz < 0 || - keySz < (int)ssl->options.minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Ed key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minEccKeySz < 0 || - keySz < (int)ctx->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate ECC key size error"); - } - } - break; - #endif /* HAVE_ED25519 */ - #ifdef HAVE_ED25519 - case ED25519k: - keyType = ed25519_sa_algo; - /* ED25519 is fixed key size */ - keySz = ED25519_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minEccKeySz < 0 || - keySz < (int)ssl->options.minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Ed key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minEccKeySz < 0 || - keySz < (int)ctx->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate ECC key size error"); - } - } - break; - #endif /* HAVE_ED25519 */ - #ifdef HAVE_ED448 - case ED448k: - keyType = ed448_sa_algo; - /* ED448 is fixed key size */ - keySz = ED448_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minEccKeySz < 0 || - keySz < (int)ssl->options.minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Ed key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minEccKeySz < 0 || - keySz < (int)ctx->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("Certificate ECC key size error"); - } - } - break; - #endif /* HAVE_ED448 */ - #if defined(HAVE_PQC) - #if defined(HAVE_FALCON) - case FALCON_LEVEL1k: - keyType = falcon_level1_sa_algo; - /* Falcon is fixed key size */ - keySz = FALCON_LEVEL1_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minFalconKeySz < 0 || - keySz < (int)ssl->options.minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Falcon key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minFalconKeySz < 0 || - keySz < (int)ctx->minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Falcon key size error"); - } - } - break; - case FALCON_LEVEL5k: - keyType = falcon_level5_sa_algo; - /* Falcon is fixed key size */ - keySz = FALCON_LEVEL5_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minFalconKeySz < 0 || - keySz < (int)ssl->options.minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Falcon key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minFalconKeySz < 0 || - keySz < (int)ctx->minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Falcon key size error"); - } - } - break; - #endif /* HAVE_FALCON */ - #if defined(HAVE_DILITHIUM) - case DILITHIUM_LEVEL2k: - keyType = dilithium_level2_sa_algo; - /* Dilithium is fixed key size */ - keySz = DILITHIUM_LEVEL2_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minDilithiumKeySz < 0 || - keySz < (int)ssl->options.minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minDilithiumKeySz < 0 || - keySz < (int)ctx->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - break; - case DILITHIUM_LEVEL3k: - keyType = dilithium_level3_sa_algo; - /* Dilithium is fixed key size */ - keySz = DILITHIUM_LEVEL3_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minDilithiumKeySz < 0 || - keySz < (int)ssl->options.minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minDilithiumKeySz < 0 || - keySz < (int)ctx->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - break; - case DILITHIUM_LEVEL5k: - keyType = dilithium_level5_sa_algo; - /* Dilithium is fixed key size */ - keySz = DILITHIUM_LEVEL5_KEY_SIZE; - if (ssl && !ssl->options.verifyNone) { - if (ssl->options.minDilithiumKeySz < 0 || - keySz < (int)ssl->options.minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - else if (ctx && !ctx->verifyNone) { - if (ctx->minDilithiumKeySz < 0 || - keySz < (int)ctx->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("Certificate Dilithium key size error"); - } - } - break; - #endif /* HAVE_DILITHIUM */ - #endif /* HAVE_PQC */ - - default: - /* In this case, there was an OID that we didn't recognize. - * This is an error. Use not compiled in because likely the - * given algorithm was not enabled. */ - ret = NOT_COMPILED_IN; - WOLFSSL_MSG("No alt key size check done on certificate"); - break; - } - - if (ssl != NULL) { - ssl->buffers.altKeyType = (byte)keyType; - ssl->buffers.altKeySz = keySz; - } - else if (ctx != NULL) { - ctx->altPrivateKeyType = (byte)keyType; - ctx->altPrivateKeySz = keySz; - } - #endif /* WOLFSSL_DUAL_ALG_CERTS */ - - FreeDecodedCert(cert); - #ifdef WOLFSSL_SMALL_STACK - XFREE(cert, heap, DYNAMIC_TYPE_DCERT); - #endif - - if (ret != 0) { - done = 1; - } - } - - if (done == 1) { - #if !defined(NO_WOLFSSL_CM_VERIFY) && (!defined(NO_WOLFSSL_CLIENT) || \ - !defined(WOLFSSL_NO_CLIENT_AUTH)) - if ((type == CA_TYPE) || (type == CERT_TYPE)) { - /* Call to over-ride status */ - if ((ctx != NULL) && (ctx->cm != NULL) && - (ctx->cm->verifyCallback != NULL)) { - ret = CM_VerifyBuffer_ex(ctx->cm, buff, - sz, format, (ret == WOLFSSL_SUCCESS ? 0 : ret)); - } - } - #endif /* NO_WOLFSSL_CM_VERIFY */ - - return ret; - } - - - if (ssl && resetSuites) { - word16 havePSK = 0; - word16 haveRSA = 0; - - #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - if (ssl->options.havePSK) { - havePSK = 1; - } - #endif - #ifndef NO_RSA - haveRSA = 1; - #endif - keySz = ssl->buffers.keySz; - - if (AllocateSuites(ssl) != 0) - return WOLFSSL_FAILURE; - /* let's reset suites */ - InitSuites(ssl->suites, ssl->version, keySz, haveRSA, - havePSK, ssl->options.haveDH, ssl->options.haveECDSAsig, - ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, - ssl->options.haveFalconSig, ssl->options.haveDilithiumSig, - ssl->options.useAnon, TRUE, ssl->options.side); - } - else if (ctx && resetSuites) { - word16 havePSK = 0; - word16 haveRSA = 0; - - #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - if (ctx->havePSK) { - havePSK = 1; - } - #endif - #ifndef NO_RSA - haveRSA = 1; - #endif - keySz = ctx->privateKeySz; - - if (AllocateCtxSuites(ctx) != 0) - return WOLFSSL_FAILURE; - /* let's reset suites */ - InitSuites(ctx->suites, ctx->method->version, keySz, haveRSA, - havePSK, ctx->haveDH, ctx->haveECDSAsig, - ctx->haveECC, TRUE, ctx->haveStaticECC, - ctx->haveFalconSig, ctx->haveDilithiumSig, -#ifdef HAVE_ANON - ctx->useAnon, -#else - FALSE, -#endif - TRUE, ctx->method->side); - } - - return WOLFSSL_SUCCESS; -} - - -/* CA PEM file for verification, may have multiple/chain certs to process */ -static int ProcessChainBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, - long sz, int format, int type, WOLFSSL* ssl, int verify) -{ - long used = 0; - int ret = 0; - int gotOne = 0; - - WOLFSSL_MSG("Processing CA PEM file"); - while (used < sz) { - long consumed = 0; - - ret = ProcessBuffer(ctx, buff + used, sz - used, format, type, ssl, - &consumed, 0, verify); - - if (ret == MEMORY_E) { - return ret; - } - else if (ret < 0) { -#if defined(WOLFSSL_WPAS) && defined(HAVE_CRL) - DerBuffer* der = NULL; - EncryptedInfo info; - - WOLFSSL_MSG("Trying a CRL"); - if (PemToDer(buff + used, sz - used, CRL_TYPE, &der, NULL, &info, - NULL) == 0) { - WOLFSSL_MSG(" Processed a CRL"); - wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, der->buffer, - der->length, WOLFSSL_FILETYPE_ASN1); - FreeDer(&der); - used += info.consumed; - continue; - } -#endif - - if (consumed > 0) { /* Made progress in file */ - WOLFSSL_ERROR(ret); - WOLFSSL_MSG("CA Parse failed, with progress in file."); - WOLFSSL_MSG("Search for other certs in file"); - } - else { - WOLFSSL_MSG("CA Parse failed, no progress in file."); - WOLFSSL_MSG("Do not continue search for other certs in file"); - break; - } - } - else { - WOLFSSL_MSG(" Processed a CA"); - gotOne = 1; - } - used += consumed; - } - - if (gotOne) { - WOLFSSL_MSG("Processed at least one valid CA. Other stuff OK"); - return WOLFSSL_SUCCESS; - } - return ret; -} - - #ifdef HAVE_CRL int wolfSSL_CTX_LoadCRLBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, @@ -8612,7 +5875,6 @@ int wolfSSL_SetOCSP_Cb(WOLFSSL* ssl, return BAD_FUNC_ARG; } - int wolfSSL_CTX_EnableOCSP(WOLFSSL_CTX* ctx, int options) { WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSP"); @@ -8691,576 +5953,11 @@ int wolfSSL_CTX_DisableOCSPMustStaple(WOLFSSL_CTX* ctx) else return BAD_FUNC_ARG; } -#endif /* HAVE_CERTIFICATE_STATUS_REQUEST || HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST || \ + * HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ #endif /* HAVE_OCSP */ -/* macro to get verify settings for AddCA */ -#define GET_VERIFY_SETTING_CTX(ctx) \ - ((ctx) && (ctx)->verifyNone ? NO_VERIFY : VERIFY) -#define GET_VERIFY_SETTING_SSL(ssl) \ - ((ssl)->options.verifyNone ? NO_VERIFY : VERIFY) - -#ifndef NO_FILESYSTEM - -/* process a file with name fname into ctx of format and type - userChain specifies a user certificate chain to pass during handshake */ -int ProcessFile(WOLFSSL_CTX* ctx, const char* fname, int format, int type, - WOLFSSL* ssl, int userChain, WOLFSSL_CRL* crl, int verify) -{ -#ifdef WOLFSSL_SMALL_STACK - byte staticBuffer[1]; /* force heap usage */ -#else - byte staticBuffer[FILE_BUFFER_SIZE]; -#endif - byte* myBuffer = staticBuffer; - int dynamic = 0; - int ret; - long sz = 0; - XFILE file; - void* heapHint = wolfSSL_CTX_GetHeap(ctx, ssl); -#ifndef NO_CODING - const char* header = NULL; - const char* footer = NULL; -#endif - - (void)crl; - (void)heapHint; - - if (fname == NULL) return WOLFSSL_BAD_FILE; - - file = XFOPEN(fname, "rb"); - if (file == XBADFILE) return WOLFSSL_BAD_FILE; - if (XFSEEK(file, 0, XSEEK_END) != 0) { - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - sz = XFTELL(file); - if (XFSEEK(file, 0, XSEEK_SET) != 0) { - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - - if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) { - WOLFSSL_MSG("ProcessFile file size error"); - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - - if (sz > (long)sizeof(staticBuffer)) { - WOLFSSL_MSG("Getting dynamic buffer"); - myBuffer = (byte*)XMALLOC(sz, heapHint, DYNAMIC_TYPE_FILE); - if (myBuffer == NULL) { - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - dynamic = 1; - } - - if ((size_t)XFREAD(myBuffer, 1, sz, file) != (size_t)sz) - ret = WOLFSSL_BAD_FILE; - else { - /* Try to detect type by parsing cert header and footer */ - if (type == DETECT_CERT_TYPE) { -#ifndef NO_CODING - if (wc_PemGetHeaderFooter(CA_TYPE, &header, &footer) == 0 && - (XSTRNSTR((char*)myBuffer, header, (int)sz) != NULL)) { - type = CA_TYPE; - } -#ifdef HAVE_CRL - else if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 && - (XSTRNSTR((char*)myBuffer, header, (int)sz) != NULL)) { - type = CRL_TYPE; - } -#endif - else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 && - (XSTRNSTR((char*)myBuffer, header, (int)sz) != NULL)) { - type = CERT_TYPE; - } - else -#endif - { - WOLFSSL_MSG("Failed to detect certificate type"); - if (dynamic) - XFREE(myBuffer, heapHint, DYNAMIC_TYPE_FILE); - XFCLOSE(file); - return WOLFSSL_BAD_CERTTYPE; - } - } - if ((type == CA_TYPE || type == TRUSTED_PEER_TYPE) - && format == WOLFSSL_FILETYPE_PEM) { - ret = ProcessChainBuffer(ctx, myBuffer, sz, format, type, ssl, - verify); - } -#ifdef HAVE_CRL - else if (type == CRL_TYPE) - ret = BufferLoadCRL(crl, myBuffer, sz, format, verify); -#endif -#ifdef WOLFSSL_DUAL_ALG_CERTS - else if (type == PRIVATEKEY_TYPE) - { - /* When support for dual algorithm certificates is enabled, the - * private key file may contain both the primary and the - * alternative private key. Hence, we have to parse both of them. - */ - long consumed = 0; - - ret = ProcessBuffer(ctx, myBuffer, sz, format, PRIVATEKEY_TYPE, - ssl, &consumed, 0, verify); - - if (ret == WOLFSSL_SUCCESS && consumed < sz) { - ret = ProcessBuffer(ctx, myBuffer + consumed, sz - consumed, - format, ALT_PRIVATEKEY_TYPE, ssl, NULL, 0, - verify); - } - } -#endif - else - ret = ProcessBuffer(ctx, myBuffer, sz, format, type, ssl, NULL, - userChain, verify); - } - - XFCLOSE(file); - if (dynamic) - XFREE(myBuffer, heapHint, DYNAMIC_TYPE_FILE); - - return ret; -} - -/* loads file then loads each file in path, no c_rehash */ -int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file, - const char* path, word32 flags) -{ - int ret = WOLFSSL_SUCCESS; -#ifndef NO_WOLFSSL_DIR - int successCount = 0; -#endif - int verify; - - WOLFSSL_MSG("wolfSSL_CTX_load_verify_locations_ex"); - - if (ctx == NULL || (file == NULL && path == NULL)) { - return WOLFSSL_FAILURE; - } - - verify = GET_VERIFY_SETTING_CTX(ctx); - if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) - verify = VERIFY_SKIP_DATE; - - if (file) { - ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0, - NULL, verify); -#ifndef NO_WOLFSSL_DIR - if (ret == WOLFSSL_SUCCESS) - successCount++; -#endif -#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS) - ret = wolfSSL_CTX_trust_peer_cert(ctx, file, WOLFSSL_FILETYPE_PEM); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error"); - } -#endif - } - - if (ret == WOLFSSL_SUCCESS && path) { -#ifndef NO_WOLFSSL_DIR - char* name = NULL; - int fileRet; - int failCount = 0; - #ifdef WOLFSSL_SMALL_STACK - ReadDirCtx* readCtx; - readCtx = (ReadDirCtx*)XMALLOC(sizeof(ReadDirCtx), ctx->heap, - DYNAMIC_TYPE_DIRCTX); - if (readCtx == NULL) - return MEMORY_E; - #else - ReadDirCtx readCtx[1]; - #endif - - /* try to load each regular file in path */ - fileRet = wc_ReadDirFirst(readCtx, path, &name); - while (fileRet == 0 && name) { - WOLFSSL_MSG(name); /* log file name */ - ret = ProcessFile(ctx, name, WOLFSSL_FILETYPE_PEM, CA_TYPE, - NULL, 0, NULL, verify); - if (ret != WOLFSSL_SUCCESS) { - /* handle flags for ignoring errors, skipping expired certs or - by PEM certificate header error */ - if ( (flags & WOLFSSL_LOAD_FLAG_IGNORE_ERR) || - ((flags & WOLFSSL_LOAD_FLAG_PEM_CA_ONLY) && - (ret == ASN_NO_PEM_HEADER))) { - /* Do not fail here if a certificate fails to load, - continue to next file */ - unsigned long err = 0; - CLEAR_ASN_NO_PEM_HEADER_ERROR(err); - #if defined(WOLFSSL_QT) - ret = WOLFSSL_SUCCESS; - #endif - } - else { - WOLFSSL_ERROR(ret); - WOLFSSL_MSG("Load CA file failed, continuing"); - failCount++; - } - } - else { - #if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS) - ret = wolfSSL_CTX_trust_peer_cert(ctx, file, WOLFSSL_FILETYPE_PEM); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error. Ignoring" - "this error."); - } - #endif - successCount++; - } - fileRet = wc_ReadDirNext(readCtx, path, &name); - } - wc_ReadDirClose(readCtx); - - /* pass directory read failure to response code */ - if (fileRet != WC_READDIR_NOFILE) { - ret = fileRet; - #if defined(WOLFSSL_QT) || defined(WOLFSSL_IGNORE_BAD_CERT_PATH) - if (ret == BAD_PATH_ERROR && - flags & WOLFSSL_LOAD_FLAG_IGNORE_BAD_PATH_ERR) { - /* QSslSocket always loads certs in system folder - * when it is initialized. - * Compliant with OpenSSL when flag sets. - */ - ret = WOLFSSL_SUCCESS; - } - else { - /* qssl socket wants to know errors. */ - WOLFSSL_ERROR(ret); - } - #endif - } - /* report failure if no files were loaded or there were failures */ - else if (successCount == 0 || failCount > 0) { - /* use existing error code if exists */ - #if defined(WOLFSSL_QT) - /* compliant with OpenSSL when flag sets*/ - if (!(flags & WOLFSSL_LOAD_FLAG_IGNORE_ZEROFILE)) - #endif - { - ret = WOLFSSL_FAILURE; - } - } - else { - ret = WOLFSSL_SUCCESS; - } - - #ifdef WOLFSSL_SMALL_STACK - XFREE(readCtx, ctx->heap, DYNAMIC_TYPE_DIRCTX); - #endif -#else - ret = NOT_COMPILED_IN; - (void)flags; -#endif - } - - return ret; -} - -WOLFSSL_ABI -int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file, - const char* path) -{ - int ret = wolfSSL_CTX_load_verify_locations_ex(ctx, file, path, - WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); - - return WS_RETURN_CODE(ret,WOLFSSL_FAILURE); -} - -#ifdef WOLFSSL_SYS_CA_CERTS - -#ifdef USE_WINDOWS_API - -static int LoadSystemCaCertsWindows(WOLFSSL_CTX* ctx, byte* loaded) -{ - int ret = WOLFSSL_SUCCESS; - word32 i; - HANDLE handle = NULL; - PCCERT_CONTEXT certCtx = NULL; - LPCSTR storeNames[2] = {"ROOT", "CA"}; - HCRYPTPROV_LEGACY hProv = (HCRYPTPROV_LEGACY)NULL; - - if (ctx == NULL || loaded == NULL) { - ret = WOLFSSL_FAILURE; - } - - for (i = 0; ret == WOLFSSL_SUCCESS && - i < sizeof(storeNames)/sizeof(*storeNames); ++i) { - handle = CertOpenSystemStoreA(hProv, storeNames[i]); - if (handle != NULL) { - while ((certCtx = CertEnumCertificatesInStore(handle, certCtx)) - != NULL) { - if (certCtx->dwCertEncodingType == X509_ASN_ENCODING) { - if (ProcessBuffer(ctx, certCtx->pbCertEncoded, - certCtx->cbCertEncoded, WOLFSSL_FILETYPE_ASN1, - CA_TYPE, NULL, NULL, 0, - GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { - /* - * Set "loaded" as long as we've loaded one CA - * cert. - */ - *loaded = 1; - } - } - } - } - else { - WOLFSSL_MSG_EX("Failed to open cert store %s.", storeNames[i]); - } - - if (handle != NULL && !CertCloseStore(handle, 0)) { - WOLFSSL_MSG_EX("Failed to close cert store %s.", storeNames[i]); - ret = WOLFSSL_FAILURE; - } - } - - return ret; -} - -#elif defined(__APPLE__) - -#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) \ - && !defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION) -/* - * Manually obtains certificates from the system trust store and loads them - * directly into wolfSSL "the old way". - * - * As of MacOS 14.0 we are still able to use this method to access system - * certificates. Accessibility of this API is indicated by the presence of the - * Security/SecTrustSettings.h header. In the likely event that Apple removes - * access to this API on Macs, this function should be removed and the - * DoAppleNativeCertValidation() routine should be used for all devices. - */ -static int LoadSystemCaCertsMac(WOLFSSL_CTX* ctx, byte* loaded) -{ - int ret = WOLFSSL_SUCCESS; - word32 i; - const unsigned int trustDomains[] = { - kSecTrustSettingsDomainUser, - kSecTrustSettingsDomainAdmin, - kSecTrustSettingsDomainSystem - }; - CFArrayRef certs; - OSStatus stat; - CFIndex numCerts; - CFDataRef der; - CFIndex j; - - if (ctx == NULL || loaded == NULL) { - ret = WOLFSSL_FAILURE; - } - - for (i = 0; ret == WOLFSSL_SUCCESS && - i < sizeof(trustDomains)/sizeof(*trustDomains); ++i) { - stat = SecTrustSettingsCopyCertificates( - (SecTrustSettingsDomain)trustDomains[i], &certs); - if (stat == errSecSuccess) { - numCerts = CFArrayGetCount(certs); - for (j = 0; j < numCerts; ++j) { - der = SecCertificateCopyData((SecCertificateRef) - CFArrayGetValueAtIndex(certs, j)); - if (der != NULL) { - if (ProcessBuffer(ctx, CFDataGetBytePtr(der), - CFDataGetLength(der), WOLFSSL_FILETYPE_ASN1, - CA_TYPE, NULL, NULL, 0, - GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { - /* - * Set "loaded" as long as we've loaded one CA - * cert. - */ - *loaded = 1; - } - - CFRelease(der); - } - } - - CFRelease(certs); - } - else if (stat == errSecNoTrustSettings) { - WOLFSSL_MSG_EX("No trust settings for domain %d, moving to next " - "domain.", trustDomains[i]); - } - else { - WOLFSSL_MSG_EX("SecTrustSettingsCopyCertificates failed with" - " status %d.", stat); - ret = WOLFSSL_FAILURE; - break; - } - } - - return ret; -} -#endif /* defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) */ - -#else - -/* Potential system CA certs directories on Linux/Unix distros. */ -static const char* systemCaDirs[] = { -#if defined(__ANDROID__) || defined(ANDROID) - "/system/etc/security/cacerts" /* Android */ -#else - "/etc/ssl/certs", /* Debian, Ubuntu, Gentoo, others */ - "/etc/pki/ca-trust/source/anchors", /* Fedora, RHEL */ - "/etc/pki/tls/certs" /* Older RHEL */ -#endif -}; - -const char** wolfSSL_get_system_CA_dirs(word32* num) -{ - const char** ret; - - if (num == NULL) { - ret = NULL; - } - else { - ret = systemCaDirs; - *num = sizeof(systemCaDirs)/sizeof(*systemCaDirs); - } - - return ret; -} - -static int LoadSystemCaCertsNix(WOLFSSL_CTX* ctx, byte* loaded) { - int ret = WOLFSSL_SUCCESS; - word32 i; - - if (ctx == NULL || loaded == NULL) { - ret = WOLFSSL_FAILURE; - } - - for (i = 0; ret == WOLFSSL_SUCCESS && - i < sizeof(systemCaDirs)/sizeof(*systemCaDirs); ++i) { - WOLFSSL_MSG_EX("Attempting to load system CA certs from %s.", - systemCaDirs[i]); - /* - * We want to keep trying to load more CAs even if one cert in - * the directory is bad and can't be used (e.g. if one is expired), - * so we use WOLFSSL_LOAD_FLAG_IGNORE_ERR. - */ - if (wolfSSL_CTX_load_verify_locations_ex(ctx, NULL, systemCaDirs[i], - WOLFSSL_LOAD_FLAG_IGNORE_ERR) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG_EX("Failed to load CA certs from %s, trying " - "next possible location.", systemCaDirs[i]); - } - else { - WOLFSSL_MSG_EX("Loaded CA certs from %s.", - systemCaDirs[i]); - *loaded = 1; - /* Stop searching after we've loaded one directory. */ - break; - } - } - - return ret; -} - -#endif - -int wolfSSL_CTX_load_system_CA_certs(WOLFSSL_CTX* ctx) -{ - int ret; - byte loaded = 0; - - WOLFSSL_ENTER("wolfSSL_CTX_load_system_CA_certs"); - -#ifdef USE_WINDOWS_API - - ret = LoadSystemCaCertsWindows(ctx, &loaded); - -#elif defined(__APPLE__) - -#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) \ - && !defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION) - /* As of MacOS 14.0 we are still able to access system certificates and - * load them manually into wolfSSL "the old way". Accessibility of this API - * is indicated by the presence of the Security/SecTrustSettings.h header */ - ret = LoadSystemCaCertsMac(ctx, &loaded); -#elif defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION) - /* For other Apple devices, Apple has removed the ability to obtain - * certificates from the trust store, so we can't use wolfSSL's built-in - * certificate validation mechanisms anymore. We instead must call into the - * Security Framework APIs to authenticate peer certificates when received. - * (see src/internal.c:DoAppleNativeCertValidation()). - * Thus, there is no CA "loading" required, but to keep behavior consistent - * with the current API (not using system CA certs unless this function has - * been called), we simply set a flag indicating that the new apple trust - * verification routine should be used later */ - ctx->doAppleNativeCertValidationFlag = 1; - ret = WOLFSSL_SUCCESS; - loaded = 1; - -#if FIPS_VERSION_GE(2,0) /* Gate back to cert 3389 FIPS modules */ -#warning "Cryptographic operations may occur outside the FIPS module boundary" \ - "Please review FIPS claims for cryptography on this Apple device" -#endif /* FIPS_VERSION_GE(2,0) */ - -#else -/* HAVE_SECURITY_SECXXX_H macros are set by autotools or CMake when searching - * system for the required SDK headers. If building with user_settings.h, you - * will need to manually define WOLFSSL_APPLE_NATIVE_CERT_VALIDATION - * and ensure the appropriate Security.framework headers and libraries are - * visible to your compiler */ -#error "WOLFSSL_SYS_CA_CERTS on Apple devices requires Security.framework" \ - " header files to be detected, or a manual override with" \ - " WOLFSSL_APPLE_NATIVE_CERT_VALIDATION" -#endif - -#else - - ret = LoadSystemCaCertsNix(ctx, &loaded); - -#endif - - if (ret == WOLFSSL_SUCCESS && !loaded) { - ret = WOLFSSL_BAD_PATH; - } - - WOLFSSL_LEAVE("wolfSSL_CTX_load_system_CA_certs", ret); - - return ret; -} - -#endif /* WOLFSSL_SYS_CA_CERTS */ - -#ifdef WOLFSSL_TRUST_PEER_CERT -/* Used to specify a peer cert to match when connecting - ctx : the ctx structure to load in peer cert - file: the string name of cert file - type: type of format such as PEM/DER - */ -int wolfSSL_CTX_trust_peer_cert(WOLFSSL_CTX* ctx, const char* file, int type) -{ - WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_cert"); - - if (ctx == NULL || file == NULL) { - return WOLFSSL_FAILURE; - } - - return ProcessFile(ctx, file, type, TRUSTED_PEER_TYPE, NULL, 0, NULL, - GET_VERIFY_SETTING_CTX(ctx)); -} - -int wolfSSL_trust_peer_cert(WOLFSSL* ssl, const char* file, int type) -{ - WOLFSSL_ENTER("wolfSSL_trust_peer_cert"); - - if (ssl == NULL || file == NULL) { - return WOLFSSL_FAILURE; - } - - return ProcessFile(NULL, file, type, TRUSTED_PEER_TYPE, ssl, 0, NULL, - GET_VERIFY_SETTING_SSL(ssl)); -} -#endif /* WOLFSSL_TRUST_PEER_CERT */ - -#endif /* NO_FILESYSTEM */ - #ifdef HAVE_CRL int wolfSSL_EnableCRL(WOLFSSL* ssl, int options) @@ -9310,7 +6007,6 @@ int wolfSSL_LoadCRLFile(WOLFSSL* ssl, const char* file, int type) } #endif - int wolfSSL_SetCRL_Cb(WOLFSSL* ssl, CbMissingCRL cb) { WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); @@ -9402,77 +6098,6 @@ int wolfSSL_CTX_SetCRL_IOCb(WOLFSSL_CTX* ctx, CbCrlIO cb) #endif /* HAVE_CRL */ -#ifndef NO_FILESYSTEM - - -#ifdef WOLFSSL_DER_LOAD - -/* Add format parameter to allow DER load of CA files */ -int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file, - int format) -{ - WOLFSSL_ENTER("wolfSSL_CTX_der_load_verify_locations"); - if (ctx == NULL || file == NULL) - return WOLFSSL_FAILURE; - - if (ProcessFile(ctx, file, format, CA_TYPE, NULL, 0, NULL, - GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - - return WOLFSSL_FAILURE; -} - -#endif /* WOLFSSL_DER_LOAD */ - - - -WOLFSSL_ABI -int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file, - int format) -{ - WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_file"); - - if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 0, NULL, - GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - - return WOLFSSL_FAILURE; -} - - -WOLFSSL_ABI -int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX* ctx, const char* file, - int format) -{ - WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_file"); - - if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE, NULL, 0, NULL, - GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - - return WOLFSSL_FAILURE; -} - -#ifdef WOLFSSL_DUAL_ALG_CERTS -int wolfSSL_CTX_use_AltPrivateKey_file(WOLFSSL_CTX* ctx, const char* file, - int format) -{ - WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_file"); - - if (ProcessFile(ctx, file, format, ALT_PRIVATEKEY_TYPE, NULL, 0, NULL, - GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - - return WOLFSSL_FAILURE; -} -#endif /* WOLFSSL_DUAL_ALG_CERTS */ -#endif /* NO_FILESYSTEM */ - - /* Sets the max chain depth when verifying a certificate chain. Default depth * is set to MAX_CHAIN_DEPTH. * @@ -9518,124 +6143,6 @@ long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx) #endif } - -#ifndef NO_FILESYSTEM - - -WOLFSSL_ABI -int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file) -{ - /* process up to MAX_CHAIN_DEPTH plus subject cert */ - WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file"); - - if (ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL, - GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - - return WOLFSSL_FAILURE; -} - - -int wolfSSL_CTX_use_certificate_chain_file_format(WOLFSSL_CTX* ctx, - const char* file, int format) -{ - /* process up to MAX_CHAIN_DEPTH plus subject cert */ - WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file_format"); - - if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 1, NULL, - GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - - return WOLFSSL_FAILURE; -} - - -#ifndef NO_DH - -/* server Diffie-Hellman parameters */ -static int wolfSSL_SetTmpDH_file_wrapper(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - const char* fname, int format) -{ -#ifdef WOLFSSL_SMALL_STACK - byte staticBuffer[1]; /* force heap usage */ -#else - byte staticBuffer[FILE_BUFFER_SIZE]; -#endif - byte* myBuffer = staticBuffer; - int dynamic = 0; - int ret; - long sz = 0; - XFILE file; - - if (ctx == NULL || fname == NULL) - return BAD_FUNC_ARG; - - file = XFOPEN(fname, "rb"); - if (file == XBADFILE) return WOLFSSL_BAD_FILE; - if(XFSEEK(file, 0, XSEEK_END) != 0) { - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - sz = XFTELL(file); - if(XFSEEK(file, 0, XSEEK_SET) != 0) { - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - - if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) { - WOLFSSL_MSG("SetTmpDH file size error"); - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - - if (sz > (long)sizeof(staticBuffer)) { - WOLFSSL_MSG("Getting dynamic buffer"); - myBuffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE); - if (myBuffer == NULL) { - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - dynamic = 1; - } - - if ((size_t)XFREAD(myBuffer, 1, sz, file) != (size_t)sz) - ret = WOLFSSL_BAD_FILE; - else { - if (ssl) - ret = wolfSSL_SetTmpDH_buffer(ssl, myBuffer, sz, format); - else - ret = wolfSSL_CTX_SetTmpDH_buffer(ctx, myBuffer, sz, format); - } - - XFCLOSE(file); - if (dynamic) - XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE); - - return ret; -} - -/* server Diffie-Hellman parameters */ -int wolfSSL_SetTmpDH_file(WOLFSSL* ssl, const char* fname, int format) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return wolfSSL_SetTmpDH_file_wrapper(ssl->ctx, ssl, fname, format); -} - - -/* server Diffie-Hellman parameters */ -int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format) -{ - return wolfSSL_SetTmpDH_file_wrapper(ctx, NULL, fname, format); -} - -#endif /* NO_DH */ - -#endif /* NO_FILESYSTEM */ - #ifndef NO_CHECK_PRIVATE_KEY #ifdef WOLF_PRIVATE_KEY_ID @@ -9977,13 +6484,615 @@ WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(const WOLFSSL_CTX* ctx) #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +#if !defined(NO_RSA) +static int d2iTryRsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_EVP_PKEY* pkey; + word32 keyIdx = 0; + int isRsaKey; + int ret = 1; +#ifndef WOLFSSL_SMALL_STACK + RsaKey rsa[1]; +#else + RsaKey *rsa = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); + if (rsa == NULL) + return 0; +#endif + + XMEMSET(rsa, 0, sizeof(RsaKey)); + + if (wc_InitRsaKey(rsa, NULL) != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(rsa, NULL, DYNAMIC_TYPE_RSA); + #endif + return 0; + } + /* test if RSA key */ + if (priv) { + isRsaKey = + (wc_RsaPrivateKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0); + } + else { + isRsaKey = + (wc_RsaPublicKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0); + } + wc_FreeRsaKey(rsa); +#ifdef WOLFSSL_SMALL_STACK + XFREE(rsa, NULL, DYNAMIC_TYPE_RSA); +#endif + + if (!isRsaKey) { + return -1; + } + + if (*out != NULL) { + pkey = *out; + } + else { + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + WOLFSSL_MSG("RSA wolfSSL_EVP_PKEY_new error"); + return 0; + } + } + + pkey->pkey_sz = keyIdx; + pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, + priv ? DYNAMIC_TYPE_PRIVATE_KEY : + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + ret = 0; + } + if (ret == 1) { + XMEMCPY(pkey->pkey.ptr, mem, keyIdx); + pkey->type = EVP_PKEY_RSA; + + pkey->ownRsa = 1; + pkey->rsa = wolfssl_rsa_d2i(NULL, mem, memSz, + priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC); + if (pkey->rsa == NULL) { + ret = 0; + } + } + + if (ret == 1) { + *out = pkey; + } + + if ((ret == 0) && (*out == NULL)) { + wolfSSL_EVP_PKEY_free(pkey); + } + return ret; +} +#endif /* !NO_RSA */ + +#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) +static int d2iTryEccKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_EVP_PKEY* pkey; + word32 keyIdx = 0; + int isEccKey; + int ret = 1; +#ifndef WOLFSSL_SMALL_STACK + ecc_key ecc[1]; +#else + ecc_key *ecc = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, + DYNAMIC_TYPE_ECC); + if (ecc == NULL) + return 0; +#endif + + XMEMSET(ecc, 0, sizeof(ecc_key)); + + if (wc_ecc_init(ecc) != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(ecc, NULL, DYNAMIC_TYPE_ECC); + #endif + return 0; + } + + if (priv) { + isEccKey = + (wc_EccPrivateKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0); + } + else { + isEccKey = + (wc_EccPublicKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0); + } + wc_ecc_free(ecc); +#ifdef WOLFSSL_SMALL_STACK + XFREE(ecc, NULL, DYNAMIC_TYPE_ECC); +#endif + + if (!isEccKey) { + return -1; + } + + if (*out != NULL) { + pkey = *out; + } + else { + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + WOLFSSL_MSG("ECC wolfSSL_EVP_PKEY_new error"); + return 0; + } + } + + pkey->pkey_sz = keyIdx; + pkey->pkey.ptr = (char*)XMALLOC(keyIdx, NULL, + priv ? DYNAMIC_TYPE_PRIVATE_KEY : + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + ret = 0; + } + if (ret == 1) { + XMEMCPY(pkey->pkey.ptr, mem, keyIdx); + pkey->type = EVP_PKEY_EC; + + pkey->ownEcc = 1; + pkey->ecc = wolfSSL_EC_KEY_new(); + if (pkey->ecc == NULL) { + ret = 0; + } + } + if ((ret == 1) && (wolfSSL_EC_KEY_LoadDer_ex(pkey->ecc, + (const unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz, priv ? WOLFSSL_RSA_LOAD_PRIVATE + : WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { + ret = 0; + } + if (ret == 1) { + *out = pkey; + } + + if ((ret == 0) && (*out == NULL)) { + wolfSSL_EVP_PKEY_free(pkey); + } + return ret; +} +#endif /* HAVE_ECC && OPENSSL_EXTRA */ + +#if !defined(NO_DSA) +static int d2iTryDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_EVP_PKEY* pkey; + word32 keyIdx = 0; + int isDsaKey; + int ret = 1; +#ifndef WOLFSSL_SMALL_STACK + DsaKey dsa[1]; +#else + DsaKey *dsa = (DsaKey*)XMALLOC(sizeof(DsaKey), NULL, DYNAMIC_TYPE_DSA); + if (dsa == NULL) + return 0; +#endif + + XMEMSET(dsa, 0, sizeof(DsaKey)); + + if (wc_InitDsaKey(dsa) != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(dsa, NULL, DYNAMIC_TYPE_DSA); + #endif + return 0; + } + + if (priv) { + isDsaKey = + (wc_DsaPrivateKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0); + } + else { + isDsaKey = + (wc_DsaPublicKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0); + } + wc_FreeDsaKey(dsa); +#ifdef WOLFSSL_SMALL_STACK + XFREE(dsa, NULL, DYNAMIC_TYPE_DSA); +#endif + + /* test if DSA key */ + if (!isDsaKey) { + return -1; + } + + if (*out != NULL) { + pkey = *out; + } + else { + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + WOLFSSL_MSG("DSA wolfSSL_EVP_PKEY_new error"); + return 0; + } + } + + pkey->pkey_sz = keyIdx; + pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, + priv ? DYNAMIC_TYPE_PRIVATE_KEY : + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + ret = 0; + } + if (ret == 1) { + XMEMCPY(pkey->pkey.ptr, mem, keyIdx); + pkey->type = EVP_PKEY_DSA; + + pkey->ownDsa = 1; + pkey->dsa = wolfSSL_DSA_new(); + if (pkey->dsa == NULL) { + ret = 0; + } + } + + if ((ret == 1) && (wolfSSL_DSA_LoadDer_ex(pkey->dsa, + (const unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz, priv ? WOLFSSL_RSA_LOAD_PRIVATE + : WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { + ret = 0; + } + if (ret == 1) { + *out = pkey; + } + + if ((ret == 0) && (*out == NULL)) { + wolfSSL_EVP_PKEY_free(pkey); + } + return ret; +} +#endif /* NO_DSA */ + +#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION > 2)) +static int d2iTryDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_EVP_PKEY* pkey; + int isDhKey; + word32 keyIdx = 0; + int ret = 1; +#ifndef WOLFSSL_SMALL_STACK + DhKey dh[1]; +#else + DhKey *dh = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); + if (dh == NULL) + return 0; +#endif + + XMEMSET(dh, 0, sizeof(DhKey)); + + if (wc_InitDhKey(dh) != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(dh, NULL, DYNAMIC_TYPE_DH); + #endif + return 0; + } + + isDhKey = (wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz) == 0); + wc_FreeDhKey(dh); +#ifdef WOLFSSL_SMALL_STACK + XFREE(dh, NULL, DYNAMIC_TYPE_DH); +#endif + + /* test if DH key */ + if (!isDhKey) { + return -1; + } + + if (*out != NULL) { + pkey = *out; + } + else { + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + WOLFSSL_MSG("DH wolfSSL_EVP_PKEY_new error"); + return 0; + } + } + + pkey->pkey_sz = (int)memSz; + pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, + priv ? DYNAMIC_TYPE_PRIVATE_KEY : + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + ret = 0; + } + if (ret == 1) { + XMEMCPY(pkey->pkey.ptr, mem, memSz); + pkey->type = EVP_PKEY_DH; + + pkey->ownDh = 1; + pkey->dh = wolfSSL_DH_new(); + if (pkey->dh == NULL) { + ret = 0; + } + } + + if ((ret == 1) && (wolfSSL_DH_LoadDer(pkey->dh, + (const unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz) != WOLFSSL_SUCCESS)) { + ret = 0; + } + if (ret == 1) { + *out = pkey; + } + + if ((ret == 0) && (*out == NULL)) { + wolfSSL_EVP_PKEY_free(pkey); + } + return ret; +} +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ + +#if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION > 2)) +static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_EVP_PKEY* pkey; + word32 keyIdx = 0; + DhKey* key = NULL; + int elements; + int ret; +#ifndef WOLFSSL_SMALL_STACK + DhKey dh[1]; +#else + DhKey* dh = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); + if (dh == NULL) + return 0; +#endif + XMEMSET(dh, 0, sizeof(DhKey)); + + /* test if DH-public key */ + if (wc_InitDhKey(dh) != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(dh, NULL, DYNAMIC_TYPE_DH); +#endif + return 0; + } + + ret = wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz); + wc_FreeDhKey(dh); +#ifdef WOLFSSL_SMALL_STACK + XFREE(dh, NULL, DYNAMIC_TYPE_DH); +#endif + + if (ret != 0) { + return -1; + } + + if (*out != NULL) { + pkey = *out; + } + else { + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + return 0; + } + } + + ret = 1; + pkey->type = EVP_PKEY_DH; + pkey->pkey_sz = (int)memSz; + pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, + priv ? DYNAMIC_TYPE_PRIVATE_KEY : + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + ret = 0; + } + if (ret == 1) { + XMEMCPY(pkey->pkey.ptr, mem, memSz); + pkey->ownDh = 1; + pkey->dh = wolfSSL_DH_new(); + if (pkey->dh == NULL) { + ret = 0; + } + } + + if (ret == 1) { + key = (DhKey*)pkey->dh->internal; + + keyIdx = 0; + if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) != 0) { + ret = 0; + } + } + + if (ret == 1) { + elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; + if (priv) { + elements |= ELEMENT_PRV; + } + if (SetDhExternal_ex(pkey->dh, elements) != WOLFSSL_SUCCESS ) { + ret = 0; + } + } + if (ret == 1) { + *out = pkey; + } + + if ((ret == 0) && (*out == NULL)) { + wolfSSL_EVP_PKEY_free(pkey); + } + return ret; +} +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ + +#ifdef HAVE_PQC +#ifdef HAVE_FALCON +static int d2iTryFalconKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_EVP_PKEY* pkey; + int isFalcon = 0; +#ifndef WOLFSSL_SMALL_STACK + falcon_key falcon[1]; +#else + falcon_key *falcon = (falcon_key *)XMALLOC(sizeof(falcon_key), NULL, + DYNAMIC_TYPE_FALCON); + if (falcon == NULL) { + return 0; + } +#endif + + if (wc_falcon_init(falcon) != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(falcon, NULL, DYNAMIC_TYPE_FALCON); + #endif + return 0; + } + + /* test if Falcon key */ + if (priv) { + /* Try level 1 */ + isFalcon = ((wc_falcon_set_level(falcon, 1) == 0) && + (wc_falcon_import_private_only(mem, (word32)memSz, + falcon) == 0)); + if (!isFalcon) { + /* Try level 5 */ + isFalcon = ((wc_falcon_set_level(falcon, 5) == 0) && + (wc_falcon_import_private_only(mem, (word32)memSz, + falcon) == 0)); + } + } + else { + /* Try level 1 */ + isFalcon = ((wc_falcon_set_level(falcon, 1) == 0) && + (wc_falcon_import_public(mem, (word32)memSz, falcon) == 0)); + + if (!isFalcon) { + /* Try level 5 */ + isFalcon = ((wc_falcon_set_level(falcon, 5) == 0) && + (wc_falcon_import_public(mem, (word32)memSz, + falcon) == 0)); + } + } + wc_falcon_free(falcon); +#ifdef WOLFSSL_SMALL_STACK + XFREE(falcon, NULL, DYNAMIC_TYPE_FALCON); +#endif + + if (!isFalcon) { + return -1; + } + + if (*out != NULL) { + pkey = *out; + } + else { + /* Create a fake Falcon EVP_PKEY. In the future, we might integrate + * Falcon into the compatibility layer. */ + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + WOLFSSL_MSG("Falcon wolfSSL_EVP_PKEY_new error"); + return 0; + } + } + pkey->type = EVP_PKEY_FALCON; + pkey->pkey.ptr = NULL; + pkey->pkey_sz = 0; + + *out = pkey; + return 1; + +} +#endif /* HAVE_FALCON */ + +#ifdef HAVE_DILITHIUM +static int d2iTryDilithiumKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_EVP_PKEY* pkey; + int isDilithium = 0; +#ifndef WOLFSSL_SMALL_STACK + dilithium_key dilithium[1]; +#else + dilithium_key *dilithium = (dilithium_key *) + XMALLOC(sizeof(dilithium_key), NULL, DYNAMIC_TYPE_DILITHIUM); + if (dilithium == NULL) { + return 0; + } +#endif + + if (wc_dilithium_init(dilithium) != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); + #endif + return 0; + } + + /* Test if Dilithium key. Try all levels. */ + if (priv) { + isDilithium = ((wc_dilithium_set_level(dilithium, 2) == 0) && + (wc_dilithium_import_private_only(mem, + (word32)memSz, dilithium) == 0)); + if (!isDilithium) { + isDilithium = ((wc_dilithium_set_level(dilithium, 3) == 0) && + (wc_dilithium_import_private_only(mem, + (word32)memSz, dilithium) == 0)); + } + if (!isDilithium) { + isDilithium = ((wc_dilithium_set_level(dilithium, 5) == 0) && + (wc_dilithium_import_private_only(mem, + (word32)memSz, dilithium) == 0)); + } + } + else { + isDilithium = ((wc_dilithium_set_level(dilithium, 2) == 0) && + (wc_dilithium_import_public(mem, (word32)memSz, + dilithium) == 0)); + if (!isDilithium) { + isDilithium = ((wc_dilithium_set_level(dilithium, 3) == 0) && + (wc_dilithium_import_public(mem, (word32)memSz, + dilithium) == 0)); + } + if (!isDilithium) { + isDilithium = ((wc_dilithium_set_level(dilithium, 5) == 0) && + (wc_dilithium_import_public(mem, (word32)memSz, + dilithium) == 0)); + } + } + wc_dilithium_free(dilithium); +#ifdef WOLFSSL_SMALL_STACK + XFREE(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); +#endif + + if (!isDilithium) { + return -1; + } + + if (*out != NULL) { + pkey = *out; + } + else { + /* Create a fake Dilithium EVP_PKEY. In the future, we might + * integrate Dilithium into the compatibility layer. */ + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + WOLFSSL_MSG("Dilithium wolfSSL_EVP_PKEY_new error"); + return 0; + } + } + pkey->type = EVP_PKEY_DILITHIUM; + pkey->pkey.ptr = NULL; + pkey->pkey_sz = 0; + + *out = pkey; + return 1; +} +#endif /* HAVE_DILITHIUM */ +#endif /* HAVE_PQC */ + static WOLFSSL_EVP_PKEY* d2iGenericKey(WOLFSSL_EVP_PKEY** out, const unsigned char** in, long inSz, int priv) { - WOLFSSL_EVP_PKEY* pkey = NULL; - const unsigned char* mem; - long memSz = inSz; WOLFSSL_ENTER("d2iGenericKey"); @@ -9991,480 +7100,79 @@ static WOLFSSL_EVP_PKEY* d2iGenericKey(WOLFSSL_EVP_PKEY** out, WOLFSSL_MSG("Bad argument"); return NULL; } - mem = *in; - #if !defined(NO_RSA) - { - word32 keyIdx = 0; - int isRsaKey; - #ifdef WOLFSSL_SMALL_STACK - RsaKey *rsa = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); - if (rsa == NULL) - return NULL; - #else - RsaKey rsa[1]; - #endif - XMEMSET(rsa, 0, sizeof(RsaKey)); - - /* test if RSA key */ - if (priv) - isRsaKey = wc_InitRsaKey(rsa, NULL) == 0 && - wc_RsaPrivateKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0; - else - isRsaKey = wc_InitRsaKey(rsa, NULL) == 0 && - wc_RsaPublicKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0; - wc_FreeRsaKey(rsa); - #ifdef WOLFSSL_SMALL_STACK - XFREE(rsa, NULL, DYNAMIC_TYPE_RSA); - #endif - - if (isRsaKey) { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey != NULL) { - pkey->pkey_sz = keyIdx; - pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, - priv ? DYNAMIC_TYPE_PRIVATE_KEY : - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkey->pkey.ptr == NULL) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - XMEMCPY(pkey->pkey.ptr, mem, keyIdx); - pkey->type = EVP_PKEY_RSA; - if (out != NULL) { - *out = pkey; - } - - pkey->ownRsa = 1; - pkey->rsa = wolfssl_rsa_d2i(NULL, mem, inSz, - priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC); - if (pkey->rsa == NULL) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - - return pkey; - } - else { - WOLFSSL_MSG("RSA wolfSSL_EVP_PKEY_new error"); - } - } + if ((out != NULL) && (*out != NULL)) { + pkey = *out; } - #endif /* NO_RSA */ - #if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) - { - word32 keyIdx = 0; - int isEccKey; - #ifdef WOLFSSL_SMALL_STACK - ecc_key *ecc = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, DYNAMIC_TYPE_ECC); - if (ecc == NULL) - return NULL; - #else - ecc_key ecc[1]; - #endif - XMEMSET(ecc, 0, sizeof(ecc_key)); - - if (priv) - isEccKey = wc_ecc_init(ecc) == 0 && - wc_EccPrivateKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0; - else - isEccKey = wc_ecc_init(ecc) == 0 && - wc_EccPublicKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0; - wc_ecc_free(ecc); - #ifdef WOLFSSL_SMALL_STACK - XFREE(ecc, NULL, DYNAMIC_TYPE_ECC); - #endif - - if (isEccKey) { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey != NULL) { - pkey->pkey_sz = keyIdx; - pkey->pkey.ptr = (char*)XMALLOC(keyIdx, NULL, - priv ? DYNAMIC_TYPE_PRIVATE_KEY : - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkey->pkey.ptr == NULL) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - XMEMCPY(pkey->pkey.ptr, mem, keyIdx); - pkey->type = EVP_PKEY_EC; - if (out != NULL) { - *out = pkey; - } - - pkey->ownEcc = 1; - pkey->ecc = wolfSSL_EC_KEY_new(); - if (pkey->ecc == NULL) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - - if (wolfSSL_EC_KEY_LoadDer_ex(pkey->ecc, - (const unsigned char*)pkey->pkey.ptr, - pkey->pkey_sz, priv ? WOLFSSL_RSA_LOAD_PRIVATE - : WOLFSSL_RSA_LOAD_PUBLIC) != 1) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - - return pkey; - } - else { - WOLFSSL_MSG("ECC wolfSSL_EVP_PKEY_new error"); - } - } +#if !defined(NO_RSA) + if (d2iTryRsaKey(&pkey, *in, inSz, priv) >= 0) { + ; } - #endif /* HAVE_ECC && OPENSSL_EXTRA */ - - #if !defined(NO_DSA) - { - word32 keyIdx = 0; - int isDsaKey; - #ifdef WOLFSSL_SMALL_STACK - DsaKey *dsa = (DsaKey*)XMALLOC(sizeof(DsaKey), NULL, DYNAMIC_TYPE_DSA); - if (dsa == NULL) - return NULL; - #else - DsaKey dsa[1]; - #endif - XMEMSET(dsa, 0, sizeof(DsaKey)); - - if (priv) - isDsaKey = wc_InitDsaKey(dsa) == 0 && - wc_DsaPrivateKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0; - else - isDsaKey = wc_InitDsaKey(dsa) == 0 && - wc_DsaPublicKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0; - wc_FreeDsaKey(dsa); - #ifdef WOLFSSL_SMALL_STACK - XFREE(dsa, NULL, DYNAMIC_TYPE_DSA); - #endif - - /* test if DSA key */ - if (isDsaKey) { - pkey = wolfSSL_EVP_PKEY_new(); - - if (pkey != NULL) { - pkey->pkey_sz = keyIdx; - pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, - priv ? DYNAMIC_TYPE_PRIVATE_KEY : - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkey->pkey.ptr == NULL) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - XMEMCPY(pkey->pkey.ptr, mem, keyIdx); - pkey->type = EVP_PKEY_DSA; - if (out != NULL) { - *out = pkey; - } - - pkey->ownDsa = 1; - pkey->dsa = wolfSSL_DSA_new(); - if (pkey->dsa == NULL) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - - if (wolfSSL_DSA_LoadDer_ex(pkey->dsa, - (const unsigned char*)pkey->pkey.ptr, - pkey->pkey_sz, priv ? WOLFSSL_RSA_LOAD_PRIVATE - : WOLFSSL_RSA_LOAD_PUBLIC) != 1) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - - return pkey; - } - else { - WOLFSSL_MSG("DSA wolfSSL_EVP_PKEY_new error"); - } - } + else +#endif /* NO_RSA */ +#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) + if (d2iTryEccKey(&pkey, *in, inSz, priv) >= 0) { + ; } - #endif /* NO_DSA */ + else +#endif /* HAVE_ECC && OPENSSL_EXTRA */ +#if !defined(NO_DSA) + if (d2iTryDsaKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* NO_DSA */ +#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION > 2)) + if (d2iTryDhKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ - #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) - #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ +#if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ (HAVE_FIPS_VERSION > 2)) - { - int isDhKey; - word32 keyIdx = 0; - #ifdef WOLFSSL_SMALL_STACK - DhKey *dh = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); - if (dh == NULL) - return NULL; - #else - DhKey dh[1]; - #endif - XMEMSET(dh, 0, sizeof(DhKey)); - - isDhKey = wc_InitDhKey(dh) == 0 && - wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz) == 0; - wc_FreeDhKey(dh); - #ifdef WOLFSSL_SMALL_STACK - XFREE(dh, NULL, DYNAMIC_TYPE_DH); - #endif - - /* test if DH key */ - if (isDhKey) { - pkey = wolfSSL_EVP_PKEY_new(); - - if (pkey != NULL) { - pkey->pkey_sz = (int)memSz; - pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, - priv ? DYNAMIC_TYPE_PRIVATE_KEY : - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkey->pkey.ptr == NULL) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - XMEMCPY(pkey->pkey.ptr, mem, memSz); - pkey->type = EVP_PKEY_DH; - if (out != NULL) { - *out = pkey; - } - - pkey->ownDh = 1; - pkey->dh = wolfSSL_DH_new(); - if (pkey->dh == NULL) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - - if (wolfSSL_DH_LoadDer(pkey->dh, - (const unsigned char*)pkey->pkey.ptr, - pkey->pkey_sz) != WOLFSSL_SUCCESS) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - - return pkey; - } - else { - WOLFSSL_MSG("DH wolfSSL_EVP_PKEY_new error"); - } - } + if (d2iTryAltDhKey(&pkey, *in, inSz, priv) >= 0) { + ; } - #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ - #endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ + else +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ - #if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) - #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION > 2)) - { - word32 keyIdx = 0; - DhKey* key = NULL; - int ret; - #ifdef WOLFSSL_SMALL_STACK - DhKey* dh = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); - if (dh == NULL) - return NULL; - #else - DhKey dh[1]; - #endif - XMEMSET(dh, 0, sizeof(DhKey)); - - /* test if DH-public key */ - if (wc_InitDhKey(dh) != 0) - return NULL; - - ret = wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz); - wc_FreeDhKey(dh); - #ifdef WOLFSSL_SMALL_STACK - XFREE(dh, NULL, DYNAMIC_TYPE_DH); - #endif - - if (ret == 0) { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey != NULL) { - pkey->type = EVP_PKEY_DH; - pkey->pkey_sz = (int)memSz; - pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, - priv ? DYNAMIC_TYPE_PRIVATE_KEY : - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkey->pkey.ptr == NULL) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - XMEMCPY(pkey->pkey.ptr, mem, memSz); - if (out != NULL) { - *out = pkey; - } - pkey->ownDh = 1; - pkey->dh = wolfSSL_DH_new(); - if (pkey->dh == NULL) { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - - key = (DhKey*)pkey->dh->internal; - - keyIdx = 0; - if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) == 0) - { - int elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | - ELEMENT_PUB; - if (priv) - elements |= ELEMENT_PRV; - if(SetDhExternal_ex(pkey->dh, elements) - == WOLFSSL_SUCCESS ) { - return pkey; - } - } - else { - wolfSSL_EVP_PKEY_free(pkey); - return NULL; - } - } - } +#ifdef HAVE_PQC +#ifdef HAVE_FALCON + if (d2iTryFalconKey(&pkey, *in, inSz, priv) >= 0) { + ; } - #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ - #endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ - - #ifdef HAVE_PQC - #ifdef HAVE_FALCON - { - int isFalcon = 0; - #ifdef WOLFSSL_SMALL_STACK - falcon_key *falcon = (falcon_key *)XMALLOC(sizeof(falcon_key), NULL, - DYNAMIC_TYPE_FALCON); - if (falcon == NULL) { - return NULL; - } - #else - falcon_key falcon[1]; - #endif - - if (wc_falcon_init(falcon) == 0) { - /* test if Falcon key */ - if (priv) { - /* Try level 1 */ - isFalcon = wc_falcon_set_level(falcon, 1) == 0 && - wc_falcon_import_private_only(mem, (word32)memSz, - falcon) == 0; - if (!isFalcon) { - /* Try level 5 */ - isFalcon = wc_falcon_set_level(falcon, 5) == 0 && - wc_falcon_import_private_only(mem, (word32)memSz, - falcon) == 0; - } - } else { - /* Try level 1 */ - isFalcon = wc_falcon_set_level(falcon, 1) == 0 && - wc_falcon_import_public(mem, (word32)memSz, falcon) - == 0; - - if (!isFalcon) { - /* Try level 5 */ - isFalcon = wc_falcon_set_level(falcon, 5) == 0 && - wc_falcon_import_public(mem, (word32)memSz, - falcon) == 0; - } - } - wc_falcon_free(falcon); - } - - #ifdef WOLFSSL_SMALL_STACK - XFREE(falcon, NULL, DYNAMIC_TYPE_FALCON); - #endif - if (isFalcon) { - /* Create a fake Falcon EVP_PKEY. In the future, we might integrate - * Falcon into the compatibility layer. */ - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("Falcon wolfSSL_EVP_PKEY_new error"); - return NULL; - } - pkey->type = EVP_PKEY_FALCON; - pkey->pkey.ptr = NULL; - pkey->pkey_sz = 0; - return pkey; - } - + else +#endif /* HAVE_FALCON */ +#ifdef HAVE_DILITHIUM + if (d2iTryDilithiumKey(&pkey, *in, inSz, priv) >= 0) { + ; } - #endif /* HAVE_FALCON */ - #ifdef HAVE_DILITHIUM + else +#endif /* HAVE_DILITHIUM */ +#endif /* HAVE_PQC */ { - int isDilithium = 0; - #ifdef WOLFSSL_SMALL_STACK - dilithium_key *dilithium = (dilithium_key *) - XMALLOC(sizeof(dilithium_key), NULL, DYNAMIC_TYPE_DILITHIUM); - if (dilithium == NULL) { - return NULL; - } - #else - dilithium_key dilithium[1]; - #endif - - if (wc_dilithium_init(dilithium) == 0) { - /* Test if Dilithium key. Try all levels. */ - if (priv) { - isDilithium = wc_dilithium_set_level(dilithium, 2) == 0 && - wc_dilithium_import_private_only(mem, - (word32)memSz, dilithium) == 0; - if (!isDilithium) { - isDilithium = wc_dilithium_set_level(dilithium, 3) == 0 && - wc_dilithium_import_private_only(mem, - (word32)memSz, dilithium) == 0; - } - if (!isDilithium) { - isDilithium = wc_dilithium_set_level(dilithium, 5) == 0 && - wc_dilithium_import_private_only(mem, - (word32)memSz, dilithium) == 0; - } - } else { - isDilithium = wc_dilithium_set_level(dilithium, 2) == 0 && - wc_dilithium_import_public(mem, (word32)memSz, - dilithium) == 0; - if (!isDilithium) { - isDilithium = wc_dilithium_set_level(dilithium, 3) == 0 && - wc_dilithium_import_public(mem, (word32)memSz, - dilithium) == 0; - } - if (!isDilithium) { - isDilithium = wc_dilithium_set_level(dilithium, 5) == 0 && - wc_dilithium_import_public(mem, (word32)memSz, - dilithium) == 0; - } - } - wc_dilithium_free(dilithium); - } - - #ifdef WOLFSSL_SMALL_STACK - XFREE(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); - #endif - if (isDilithium) { - /* Create a fake Dilithium EVP_PKEY. In the future, we might - * integrate Dilithium into the compatibility layer. */ - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("Dilithium wolfSSL_EVP_PKEY_new error"); - return NULL; - } - pkey->type = EVP_PKEY_DILITHIUM; - pkey->pkey.ptr = NULL; - pkey->pkey_sz = 0; - return pkey; - } - - } - #endif /* HAVE_DILITHIUM */ - #endif /* HAVE_PQC */ - - if (pkey == NULL) { WOLFSSL_MSG("wolfSSL_d2i_PUBKEY couldn't determine key type"); } + if ((pkey != NULL) && (out != NULL)) { + *out = pkey; + } return pkey; - } #endif /* OPENSSL_EXTRA || WPA_SMALL */ #ifdef OPENSSL_EXTRA WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY( - WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey, const unsigned char** keyBuf, long keyLen) + WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey, const unsigned char** keyBuf, + long keyLen) { WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL; #ifdef WOLFSSL_PEM_TO_DER @@ -10489,7 +7197,8 @@ WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY( /* Verify this is PKCS8 Key */ word32 inOutIdx = 0; word32 algId; - ret = ToTraditionalInline_ex(der->buffer, &inOutIdx, der->length, &algId); + ret = ToTraditionalInline_ex(der->buffer, &inOutIdx, der->length, + &algId); if (ret >= 0) { ret = 0; /* good DER */ } @@ -10635,7 +7344,8 @@ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** out, !defined(NO_PWDBASED) /* helper function to get raw pointer to DER buffer from WOLFSSL_EVP_PKEY */ -static int wolfSSL_EVP_PKEY_get_der(const WOLFSSL_EVP_PKEY* key, unsigned char** der) +static int wolfSSL_EVP_PKEY_get_der(const WOLFSSL_EVP_PKEY* key, + unsigned char** der) { int sz; word16 pkcs8HeaderSz; @@ -10966,78 +7676,6 @@ int wolfSSL_check_private_key(const WOLFSSL* ssl) #endif /* !NO_CERTS */ -int wolfSSL_use_PrivateKey(WOLFSSL* ssl, WOLFSSL_EVP_PKEY* pkey) -{ - WOLFSSL_ENTER("wolfSSL_use_PrivateKey"); - if (ssl == NULL || pkey == NULL ) { - return WOLFSSL_FAILURE; - } - - return wolfSSL_use_PrivateKey_buffer(ssl, (unsigned char*)pkey->pkey.ptr, - pkey->pkey_sz, WOLFSSL_FILETYPE_ASN1); -} - - -int wolfSSL_use_PrivateKey_ASN1(int pri, WOLFSSL* ssl, const unsigned char* der, - long derSz) -{ - WOLFSSL_ENTER("wolfSSL_use_PrivateKey_ASN1"); - if (ssl == NULL || der == NULL ) { - return WOLFSSL_FAILURE; - } - - (void)pri; /* type of private key */ - return wolfSSL_use_PrivateKey_buffer(ssl, der, derSz, WOLFSSL_FILETYPE_ASN1); -} -/****************************************************************************** -* wolfSSL_CTX_use_PrivateKey_ASN1 - loads a private key buffer into the SSL ctx -* -* RETURNS: -* returns WOLFSSL_SUCCESS on success, otherwise returns WOLFSSL_FAILURE -*/ - -int wolfSSL_CTX_use_PrivateKey_ASN1(int pri, WOLFSSL_CTX* ctx, - unsigned char* der, long derSz) -{ - WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_ASN1"); - if (ctx == NULL || der == NULL ) { - return WOLFSSL_FAILURE; - } - - (void)pri; /* type of private key */ - return wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1); -} - - -#ifndef NO_RSA -int wolfSSL_use_RSAPrivateKey_ASN1(WOLFSSL* ssl, unsigned char* der, long derSz) -{ - WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_ASN1"); - if (ssl == NULL || der == NULL ) { - return WOLFSSL_FAILURE; - } - - return wolfSSL_use_PrivateKey_buffer(ssl, der, derSz, WOLFSSL_FILETYPE_ASN1); -} -#endif - -int wolfSSL_use_certificate(WOLFSSL* ssl, WOLFSSL_X509* x509) -{ - long idx = 0; - - WOLFSSL_ENTER("wolfSSL_use_certificate"); - if (x509 != NULL && ssl != NULL && x509->derCert != NULL) { - if (ProcessBuffer(NULL, x509->derCert->buffer, x509->derCert->length, - WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl, &idx, 0, - GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - } - - (void)idx; - return WOLFSSL_FAILURE; -} - #endif /* OPENSSL_EXTRA */ #if defined(HAVE_RPK) @@ -11266,98 +7904,6 @@ WOLFSSL_API int wolfSSL_get_negotiated_server_cert_type(WOLFSSL* ssl, int* tp) #endif /* HAVE_RPK */ -int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, const unsigned char* der, - int derSz) -{ - long idx = 0; - - WOLFSSL_ENTER("wolfSSL_use_certificate_ASN1"); - if (der != NULL && ssl != NULL) { - if (ProcessBuffer(NULL, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, - ssl, &idx, 0, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - } - - (void)idx; - return WOLFSSL_FAILURE; -} - -#ifndef NO_FILESYSTEM - -WOLFSSL_ABI -int wolfSSL_use_certificate_file(WOLFSSL* ssl, const char* file, int format) -{ - WOLFSSL_ENTER("wolfSSL_use_certificate_file"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - if (ProcessFile(ssl->ctx, file, format, CERT_TYPE, - ssl, 0, NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - - return WOLFSSL_FAILURE; -} - - -WOLFSSL_ABI -int wolfSSL_use_PrivateKey_file(WOLFSSL* ssl, const char* file, int format) -{ - WOLFSSL_ENTER("wolfSSL_use_PrivateKey_file"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - if (ProcessFile(ssl->ctx, file, format, PRIVATEKEY_TYPE, - ssl, 0, NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - - return WOLFSSL_FAILURE; -} - - -WOLFSSL_ABI -int wolfSSL_use_certificate_chain_file(WOLFSSL* ssl, const char* file) -{ - /* process up to MAX_CHAIN_DEPTH plus subject cert */ - WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - if (ProcessFile(ssl->ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, - ssl, 1, NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - - return WOLFSSL_FAILURE; -} - -int wolfSSL_use_certificate_chain_file_format(WOLFSSL* ssl, const char* file, - int format) -{ - /* process up to MAX_CHAIN_DEPTH plus subject cert */ - WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file_format"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - if (ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 1, - NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - return WOLFSSL_FAILURE; -} - -#endif /* !NO_FILESYSTEM */ - #ifdef HAVE_ECC /* Set Temp CTX EC-DHE size in octets, can be 14 - 66 (112 - 521 bit) */ @@ -11416,78 +7962,6 @@ int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL* ssl, word16 sz) #endif /* HAVE_ECC */ -#ifdef OPENSSL_EXTRA - -#ifndef NO_FILESYSTEM -int wolfSSL_CTX_use_RSAPrivateKey_file(WOLFSSL_CTX* ctx,const char* file, - int format) -{ - WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey_file"); - - return wolfSSL_CTX_use_PrivateKey_file(ctx, file, format); -} - - -int wolfSSL_use_RSAPrivateKey_file(WOLFSSL* ssl, const char* file, int format) -{ - WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_file"); - - return wolfSSL_use_PrivateKey_file(ssl, file, format); -} -#endif /* NO_FILESYSTEM */ - - -/* Copies the master secret over to out buffer. If outSz is 0 returns the size - * of master secret. - * - * ses : a session from completed TLS/SSL handshake - * out : buffer to hold copy of master secret - * outSz : size of out buffer - * returns : number of bytes copied into out buffer on success - * less then or equal to 0 is considered a failure case - */ -int wolfSSL_SESSION_get_master_key(const WOLFSSL_SESSION* ses, - unsigned char* out, int outSz) -{ - int size; - - ses = ClientSessionToSession(ses); - - if (outSz == 0) { - return SECRET_LEN; - } - - if (ses == NULL || out == NULL || outSz < 0) { - return 0; - } - - if (outSz > SECRET_LEN) { - size = SECRET_LEN; - } - else { - size = outSz; - } - - XMEMCPY(out, ses->masterSecret, size); - return size; -} - - -int wolfSSL_SESSION_get_master_key_length(const WOLFSSL_SESSION* ses) -{ - (void)ses; - return SECRET_LEN; -} - -#ifdef WOLFSSL_EARLY_DATA -unsigned int wolfSSL_SESSION_get_max_early_data(const WOLFSSL_SESSION *session) -{ - return session->maxEarlyDataSz; -} -#endif /* WOLFSSL_EARLY_DATA */ - -#endif /* OPENSSL_EXTRA */ - typedef struct { byte verifyPeer:1; byte verifyNone:1; @@ -11629,7 +8103,8 @@ int wolfSSL_set_post_handshake_auth(WOLFSSL* ssl, int val) } return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } -#endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_TLS13 && WOLFSSL_POST_HANDSHAKE_AUTH */ +#endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_TLS13 && + * WOLFSSL_POST_HANDSHAKE_AUTH */ /* store user ctx for verify callback */ void wolfSSL_SetCertCbCtx(WOLFSSL* ssl, void* ctx) @@ -11726,499 +8201,6 @@ int wolfSSL_CTX_get_cert_cache_memsize(WOLFSSL_CTX* ctx) #endif /* !NO_CERTS */ -#ifndef NO_SESSION_CACHE - -WOLFSSL_ABI -WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_session"); - if (ssl) { -#ifdef NO_SESSION_CACHE_REF - return ssl->session; -#else - if (ssl->options.side == WOLFSSL_CLIENT_END) { - /* On the client side we want to return a persistent reference for - * backwards compatibility. */ -#ifndef NO_CLIENT_CACHE - if (ssl->clientSession) { - return (WOLFSSL_SESSION*)ssl->clientSession; - } - else { - /* Try to add a ClientCache entry to associate with the current - * session. Ignore any session cache options. */ - int err; - const byte* id = ssl->session->sessionID; - byte idSz = ssl->session->sessionIDSz; - if (ssl->session->haveAltSessionID) { - id = ssl->session->altSessionID; - idSz = ID_LEN; - } - err = AddSessionToCache(ssl->ctx, ssl->session, id, idSz, - NULL, ssl->session->side, - #ifdef HAVE_SESSION_TICKET - ssl->session->ticketLen > 0, - #else - 0, - #endif - &ssl->clientSession); - if (err == 0) { - return (WOLFSSL_SESSION*)ssl->clientSession; - } - } -#endif - } - else { - return ssl->session; - } -#endif - } - - return NULL; -} - -/* The get1 version requires caller to call SSL_SESSION_free */ -WOLFSSL_SESSION* wolfSSL_get1_session(WOLFSSL* ssl) -{ - WOLFSSL_SESSION* sess = NULL; - WOLFSSL_ENTER("wolfSSL_get1_session"); - if (ssl != NULL) { - sess = ssl->session; - if (sess != NULL) { - /* increase reference count if allocated session */ - if (sess->type == WOLFSSL_SESSION_TYPE_HEAP) { - if (wolfSSL_SESSION_up_ref(sess) != WOLFSSL_SUCCESS) - sess = NULL; - } - } - } - return sess; -} - - -/* - * Sets the session object to use when establishing a TLS/SSL session using - * the ssl object. Therefore, this function must be called before - * wolfSSL_connect. The session object to use can be obtained in a previous - * TLS/SSL connection using wolfSSL_get_session. - * - * This function rejects the session if it has been expired when this function - * is called. Note that this expiration check is wolfSSL specific and differs - * from OpenSSL return code behavior. - * - * By default, wolfSSL_set_session returns WOLFSSL_SUCCESS on successfully - * setting the session, WOLFSSL_FAILURE on failure due to the session cache - * being disabled, or the session has expired. - * - * To match OpenSSL return code behavior when session is expired, define - * OPENSSL_EXTRA and WOLFSSL_ERROR_CODE_OPENSSL. This behavior will return - * WOLFSSL_SUCCESS even when the session is expired and rejected. - */ -WOLFSSL_ABI -int wolfSSL_set_session(WOLFSSL* ssl, WOLFSSL_SESSION* session) -{ - WOLFSSL_ENTER("wolfSSL_set_session"); - if (session) - return wolfSSL_SetSession(ssl, session); - - return WOLFSSL_FAILURE; -} - - -#ifndef NO_CLIENT_CACHE - -/* Associate client session with serverID, find existing or store for saving - if newSession flag on, don't reuse existing session - WOLFSSL_SUCCESS on ok */ -int wolfSSL_SetServerID(WOLFSSL* ssl, const byte* id, int len, int newSession) -{ - WOLFSSL_SESSION* session = NULL; - byte idHash[SERVER_ID_LEN]; - - WOLFSSL_ENTER("wolfSSL_SetServerID"); - - if (ssl == NULL || id == NULL || len <= 0) - return BAD_FUNC_ARG; - - if (len > SERVER_ID_LEN) { -#if defined(NO_SHA) && !defined(NO_SHA256) - if (wc_Sha256Hash(id, len, idHash) != 0) - return WOLFSSL_FAILURE; -#else - if (wc_ShaHash(id, len, idHash) != 0) - return WOLFSSL_FAILURE; -#endif - id = idHash; - len = SERVER_ID_LEN; - } - - if (newSession == 0) { - session = wolfSSL_GetSessionClient(ssl, id, len); - if (session) { - if (wolfSSL_SetSession(ssl, session) != WOLFSSL_SUCCESS) { - #ifdef HAVE_EXT_CACHE - wolfSSL_FreeSession(ssl->ctx, session); - #endif - WOLFSSL_MSG("wolfSSL_SetSession failed"); - session = NULL; - } - } - } - - if (session == NULL) { - WOLFSSL_MSG("Valid ServerID not cached already"); - - ssl->session->idLen = (word16)len; - XMEMCPY(ssl->session->serverID, id, len); - } -#ifdef HAVE_EXT_CACHE - else { - wolfSSL_FreeSession(ssl->ctx, session); - } -#endif - - return WOLFSSL_SUCCESS; -} - -#endif /* !NO_CLIENT_CACHE */ - -/* TODO: Add SESSION_CACHE_DYNAMIC_MEM support for PERSIST_SESSION_CACHE. - * Need a count of current sessions to get an accurate memsize (totalCount is - * not decremented when sessions are removed). - * Need to determine ideal layout for mem/filesave. - * Also need mem/filesave checking to ensure not restoring non DYNAMIC_MEM cache. - */ -#if defined(PERSIST_SESSION_CACHE) && !defined(SESSION_CACHE_DYNAMIC_MEM) - -/* for persistence, if changes to layout need to increment and modify - save_session_cache() and restore_session_cache and memory versions too */ -#define WOLFSSL_CACHE_VERSION 2 - -/* Session Cache Header information */ -typedef struct { - int version; /* cache layout version id */ - int rows; /* session rows */ - int columns; /* session columns */ - int sessionSz; /* sizeof WOLFSSL_SESSION */ -} cache_header_t; - -/* current persistence layout is: - - 1) cache_header_t - 2) SessionCache - 3) ClientCache - - update WOLFSSL_CACHE_VERSION if change layout for the following - PERSISTENT_SESSION_CACHE functions -*/ - -/* get how big the the session cache save buffer needs to be */ -int wolfSSL_get_session_cache_memsize(void) -{ - int sz = (int)(sizeof(SessionCache) + sizeof(cache_header_t)); -#ifndef NO_CLIENT_CACHE - sz += (int)(sizeof(ClientCache)); -#endif - return sz; -} - - -/* Persist session cache to memory */ -int wolfSSL_memsave_session_cache(void* mem, int sz) -{ - int i; - cache_header_t cache_header; - SessionRow* row = (SessionRow*)((byte*)mem + sizeof(cache_header)); - - WOLFSSL_ENTER("wolfSSL_memsave_session_cache"); - - if (sz < wolfSSL_get_session_cache_memsize()) { - WOLFSSL_MSG("Memory buffer too small"); - return BUFFER_E; - } - - cache_header.version = WOLFSSL_CACHE_VERSION; - cache_header.rows = SESSION_ROWS; - cache_header.columns = SESSIONS_PER_ROW; - cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION); - XMEMCPY(mem, &cache_header, sizeof(cache_header)); - -#ifndef ENABLE_SESSION_CACHE_ROW_LOCK - if (SESSION_ROW_RD_LOCK(row) != 0) { - WOLFSSL_MSG("Session cache mutex lock failed"); - return BAD_MUTEX_E; - } -#endif - for (i = 0; i < cache_header.rows; ++i) { - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - if (SESSION_ROW_RD_LOCK(&SessionCache[i]) != 0) { - WOLFSSL_MSG("Session row cache mutex lock failed"); - return BAD_MUTEX_E; - } - #endif - - XMEMCPY(row++, &SessionCache[i], SIZEOF_SESSION_ROW); - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_UNLOCK(&SessionCache[i]); - #endif - } -#ifndef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_UNLOCK(row); -#endif - -#ifndef NO_CLIENT_CACHE - if (wc_LockMutex(&clisession_mutex) != 0) { - WOLFSSL_MSG("Client cache mutex lock failed"); - return BAD_MUTEX_E; - } - XMEMCPY(row, ClientCache, sizeof(ClientCache)); - wc_UnLockMutex(&clisession_mutex); -#endif - - WOLFSSL_LEAVE("wolfSSL_memsave_session_cache", WOLFSSL_SUCCESS); - - return WOLFSSL_SUCCESS; -} - - -/* Restore the persistent session cache from memory */ -int wolfSSL_memrestore_session_cache(const void* mem, int sz) -{ - int i; - cache_header_t cache_header; - SessionRow* row = (SessionRow*)((byte*)mem + sizeof(cache_header)); - - WOLFSSL_ENTER("wolfSSL_memrestore_session_cache"); - - if (sz < wolfSSL_get_session_cache_memsize()) { - WOLFSSL_MSG("Memory buffer too small"); - return BUFFER_E; - } - - XMEMCPY(&cache_header, mem, sizeof(cache_header)); - if (cache_header.version != WOLFSSL_CACHE_VERSION || - cache_header.rows != SESSION_ROWS || - cache_header.columns != SESSIONS_PER_ROW || - cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) { - - WOLFSSL_MSG("Session cache header match failed"); - return CACHE_MATCH_ERROR; - } - -#ifndef ENABLE_SESSION_CACHE_ROW_LOCK - if (SESSION_ROW_WR_LOCK(&SessionCache[0]) != 0) { - WOLFSSL_MSG("Session cache mutex lock failed"); - return BAD_MUTEX_E; - } -#endif - for (i = 0; i < cache_header.rows; ++i) { - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) { - WOLFSSL_MSG("Session row cache mutex lock failed"); - return BAD_MUTEX_E; - } - #endif - - XMEMCPY(&SessionCache[i], row++, SIZEOF_SESSION_ROW); - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_UNLOCK(&SessionCache[i]); - #endif - } -#ifndef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_UNLOCK(&SessionCache[0]); -#endif - -#ifndef NO_CLIENT_CACHE - if (wc_LockMutex(&clisession_mutex) != 0) { - WOLFSSL_MSG("Client cache mutex lock failed"); - return BAD_MUTEX_E; - } - XMEMCPY(ClientCache, row, sizeof(ClientCache)); - wc_UnLockMutex(&clisession_mutex); -#endif - - WOLFSSL_LEAVE("wolfSSL_memrestore_session_cache", WOLFSSL_SUCCESS); - - return WOLFSSL_SUCCESS; -} - -#if !defined(NO_FILESYSTEM) - -/* Persist session cache to file */ -/* doesn't use memsave because of additional memory use */ -int wolfSSL_save_session_cache(const char *fname) -{ - XFILE file; - int ret; - int rc = WOLFSSL_SUCCESS; - int i; - cache_header_t cache_header; - - WOLFSSL_ENTER("wolfSSL_save_session_cache"); - - file = XFOPEN(fname, "w+b"); - if (file == XBADFILE) { - WOLFSSL_MSG("Couldn't open session cache save file"); - return WOLFSSL_BAD_FILE; - } - cache_header.version = WOLFSSL_CACHE_VERSION; - cache_header.rows = SESSION_ROWS; - cache_header.columns = SESSIONS_PER_ROW; - cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION); - - /* cache header */ - ret = (int)XFWRITE(&cache_header, sizeof cache_header, 1, file); - if (ret != 1) { - WOLFSSL_MSG("Session cache header file write failed"); - XFCLOSE(file); - return FWRITE_ERROR; - } - -#ifndef ENABLE_SESSION_CACHE_ROW_LOCK - if (SESSION_ROW_RD_LOCK(&SessionCache[0]) != 0) { - WOLFSSL_MSG("Session cache mutex lock failed"); - XFCLOSE(file); - return BAD_MUTEX_E; - } -#endif - /* session cache */ - for (i = 0; i < cache_header.rows; ++i) { - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - if (SESSION_ROW_RD_LOCK(&SessionCache[i]) != 0) { - WOLFSSL_MSG("Session row cache mutex lock failed"); - XFCLOSE(file); - return BAD_MUTEX_E; - } - #endif - - ret = (int)XFWRITE(&SessionCache[i], SIZEOF_SESSION_ROW, 1, file); - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_UNLOCK(&SessionCache[i]); - #endif - if (ret != 1) { - WOLFSSL_MSG("Session cache member file write failed"); - rc = FWRITE_ERROR; - break; - } - } -#ifndef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_UNLOCK(&SessionCache[0]); -#endif - -#ifndef NO_CLIENT_CACHE - /* client cache */ - if (wc_LockMutex(&clisession_mutex) != 0) { - WOLFSSL_MSG("Client cache mutex lock failed"); - XFCLOSE(file); - return BAD_MUTEX_E; - } - ret = (int)XFWRITE(ClientCache, sizeof(ClientCache), 1, file); - if (ret != 1) { - WOLFSSL_MSG("Client cache member file write failed"); - rc = FWRITE_ERROR; - } - wc_UnLockMutex(&clisession_mutex); -#endif /* !NO_CLIENT_CACHE */ - - XFCLOSE(file); - WOLFSSL_LEAVE("wolfSSL_save_session_cache", rc); - - return rc; -} - - -/* Restore the persistent session cache from file */ -/* doesn't use memstore because of additional memory use */ -int wolfSSL_restore_session_cache(const char *fname) -{ - XFILE file; - int rc = WOLFSSL_SUCCESS; - int ret; - int i; - cache_header_t cache_header; - - WOLFSSL_ENTER("wolfSSL_restore_session_cache"); - - file = XFOPEN(fname, "rb"); - if (file == XBADFILE) { - WOLFSSL_MSG("Couldn't open session cache save file"); - return WOLFSSL_BAD_FILE; - } - /* cache header */ - ret = (int)XFREAD(&cache_header, sizeof(cache_header), 1, file); - if (ret != 1) { - WOLFSSL_MSG("Session cache header file read failed"); - XFCLOSE(file); - return FREAD_ERROR; - } - if (cache_header.version != WOLFSSL_CACHE_VERSION || - cache_header.rows != SESSION_ROWS || - cache_header.columns != SESSIONS_PER_ROW || - cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) { - - WOLFSSL_MSG("Session cache header match failed"); - XFCLOSE(file); - return CACHE_MATCH_ERROR; - } - -#ifndef ENABLE_SESSION_CACHE_ROW_LOCK - if (SESSION_ROW_WR_LOCK(&SessionCache[0]) != 0) { - WOLFSSL_MSG("Session cache mutex lock failed"); - XFCLOSE(file); - return BAD_MUTEX_E; - } -#endif - /* session cache */ - for (i = 0; i < cache_header.rows; ++i) { - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) { - WOLFSSL_MSG("Session row cache mutex lock failed"); - XFCLOSE(file); - return BAD_MUTEX_E; - } - #endif - - ret = (int)XFREAD(&SessionCache[i], SIZEOF_SESSION_ROW, 1, file); - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_UNLOCK(&SessionCache[i]); - #endif - if (ret != 1) { - WOLFSSL_MSG("Session cache member file read failed"); - XMEMSET(SessionCache, 0, sizeof SessionCache); - rc = FREAD_ERROR; - break; - } - } -#ifndef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_UNLOCK(&SessionCache[0]); -#endif - -#ifndef NO_CLIENT_CACHE - /* client cache */ - if (wc_LockMutex(&clisession_mutex) != 0) { - WOLFSSL_MSG("Client cache mutex lock failed"); - XFCLOSE(file); - return BAD_MUTEX_E; - } - ret = (int)XFREAD(ClientCache, sizeof(ClientCache), 1, file); - if (ret != 1) { - WOLFSSL_MSG("Client cache member file read failed"); - XMEMSET(ClientCache, 0, sizeof ClientCache); - rc = FREAD_ERROR; - } - wc_UnLockMutex(&clisession_mutex); -#endif /* !NO_CLIENT_CACHE */ - - XFCLOSE(file); - WOLFSSL_LEAVE("wolfSSL_restore_session_cache", rc); - - return rc; -} - -#endif /* !NO_FILESYSTEM */ -#endif /* PERSIST_SESSION_CACHE && !SESSION_CACHE_DYNAMIC_MEM */ -#endif /* NO_SESSION_CACHE */ - - void wolfSSL_load_error_strings(void) { /* compatibility only */ @@ -12257,78 +8239,6 @@ int wolfSSL_set_session_secret_cb(WOLFSSL* ssl, SessionSecretCb cb, void* ctx) #endif -#ifndef NO_SESSION_CACHE - -/* on by default if built in but allow user to turn off */ -WOLFSSL_ABI -long wolfSSL_CTX_set_session_cache_mode(WOLFSSL_CTX* ctx, long mode) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_session_cache_mode"); - - if (ctx == NULL) - return WOLFSSL_FAILURE; - - if (mode == WOLFSSL_SESS_CACHE_OFF) { - ctx->sessionCacheOff = 1; -#ifdef HAVE_EXT_CACHE - ctx->internalCacheOff = 1; - ctx->internalCacheLookupOff = 1; -#endif - } - - if ((mode & WOLFSSL_SESS_CACHE_NO_AUTO_CLEAR) != 0) - ctx->sessionCacheFlushOff = 1; - -#ifdef HAVE_EXT_CACHE - /* WOLFSSL_SESS_CACHE_NO_INTERNAL activates both if's */ - if ((mode & WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE) != 0) - ctx->internalCacheOff = 1; - if ((mode & WOLFSSL_SESS_CACHE_NO_INTERNAL_LOOKUP) != 0) - ctx->internalCacheLookupOff = 1; -#endif - - return WOLFSSL_SUCCESS; -} - -#ifdef OPENSSL_EXTRA -/* Get the session cache mode for CTX - * - * ctx WOLFSSL_CTX struct to get cache mode from - * - * Returns a bit mask that has the session cache mode */ -long wolfSSL_CTX_get_session_cache_mode(WOLFSSL_CTX* ctx) -{ - long m = 0; - - WOLFSSL_ENTER("wolfSSL_CTX_get_session_cache_mode"); - - if (ctx == NULL) { - return m; - } - - if (ctx->sessionCacheOff != 1) { - m |= WOLFSSL_SESS_CACHE_SERVER; - } - - if (ctx->sessionCacheFlushOff == 1) { - m |= WOLFSSL_SESS_CACHE_NO_AUTO_CLEAR; - } - -#ifdef HAVE_EXT_CACHE - if (ctx->internalCacheOff == 1) { - m |= WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE; - } - if (ctx->internalCacheLookupOff == 1) { - m |= WOLFSSL_SESS_CACHE_NO_INTERNAL_LOOKUP; - } -#endif - - return m; -} -#endif /* OPENSSL_EXTRA */ - -#endif /* NO_SESSION_CACHE */ - #ifdef OPENSSL_EXTRA /* @@ -12639,7 +8549,8 @@ static const struct ForbiddenLabels { {TLS_PRF_LABEL_CLIENT_FINISHED, XSTR_SIZEOF(TLS_PRF_LABEL_CLIENT_FINISHED)}, {TLS_PRF_LABEL_SERVER_FINISHED, XSTR_SIZEOF(TLS_PRF_LABEL_SERVER_FINISHED)}, {TLS_PRF_LABEL_MASTER_SECRET, XSTR_SIZEOF(TLS_PRF_LABEL_MASTER_SECRET)}, - {TLS_PRF_LABEL_EXT_MASTER_SECRET, XSTR_SIZEOF(TLS_PRF_LABEL_EXT_MASTER_SECRET)}, + {TLS_PRF_LABEL_EXT_MASTER_SECRET, + XSTR_SIZEOF(TLS_PRF_LABEL_EXT_MASTER_SECRET)}, {TLS_PRF_LABEL_KEY_EXPANSION, XSTR_SIZEOF(TLS_PRF_LABEL_KEY_EXPANSION)}, {NULL, 0}, }; @@ -12728,8 +8639,9 @@ int wolfSSL_export_keying_material(WOLFSSL *ssl, PRIVATE_KEY_UNLOCK(); if (wc_PRF_TLS(out, (word32)outLen, ssl->arrays->masterSecret, SECRET_LEN, - (byte*)label, (word32)labelLen, seed, seedLen, IsAtLeastTLSv1_2(ssl), - ssl->specs.mac_algorithm, ssl->heap, ssl->devId) != 0) { + (byte*)label, (word32)labelLen, seed, seedLen, + IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, ssl->heap, + ssl->devId) != 0) { WOLFSSL_MSG("wc_PRF_TLS error"); PRIVATE_KEY_LOCK(); XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -12841,7 +8753,8 @@ int wolfSSL_DTLSv1_handle_timeout(WOLFSSL* ssl) #endif #ifndef NO_WOLFSSL_STUB -void wolfSSL_DTLSv1_set_initial_timeout_duration(WOLFSSL* ssl, word32 duration_ms) +void wolfSSL_DTLSv1_set_initial_timeout_duration(WOLFSSL* ssl, + word32 duration_ms) { WOLFSSL_STUB("SSL_DTLSv1_set_initial_timeout_duration"); (void)ssl; @@ -12856,7 +8769,8 @@ int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int timeout) return BAD_FUNC_ARG; if (timeout > ssl->dtls_timeout_max) { - WOLFSSL_MSG("Can't set dtls timeout init greater than dtls timeout max"); + WOLFSSL_MSG("Can't set dtls timeout init greater than dtls timeout " + "max"); return BAD_FUNC_ARG; } @@ -13108,7 +9022,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, (void)heap; WOLFSSL_ENTER("wolfSSLv23_client_method_ex"); if (method) { - #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) + #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || \ + defined(WOLFSSL_SHA512) #if defined(WOLFSSL_TLS13) InitSSL_Method(method, MakeTLSv1_3()); #elif !defined(WOLFSSL_NO_TLS12) @@ -13132,7 +9047,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, WOLFSSL_ABI int wolfSSL_connect(WOLFSSL* ssl) { - #if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13)) + #if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ + defined(WOLFSSL_TLS13)) int neededState; byte advanceState; #endif @@ -13165,7 +9081,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #endif #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ - #if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13) + #if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ + defined(WOLFSSL_TLS13) return wolfSSL_connect_TLSv13(ssl); #else #ifdef WOLFSSL_TLS13 @@ -13239,8 +9156,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, if (ssl->fragOffset == 0 && !ssl->options.buildingMsg) { if (advanceState) { ssl->options.connectState++; - WOLFSSL_MSG("connect state: " - "Advanced from last buffered fragment send"); + WOLFSSL_MSG("connect state: Advanced from last " + "buffered fragment send"); #ifdef WOLFSSL_ASYNC_IO /* Cleanup async */ FreeAsyncCtx(ssl, 0); @@ -13541,7 +9458,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SECURE_RENEGOTIATION) /* This may be necessary in async so that we don't try to * renegotiate again */ - if (ssl->secure_renegotiation && ssl->secure_renegotiation->startScr) { + if (ssl->secure_renegotiation && + ssl->secure_renegotiation->startScr) { ssl->secure_renegotiation->startScr = 0; } #endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */ @@ -13610,7 +9528,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, (void)heap; WOLFSSL_ENTER("wolfSSLv23_server_method_ex"); if (method) { - #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) + #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || \ + defined(WOLFSSL_SHA512) #ifdef WOLFSSL_TLS13 InitSSL_Method(method, MakeTLSv1_3()); #elif !defined(WOLFSSL_NO_TLS12) @@ -13637,7 +9556,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, WOLFSSL_ABI int wolfSSL_accept(WOLFSSL* ssl) { -#if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13)) +#if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ + defined(WOLFSSL_TLS13)) word16 havePSK = 0; word16 haveAnon = 0; word16 haveMcast = 0; @@ -13798,8 +9718,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, ssl->options.acceptState == TICKET_SENT || ssl->options.acceptState == CHANGE_CIPHER_SENT) { ssl->options.acceptState++; - WOLFSSL_MSG("accept state: " - "Advanced from last buffered fragment send"); + WOLFSSL_MSG("accept state: Advanced from last " + "buffered fragment send"); #ifdef WOLFSSL_ASYNC_IO /* Cleanup async */ FreeAsyncCtx(ssl, 0); @@ -13927,7 +9847,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, if (ssl->options.verifyPeer) { if ( (ssl->error = SendCertificateRequest(ssl)) != 0) { #ifdef WOLFSSL_CHECK_ALERT_ON_ERR - ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ + /* See if an alert was sent. */ + ProcessReplyEx(ssl, 1); #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; @@ -14070,7 +9991,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SECURE_RENEGOTIATION) /* This may be necessary in async so that we don't try to * renegotiate again */ - if (ssl->secure_renegotiation && ssl->secure_renegotiation->startScr) { + if (ssl->secure_renegotiation && + ssl->secure_renegotiation->startScr) { ssl->secure_renegotiation->startScr = 0; } #endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */ @@ -14222,7 +10144,8 @@ int wolfSSL_Cleanup(void) #endif /* !NO_SESSION_CACHE */ #ifndef WOLFSSL_MUTEX_INITIALIZER - if ((inits_count_mutex_valid == 1) && (wc_FreeMutex(&inits_count_mutex) != 0)) { + if ((inits_count_mutex_valid == 1) && + (wc_FreeMutex(&inits_count_mutex) != 0)) { if (ret == WOLFSSL_SUCCESS) ret = BAD_MUTEX_E; } @@ -14277,1711 +10200,6 @@ int wolfSSL_Cleanup(void) return ret; } -void SetupSession(WOLFSSL* ssl) -{ - WOLFSSL_SESSION* session = ssl->session; - - WOLFSSL_ENTER("SetupSession"); - - if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) { - /* Make sure the session ID is available when the user calls any - * get_session API */ - if (!session->haveAltSessionID) { - XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN); - session->sessionIDSz = ssl->arrays->sessionIDSz; - } - else { - XMEMCPY(session->sessionID, session->altSessionID, ID_LEN); - session->sessionIDSz = ID_LEN; - } - } - session->side = (byte)ssl->options.side; - if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) - XMEMCPY(session->masterSecret, ssl->arrays->masterSecret, SECRET_LEN); - session->haveEMS = ssl->options.haveEMS; -#ifdef WOLFSSL_SESSION_ID_CTX - /* If using compatibility layer then check for and copy over session context - * id. */ - if (ssl->sessionCtxSz > 0 && ssl->sessionCtxSz < ID_LEN) { - XMEMCPY(ssl->session->sessionCtx, ssl->sessionCtx, ssl->sessionCtxSz); - session->sessionCtxSz = ssl->sessionCtxSz; - } -#endif - session->timeout = ssl->timeout; -#ifndef NO_ASN_TIME - session->bornOn = LowResTimer(); -#endif -#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET)) - session->version = ssl->version; -#endif -#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ - (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) - session->cipherSuite0 = ssl->options.cipherSuite0; - session->cipherSuite = ssl->options.cipherSuite; -#endif -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - session->peerVerifyRet = (byte)ssl->peerVerifyRet; -#endif - session->isSetup = 1; -} - -#ifndef NO_SESSION_CACHE - -WOLFSSL_ABI -void wolfSSL_flush_sessions(WOLFSSL_CTX* ctx, long tm) -{ - /* static table now, no flushing needed */ - (void)ctx; - (void)tm; -} - -void wolfSSL_CTX_flush_sessions(WOLFSSL_CTX* ctx, long tm) -{ - int i, j; - byte id[ID_LEN]; - - (void)ctx; - XMEMSET(id, 0, ID_LEN); - WOLFSSL_ENTER("wolfSSL_flush_sessions"); - for (i = 0; i < SESSION_ROWS; ++i) { - if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) { - WOLFSSL_MSG("Session cache mutex lock failed"); - return; - } - for (j = 0; j < SESSIONS_PER_ROW; j++) { -#ifdef SESSION_CACHE_DYNAMIC_MEM - WOLFSSL_SESSION* s = SessionCache[i].Sessions[j]; -#else - WOLFSSL_SESSION* s = &SessionCache[i].Sessions[j]; -#endif - if ( -#ifdef SESSION_CACHE_DYNAMIC_MEM - s != NULL && -#endif - XMEMCMP(s->sessionID, id, ID_LEN) != 0 && - s->bornOn + s->timeout < (word32)tm - ) - { - EvictSessionFromCache(s); -#ifdef SESSION_CACHE_DYNAMIC_MEM - XFREE(s, s->heap, DYNAMIC_TYPE_SESSION); - SessionCache[i].Sessions[j] = NULL; -#endif - } - } - SESSION_ROW_UNLOCK(&SessionCache[i]); - } -} - - -/* set ssl session timeout in seconds */ -WOLFSSL_ABI -int wolfSSL_set_timeout(WOLFSSL* ssl, unsigned int to) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (to == 0) - to = WOLFSSL_SESSION_TIMEOUT; - ssl->timeout = to; - - return WOLFSSL_SUCCESS; -} - - -/** - * Sets ctx session timeout in seconds. - * The timeout value set here should be reflected in the - * "session ticket lifetime hint" if this API works in the openssl compat-layer. - * Therefore wolfSSL_CTX_set_TicketHint is called internally. - * Arguments: - * - ctx WOLFSSL_CTX object which the timeout is set to - * - to timeout value in second - * Returns: - * WOLFSSL_SUCCESS on success, BAD_FUNC_ARG on failure. - * When WOLFSSL_ERROR_CODE_OPENSSL is defined, returns previous timeout value - * on success, BAD_FUNC_ARG on failure. - */ -WOLFSSL_ABI -int wolfSSL_CTX_set_timeout(WOLFSSL_CTX* ctx, unsigned int to) -{ - #if defined(WOLFSSL_ERROR_CODE_OPENSSL) - word32 prev_timeout = 0; - #endif - - int ret = WOLFSSL_SUCCESS; - (void)ret; - - if (ctx == NULL) - ret = BAD_FUNC_ARG; - - if (ret == WOLFSSL_SUCCESS) { - #if defined(WOLFSSL_ERROR_CODE_OPENSSL) - prev_timeout = ctx->timeout; - #endif - if (to == 0) { - ctx->timeout = WOLFSSL_SESSION_TIMEOUT; - } - else { - ctx->timeout = to; - } - } -#if defined(OPENSSL_EXTRA) && defined(HAVE_SESSION_TICKET) && \ - !defined(NO_WOLFSSL_SERVER) - if (ret == WOLFSSL_SUCCESS) { - if (to == 0) { - ret = wolfSSL_CTX_set_TicketHint(ctx, SESSION_TICKET_HINT_DEFAULT); - } - else { - ret = wolfSSL_CTX_set_TicketHint(ctx, to); - } - } -#endif /* OPENSSL_EXTRA && HAVE_SESSION_TICKET && !NO_WOLFSSL_SERVER */ - -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - if (ret == WOLFSSL_SUCCESS) { - return prev_timeout; - } - else { - return ret; - } -#else - return ret; -#endif /* WOLFSSL_ERROR_CODE_OPENSSL */ -} - - -#ifndef NO_CLIENT_CACHE - -/* Get Session from Client cache based on id/len, return NULL on failure */ -WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len) -{ - WOLFSSL_SESSION* ret = NULL; - word32 row; - int idx; - int count; - int error = 0; - ClientSession* clSess; - - WOLFSSL_ENTER("wolfSSL_GetSessionClient"); - - if (ssl->ctx->sessionCacheOff) { - WOLFSSL_MSG("Session Cache off"); - return NULL; - } - - if (ssl->options.side == WOLFSSL_SERVER_END) - return NULL; - - len = min(SERVER_ID_LEN, (word32)len); - - /* Do not access ssl->ctx->get_sess_cb from here. It is using a different - * set of ID's */ - - row = HashObject(id, len, &error) % CLIENT_SESSION_ROWS; - if (error != 0) { - WOLFSSL_MSG("Hash session failed"); - return NULL; - } - - if (wc_LockMutex(&clisession_mutex) != 0) { - WOLFSSL_MSG("Client cache mutex lock failed"); - return NULL; - } - - /* start from most recently used */ - count = min((word32)ClientCache[row].totalCount, CLIENT_SESSIONS_PER_ROW); - idx = ClientCache[row].nextIdx - 1; - if (idx < 0 || idx >= CLIENT_SESSIONS_PER_ROW) { - idx = CLIENT_SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */ - } - clSess = ClientCache[row].Clients; - - for (; count > 0; --count) { - WOLFSSL_SESSION* current; - SessionRow* sessRow; - - if (clSess[idx].serverRow >= SESSION_ROWS) { - WOLFSSL_MSG("Client cache serverRow invalid"); - break; - } - - /* lock row */ - sessRow = &SessionCache[clSess[idx].serverRow]; - if (SESSION_ROW_RD_LOCK(sessRow) != 0) { - WOLFSSL_MSG("Session cache row lock failure"); - break; - } - -#ifdef SESSION_CACHE_DYNAMIC_MEM - current = sessRow->Sessions[clSess[idx].serverIdx]; -#else - current = &sessRow->Sessions[clSess[idx].serverIdx]; -#endif - if (current && XMEMCMP(current->serverID, id, len) == 0) { - WOLFSSL_MSG("Found a serverid match for client"); - if (LowResTimer() < (current->bornOn + current->timeout)) { - WOLFSSL_MSG("Session valid"); - ret = current; - SESSION_ROW_UNLOCK(sessRow); - break; - } else { - WOLFSSL_MSG("Session timed out"); /* could have more for id */ - } - } else { - WOLFSSL_MSG("ServerID not a match from client table"); - } - SESSION_ROW_UNLOCK(sessRow); - - idx = idx > 0 ? idx - 1 : CLIENT_SESSIONS_PER_ROW - 1; - } - - wc_UnLockMutex(&clisession_mutex); - - return ret; -} - -#endif /* !NO_CLIENT_CACHE */ - -static int SslSessionCacheOff(const WOLFSSL* ssl, const WOLFSSL_SESSION* session) -{ - (void)session; - return ssl->options.sessionCacheOff - #if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_FORCE_CACHE_ON_TICKET) - && session->ticketLen == 0 - #endif - ; -} - -#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ - defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) -/** - * SessionTicketNoncePrealloc() - prealloc a buffer for ticket nonces - * @output: [in] pointer to WOLFSSL_SESSION object that will soon be a - * destination of a session duplication - * @buf: [out] address of the preallocated buf - * @len: [out] len of the preallocated buf - * - * prealloc a buffer that will likely suffice to contain a ticket nonce. It's - * used when copying session under lock, when syscalls need to be avoided. If - * output already has a dynamic buffer, it's reused. - */ -static int SessionTicketNoncePrealloc(byte** buf, byte* len, void *heap) -{ - (void)heap; - - *buf = (byte*)XMALLOC(PREALLOC_SESSION_TICKET_NONCE_LEN, heap, - DYNAMIC_TYPE_SESSION_TICK); - if (*buf == NULL) { - WOLFSSL_MSG("Failed to preallocate ticket nonce buffer"); - *len = 0; - return 1; - } - - *len = PREALLOC_SESSION_TICKET_NONCE_LEN; - return 0; -} -#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */ - -static int wolfSSL_DupSessionEx(const WOLFSSL_SESSION* input, - WOLFSSL_SESSION* output, int avoidSysCalls, byte* ticketNonceBuf, - byte* ticketNonceLen, byte* preallocUsed); - -void TlsSessionCacheUnlockRow(word32 row) -{ - SessionRow* sessRow; - - sessRow = &SessionCache[row]; - (void)sessRow; - SESSION_ROW_UNLOCK(sessRow); -} - -/* Don't use this function directly. Use TlsSessionCacheGetAndRdLock and - * TlsSessionCacheGetAndWrLock to fully utilize compiler const support. */ -static int TlsSessionCacheGetAndLock(const byte *id, - const WOLFSSL_SESSION **sess, word32 *lockedRow, byte readOnly, byte side) -{ - SessionRow *sessRow; - const WOLFSSL_SESSION *s; - word32 row; - int count; - int error; - int idx; - - *sess = NULL; - row = HashObject(id, ID_LEN, &error) % SESSION_ROWS; - if (error != 0) - return error; - sessRow = &SessionCache[row]; - if (readOnly) - error = SESSION_ROW_RD_LOCK(sessRow); - else - error = SESSION_ROW_WR_LOCK(sessRow); - if (error != 0) - return FATAL_ERROR; - - /* start from most recently used */ - count = min((word32)sessRow->totalCount, SESSIONS_PER_ROW); - idx = sessRow->nextIdx - 1; - if (idx < 0 || idx >= SESSIONS_PER_ROW) { - idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */ - } - for (; count > 0; --count) { -#ifdef SESSION_CACHE_DYNAMIC_MEM - s = sessRow->Sessions[idx]; -#else - s = &sessRow->Sessions[idx]; -#endif - if (s && XMEMCMP(s->sessionID, id, ID_LEN) == 0 && s->side == side) { - *sess = s; - break; - } - idx = idx > 0 ? idx - 1 : SESSIONS_PER_ROW - 1; - } - if (*sess == NULL) { - SESSION_ROW_UNLOCK(sessRow); - } - else { - *lockedRow = row; - } - - return 0; -} - -static int CheckSessionMatch(const WOLFSSL* ssl, const WOLFSSL_SESSION* sess) -{ - if (ssl == NULL || sess == NULL) - return 0; -#ifdef OPENSSL_EXTRA - if (ssl->sessionCtxSz > 0 && (ssl->sessionCtxSz != sess->sessionCtxSz || - XMEMCMP(ssl->sessionCtx, sess->sessionCtx, sess->sessionCtxSz) != 0)) - return 0; -#endif -#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) - if (IsAtLeastTLSv1_3(ssl->version) != IsAtLeastTLSv1_3(sess->version)) - return 0; -#endif - return 1; -} - -int TlsSessionCacheGetAndRdLock(const byte *id, const WOLFSSL_SESSION **sess, - word32 *lockedRow, byte side) -{ - return TlsSessionCacheGetAndLock(id, sess, lockedRow, 1, side); -} - -int TlsSessionCacheGetAndWrLock(const byte *id, WOLFSSL_SESSION **sess, - word32 *lockedRow, byte side) -{ - return TlsSessionCacheGetAndLock(id, (const WOLFSSL_SESSION**)sess, - lockedRow, 0, side); -} - -int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) -{ - const WOLFSSL_SESSION* sess = NULL; - const byte* id = NULL; - word32 row; - int error = 0; -#ifdef HAVE_SESSION_TICKET -#ifndef WOLFSSL_SMALL_STACK - byte tmpTicket[PREALLOC_SESSION_TICKET_LEN]; -#else - byte* tmpTicket = NULL; -#endif -#ifdef WOLFSSL_TLS13 - byte *preallocNonce = NULL; - byte preallocNonceLen = 0; - byte preallocNonceUsed = 0; -#endif /* WOLFSSL_TLS13 */ - byte tmpBufSet = 0; -#endif -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - WOLFSSL_X509* peer = NULL; -#endif - byte bogusID[ID_LEN]; - byte bogusIDSz = 0; - - WOLFSSL_ENTER("wolfSSL_GetSessionFromCache"); - - if (output == NULL) { - WOLFSSL_MSG("NULL output"); - return WOLFSSL_FAILURE; - } - - if (SslSessionCacheOff(ssl, ssl->session)) - return WOLFSSL_FAILURE; - - if (ssl->options.haveSessionId == 0 && !ssl->session->haveAltSessionID) - return WOLFSSL_FAILURE; - -#ifdef HAVE_SESSION_TICKET - if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1) - return WOLFSSL_FAILURE; -#endif - - XMEMSET(bogusID, 0, sizeof(bogusID)); - if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL - && !ssl->session->haveAltSessionID) - id = ssl->arrays->sessionID; - else if (ssl->session->haveAltSessionID) { - id = ssl->session->altSessionID; - /* We want to restore the bogus ID for TLS compatibility */ - if (output == ssl->session) { - XMEMCPY(bogusID, ssl->session->sessionID, ID_LEN); - bogusIDSz = ssl->session->sessionIDSz; - } - } - else - id = ssl->session->sessionID; - - -#ifdef HAVE_EXT_CACHE - if (ssl->ctx->get_sess_cb != NULL) { - int copy = 0; - int found = 0; - WOLFSSL_SESSION* extSess; - /* Attempt to retrieve the session from the external cache. */ - WOLFSSL_MSG("Calling external session cache"); - extSess = ssl->ctx->get_sess_cb(ssl, (byte*)id, ID_LEN, ©); - if ((extSess != NULL) - && CheckSessionMatch(ssl, extSess) - ) { - WOLFSSL_MSG("Session found in external cache"); - found = 1; - - error = wolfSSL_DupSession(extSess, output, 0); -#ifdef HAVE_EX_DATA - extSess->ownExData = 1; - output->ownExData = 0; -#endif - /* We want to restore the bogus ID for TLS compatibility */ - if (ssl->session->haveAltSessionID && - output == ssl->session) { - XMEMCPY(ssl->session->sessionID, bogusID, ID_LEN); - ssl->session->sessionIDSz = bogusIDSz; - } - } - /* If copy not set then free immediately */ - if (extSess != NULL && !copy) - wolfSSL_FreeSession(ssl->ctx, extSess); - if (found) - return error; - WOLFSSL_MSG("Session not found in external cache"); - } - - if (ssl->options.internalCacheLookupOff) { - WOLFSSL_MSG("Internal cache lookup turned off"); - return WOLFSSL_FAILURE; - } -#endif - -#ifdef HAVE_SESSION_TICKET - if (output->ticket == NULL || - output->ticketLenAlloc < PREALLOC_SESSION_TICKET_LEN) { -#ifdef WOLFSSL_SMALL_STACK - tmpTicket = (byte*)XMALLOC(PREALLOC_SESSION_TICKET_LEN, output->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (tmpTicket == NULL) { - WOLFSSL_MSG("tmpTicket malloc failed"); - return WOLFSSL_FAILURE; - } -#endif - if (output->ticketLenAlloc) - XFREE(output->ticket, output->heap, DYNAMIC_TYPE_SESSION_TICK); - output->ticket = tmpTicket; /* cppcheck-suppress autoVariables - */ - output->ticketLenAlloc = PREALLOC_SESSION_TICKET_LEN; - output->ticketLen = 0; - tmpBufSet = 1; - } -#endif - -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - if (output->peer != NULL) { - wolfSSL_X509_free(output->peer); - output->peer = NULL; - } -#endif - -#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \ - defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - if (output->ticketNonce.data != output->ticketNonce.dataStatic) { - XFREE(output->ticketNonce.data, output->heap, - DYNAMIC_TYPE_SESSION_TICK); - output->ticketNonce.data = output->ticketNonce.dataStatic; - output->ticketNonce.len = 0; - } - error = SessionTicketNoncePrealloc(&preallocNonce, &preallocNonceLen, - output->heap); - if (error != 0) { - if (tmpBufSet) { - output->ticket = output->staticTicket; - output->ticketLenAlloc = 0; - } -#ifdef WOLFSSL_SMALL_STACK - if (tmpTicket != NULL) - XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return WOLFSSL_FAILURE; - } -#endif /* WOLFSSL_TLS13 && HAVE_SESSION_TICKET*/ - - /* init to avoid clang static analyzer false positive */ - row = 0; - error = TlsSessionCacheGetAndRdLock(id, &sess, &row, (byte)ssl->options.side); - error = (error == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; - if (error != WOLFSSL_SUCCESS || sess == NULL) { - WOLFSSL_MSG("Get Session from cache failed"); - error = WOLFSSL_FAILURE; -#ifdef HAVE_SESSION_TICKET - if (tmpBufSet) { - output->ticket = output->staticTicket; - output->ticketLenAlloc = 0; - } -#ifdef WOLFSSL_TLS13 - if (preallocNonce != NULL) { - XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK); - preallocNonce = NULL; - } -#endif /* WOLFSSL_TLS13 */ -#ifdef WOLFSSL_SMALL_STACK - if (tmpTicket != NULL) { - XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); - tmpTicket = NULL; - } -#endif -#endif - } - else { - if (!CheckSessionMatch(ssl, sess)) { - WOLFSSL_MSG("Invalid session: can't be used in this context"); - TlsSessionCacheUnlockRow(row); - error = WOLFSSL_FAILURE; - } - else if (LowResTimer() >= (sess->bornOn + sess->timeout)) { - WOLFSSL_SESSION* wrSess = NULL; - WOLFSSL_MSG("Invalid session: timed out"); - sess = NULL; - TlsSessionCacheUnlockRow(row); - /* Attempt to get a write lock */ - error = TlsSessionCacheGetAndWrLock(id, &wrSess, &row, - (byte)ssl->options.side); - if (error == 0 && wrSess != NULL) { - EvictSessionFromCache(wrSess); - TlsSessionCacheUnlockRow(row); - } - error = WOLFSSL_FAILURE; - } - } - - /* mollify confused cppcheck nullPointer warning. */ - if (sess == NULL) - error = WOLFSSL_FAILURE; - - if (error == WOLFSSL_SUCCESS) { -#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) - error = wolfSSL_DupSessionEx(sess, output, 1, - preallocNonce, &preallocNonceLen, &preallocNonceUsed); -#else - error = wolfSSL_DupSession(sess, output, 1); -#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */ -#ifdef HAVE_EX_DATA - output->ownExData = !sess->ownExData; /* Session may own ex_data */ -#endif - TlsSessionCacheUnlockRow(row); - } - - /* We want to restore the bogus ID for TLS compatibility */ - if (ssl->session->haveAltSessionID && - output == ssl->session) { - XMEMCPY(ssl->session->sessionID, bogusID, ID_LEN); - ssl->session->sessionIDSz = bogusIDSz; - } - -#ifdef HAVE_SESSION_TICKET - if (tmpBufSet) { - if (error == WOLFSSL_SUCCESS) { - if (output->ticketLen > SESSION_TICKET_LEN) { - output->ticket = (byte*)XMALLOC(output->ticketLen, output->heap, - DYNAMIC_TYPE_SESSION_TICK); - if (output->ticket == NULL) { - error = WOLFSSL_FAILURE; - output->ticket = output->staticTicket; - output->ticketLenAlloc = 0; - output->ticketLen = 0; - } - } - else { - output->ticket = output->staticTicket; - output->ticketLenAlloc = 0; - } - } - else { - output->ticket = output->staticTicket; - output->ticketLenAlloc = 0; - output->ticketLen = 0; - } - if (error == WOLFSSL_SUCCESS) { - XMEMCPY(output->ticket, tmpTicket, output->ticketLen); - } - } -#ifdef WOLFSSL_SMALL_STACK - if (tmpTicket != NULL) - XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - if (error == WOLFSSL_SUCCESS && preallocNonceUsed) { - if (preallocNonceLen < PREALLOC_SESSION_TICKET_NONCE_LEN) { - /* buffer bigger than needed */ -#ifndef XREALLOC - output->ticketNonce.data = (byte*)XMALLOC(preallocNonceLen, - output->heap, DYNAMIC_TYPE_SESSION_TICK); - if (output->ticketNonce.data != NULL) - XMEMCPY(output->ticketNonce.data, preallocNonce, - preallocNonceLen); - XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK); - preallocNonce = NULL; -#else - output->ticketNonce.data = (byte*)XREALLOC(preallocNonce, - preallocNonceLen, output->heap, DYNAMIC_TYPE_SESSION_TICK); - if (output->ticketNonce.data != NULL) { - /* don't free the reallocated pointer */ - preallocNonce = NULL; - } -#endif /* !XREALLOC */ - if (output->ticketNonce.data == NULL) { - output->ticketNonce.data = output->ticketNonce.dataStatic; - output->ticketNonce.len = 0; - error = WOLFSSL_FAILURE; - /* preallocNonce will be free'd after the if */ - } - } - else { - output->ticketNonce.data = preallocNonce; - output->ticketNonce.len = preallocNonceLen; - preallocNonce = NULL; - } - } - if (preallocNonce != NULL) - XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK); -#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ - -#endif - -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - if (peer != NULL) { - wolfSSL_X509_free(peer); - } -#endif - - return error; -} - -WOLFSSL_SESSION* wolfSSL_GetSession(WOLFSSL* ssl, byte* masterSecret, - byte restoreSessionCerts) -{ - WOLFSSL_SESSION* ret = NULL; - - (void)restoreSessionCerts; /* Kept for compatibility */ - - if (wolfSSL_GetSessionFromCache(ssl, ssl->session) == WOLFSSL_SUCCESS) { - ret = ssl->session; - } - else { - WOLFSSL_MSG("wolfSSL_GetSessionFromCache did not return a session"); - } - - if (ret != NULL && masterSecret != NULL) - XMEMCPY(masterSecret, ret->masterSecret, SECRET_LEN); - - return ret; -} - -int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) -{ - SessionRow* sessRow = NULL; - int ret = WOLFSSL_SUCCESS; - - session = ClientSessionToSession(session); - - if (ssl == NULL || session == NULL || !session->isSetup) { - WOLFSSL_MSG("ssl or session NULL or not set up"); - return WOLFSSL_FAILURE; - } - - /* We need to lock the session as the first step if its in the cache */ - if (session->type == WOLFSSL_SESSION_TYPE_CACHE) { - if (session->cacheRow < SESSION_ROWS) { - sessRow = &SessionCache[session->cacheRow]; - if (SESSION_ROW_RD_LOCK(sessRow) != 0) { - WOLFSSL_MSG("Session row lock failed"); - return WOLFSSL_FAILURE; - } - } - } - - if (ret == WOLFSSL_SUCCESS && ssl->options.side != WOLFSSL_NEITHER_END && - (byte)ssl->options.side != session->side) { - WOLFSSL_MSG("Setting session for wrong role"); - ret = WOLFSSL_FAILURE; - } - - if (ret == WOLFSSL_SUCCESS) { - if (ssl->session == session) { - WOLFSSL_MSG("ssl->session and session same"); - } - else if (session->type != WOLFSSL_SESSION_TYPE_CACHE) { - if (wolfSSL_SESSION_up_ref(session) == WOLFSSL_SUCCESS) { - wolfSSL_FreeSession(ssl->ctx, ssl->session); - ssl->session = session; - } - else - ret = WOLFSSL_FAILURE; - } - else { - ret = wolfSSL_DupSession(session, ssl->session, 0); - if (ret != WOLFSSL_SUCCESS) - WOLFSSL_MSG("Session duplicate failed"); - } - } - - /* Let's copy over the altSessionID for local cache purposes */ - if (ret == WOLFSSL_SUCCESS && session->haveAltSessionID && - ssl->session != session) { - ssl->session->haveAltSessionID = 1; - XMEMCPY(ssl->session->altSessionID, session->altSessionID, ID_LEN); - } - - if (sessRow != NULL) { - SESSION_ROW_UNLOCK(sessRow); - sessRow = NULL; - } - - /* Note: the `session` variable cannot be used below, since the row is - * un-locked */ - - if (ret != WOLFSSL_SUCCESS) - return ret; - -#ifdef WOLFSSL_SESSION_ID_CTX - /* check for application context id */ - if (ssl->sessionCtxSz > 0) { - if (XMEMCMP(ssl->sessionCtx, ssl->session->sessionCtx, ssl->sessionCtxSz)) { - /* context id did not match! */ - WOLFSSL_MSG("Session context did not match"); - return WOLFSSL_FAILURE; - } - } -#endif /* WOLFSSL_SESSION_ID_CTX */ - - if (LowResTimer() >= (ssl->session->bornOn + ssl->session->timeout)) { -#if !defined(OPENSSL_EXTRA) || !defined(WOLFSSL_ERROR_CODE_OPENSSL) - return WOLFSSL_FAILURE; /* session timed out */ -#else /* defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) */ - WOLFSSL_MSG("Session is expired but return success for " - "OpenSSL compatibility"); -#endif - } - ssl->options.resuming = 1; - ssl->options.haveEMS = ssl->session->haveEMS; - -#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET)) - ssl->version = ssl->session->version; - if (IsAtLeastTLSv1_3(ssl->version)) - ssl->options.tls1_3 = 1; -#endif -#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ - (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) - ssl->options.cipherSuite0 = ssl->session->cipherSuite0; - ssl->options.cipherSuite = ssl->session->cipherSuite; -#endif -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - ssl->peerVerifyRet = (unsigned long)ssl->session->peerVerifyRet; -#endif - - return WOLFSSL_SUCCESS; -} - - -#ifdef WOLFSSL_SESSION_STATS -static int get_locked_session_stats(word32* active, word32* total, - word32* peak); -#endif - -#ifndef NO_CLIENT_CACHE -ClientSession* AddSessionToClientCache(int side, int row, int idx, byte* serverID, - word16 idLen, const byte* sessionID, - word16 useTicket) -{ - int error = -1; - word32 clientRow = 0, clientIdx = 0; - ClientSession* ret = NULL; - - (void)useTicket; - if (side == WOLFSSL_CLIENT_END - && row != INVALID_SESSION_ROW - && (idLen -#ifdef HAVE_SESSION_TICKET - || useTicket == 1 -#endif - || serverID != NULL - )) { - - WOLFSSL_MSG("Trying to add client cache entry"); - - if (idLen) { - clientRow = HashObject(serverID, - idLen, &error) % CLIENT_SESSION_ROWS; - } - else if (serverID != NULL) { - clientRow = HashObject(sessionID, - ID_LEN, &error) % CLIENT_SESSION_ROWS; - } - else { - error = -1; - } - if (error == 0 && wc_LockMutex(&clisession_mutex) == 0) { - clientIdx = ClientCache[clientRow].nextIdx; - if (clientIdx < CLIENT_SESSIONS_PER_ROW) { - ClientCache[clientRow].Clients[clientIdx].serverRow = - (word16)row; - ClientCache[clientRow].Clients[clientIdx].serverIdx = - (word16)idx; - if (sessionID != NULL) { - word32 sessionIDHash = HashObject(sessionID, ID_LEN, - &error); - if (error == 0) { - ClientCache[clientRow].Clients[clientIdx].sessionIDHash - = sessionIDHash; - } - } - } - else { - error = -1; - ClientCache[clientRow].nextIdx = 0; /* reset index as safety */ - WOLFSSL_MSG("Invalid client cache index! " - "Possible corrupted memory"); - } - if (error == 0) { - WOLFSSL_MSG("Adding client cache entry"); - - ret = &ClientCache[clientRow].Clients[clientIdx]; - - if (ClientCache[clientRow].totalCount < CLIENT_SESSIONS_PER_ROW) - ClientCache[clientRow].totalCount++; - ClientCache[clientRow].nextIdx++; - ClientCache[clientRow].nextIdx %= CLIENT_SESSIONS_PER_ROW; - } - - wc_UnLockMutex(&clisession_mutex); - } - else { - WOLFSSL_MSG("Hash session or lock failed"); - } - } - else { - WOLFSSL_MSG("Skipping client cache"); - } - - return ret; -} -#endif /* !NO_CLIENT_CACHE */ - -/** - * For backwards compatibility, this API needs to be used in *ALL* functions - * that access the WOLFSSL_SESSION members directly. - * - * This API checks if the passed in session is actually a ClientSession object - * and returns the matching session cache object. Otherwise just return the - * input. ClientSession objects only occur in the ClientCache. They are not - * allocated anywhere else. - */ -WOLFSSL_SESSION* ClientSessionToSession(const WOLFSSL_SESSION* session) -{ - WOLFSSL_ENTER("ClientSessionToSession"); -#ifdef NO_SESSION_CACHE_REF - return (WOLFSSL_SESSION*)session; -#else -#ifndef NO_CLIENT_CACHE - if (session == NULL) - return NULL; - /* Check if session points into ClientCache */ - if ((byte*)session >= (byte*)ClientCache && - /* Cast to byte* to make pointer arithmetic work per byte */ - (byte*)session < ((byte*)ClientCache) + sizeof(ClientCache)) { - ClientSession* clientSession = (ClientSession*)session; - SessionRow* sessRow = NULL; - WOLFSSL_SESSION* cacheSession = NULL; - word32 sessionIDHash = 0; - int error = 0; - session = NULL; /* Default to NULL for failure case */ - if (wc_LockMutex(&clisession_mutex) != 0) { - WOLFSSL_MSG("Client cache mutex lock failed"); - return NULL; - } - if (clientSession->serverRow >= SESSION_ROWS || - clientSession->serverIdx >= SESSIONS_PER_ROW) { - WOLFSSL_MSG("Client cache serverRow or serverIdx invalid"); - error = -1; - } - /* Prevent memory access before clientSession->serverRow and - * clientSession->serverIdx are sanitized. */ - XFENCE(); - if (error == 0) { - /* Lock row */ - sessRow = &SessionCache[clientSession->serverRow]; - error = SESSION_ROW_RD_LOCK(sessRow); - if (error != 0) { - WOLFSSL_MSG("Session cache row lock failure"); - sessRow = NULL; - } - } - if (error == 0) { -#ifdef SESSION_CACHE_DYNAMIC_MEM - cacheSession = sessRow->Sessions[clientSession->serverIdx]; -#else - cacheSession = &sessRow->Sessions[clientSession->serverIdx]; -#endif - if (cacheSession && cacheSession->sessionIDSz == 0) { - cacheSession = NULL; - WOLFSSL_MSG("Session cache entry not set"); - error = -1; - } - } - if (error == 0) { - /* Calculate the hash of the session ID */ - sessionIDHash = HashObject(cacheSession->sessionID, ID_LEN, - &error); - } - if (error == 0) { - /* Check the session ID hash matches */ - error = clientSession->sessionIDHash != sessionIDHash; - if (error != 0) - WOLFSSL_MSG("session ID hash don't match"); - } - if (error == 0) { - /* Hashes match */ - session = cacheSession; - WOLFSSL_MSG("Found session cache matching client session object"); - } - if (sessRow != NULL) { - SESSION_ROW_UNLOCK(sessRow); - } - wc_UnLockMutex(&clisession_mutex); - return (WOLFSSL_SESSION*)session; - } - else { - /* Plain WOLFSSL_SESSION object */ - return (WOLFSSL_SESSION*)session; - } -#else - return (WOLFSSL_SESSION*)session; -#endif -#endif -} - -int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, - const byte* id, byte idSz, int* sessionIndex, int side, - word16 useTicket, ClientSession** clientCacheEntry) -{ - WOLFSSL_SESSION* cacheSession = NULL; - SessionRow* sessRow = NULL; - word32 idx = 0; -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - WOLFSSL_X509* cachePeer = NULL; - WOLFSSL_X509* addPeer = NULL; -#endif -#ifdef HAVE_SESSION_TICKET - byte* cacheTicBuff = NULL; - byte ticBuffUsed = 0; - byte* ticBuff = NULL; - int ticLen = 0; -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - byte *preallocNonce = NULL; - byte preallocNonceLen = 0; - byte preallocNonceUsed = 0; - byte *toFree = NULL; -#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC */ -#endif /* HAVE_SESSION_TICKET */ - int ret = 0; - int row; - int i; - int overwrite = 0; - (void)ctx; - (void)sessionIndex; - (void)useTicket; - (void)clientCacheEntry; - - WOLFSSL_ENTER("AddSessionToCache"); - - if (idSz == 0) { - WOLFSSL_MSG("AddSessionToCache idSz == 0"); - return BAD_FUNC_ARG; - } - - addSession = ClientSessionToSession(addSession); - if (addSession == NULL) { - WOLFSSL_MSG("AddSessionToCache is NULL"); - return MEMORY_E; - } - -#ifdef HAVE_SESSION_TICKET - ticLen = addSession->ticketLen; - /* Alloc Memory here to avoid syscalls during lock */ - if (ticLen > SESSION_TICKET_LEN) { - ticBuff = (byte*)XMALLOC(ticLen, NULL, - DYNAMIC_TYPE_SESSION_TICK); - if (ticBuff == NULL) { - return MEMORY_E; - } - } -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - if (addSession->ticketNonce.data != addSession->ticketNonce.dataStatic) { - /* use the AddSession->heap even if the buffer maybe saved in - * CachedSession objects. CachedSession heap and AddSession heap should - * be the same */ - preallocNonce = (byte*)XMALLOC(addSession->ticketNonce.len, - addSession->heap, DYNAMIC_TYPE_SESSION_TICK); - if (preallocNonce == NULL) { - if (ticBuff != NULL) - XFREE(ticBuff, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); - return MEMORY_E; - } - preallocNonceLen = addSession->ticketNonce.len; - } -#endif /* WOLFSSL_TLS13 && WOLFSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3) */ -#endif /* HAVE_SESSION_TICKET */ - - /* Find a position for the new session in cache and use that */ - /* Use the session object in the cache for external cache if required */ - row = (int)(HashObject(id, ID_LEN, &ret) % SESSION_ROWS); - if (ret != 0) { - WOLFSSL_MSG("Hash session failed"); - #ifdef HAVE_SESSION_TICKET - XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); - #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) - XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); - #endif - #endif - return ret; - } - - sessRow = &SessionCache[row]; - if (SESSION_ROW_WR_LOCK(sessRow) != 0) { - #ifdef HAVE_SESSION_TICKET - XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); - #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) - XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); - #endif - #endif - WOLFSSL_MSG("Session row lock failed"); - return BAD_MUTEX_E; - } - - for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) { -#ifdef SESSION_CACHE_DYNAMIC_MEM - cacheSession = sessRow->Sessions[i]; -#else - cacheSession = &sessRow->Sessions[i]; -#endif - if (cacheSession && XMEMCMP(id, - cacheSession->sessionID, ID_LEN) == 0 && - cacheSession->side == side) { - WOLFSSL_MSG("Session already exists. Overwriting."); - overwrite = 1; - idx = i; - break; - } - } - - if (!overwrite) - idx = sessRow->nextIdx; -#ifdef SESSION_INDEX - if (sessionIndex != NULL) - *sessionIndex = (row << SESSIDX_ROW_SHIFT) | idx; -#endif - -#ifdef SESSION_CACHE_DYNAMIC_MEM - cacheSession = sessRow->Sessions[idx]; - if (cacheSession == NULL) { - cacheSession = (WOLFSSL_SESSION*) XMALLOC(sizeof(WOLFSSL_SESSION), - sessRow->heap, DYNAMIC_TYPE_SESSION); - if (cacheSession == NULL) { - #ifdef HAVE_SESSION_TICKET - XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); - #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) - XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); - #endif - #endif - SESSION_ROW_UNLOCK(sessRow); - return MEMORY_E; - } - XMEMSET(cacheSession, 0, sizeof(WOLFSSL_SESSION)); - sessRow->Sessions[idx] = cacheSession; - } -#else - cacheSession = &sessRow->Sessions[idx]; -#endif - -#ifdef HAVE_EX_DATA - if (overwrite) { - /* Figure out who owns the ex_data */ - if (cacheSession->ownExData) { - /* Prioritize cacheSession copy */ - XMEMCPY(&addSession->ex_data, &cacheSession->ex_data, - sizeof(WOLFSSL_CRYPTO_EX_DATA)); - } - /* else will be copied in wolfSSL_DupSession call */ - } - else if (cacheSession->ownExData) { - crypto_ex_cb_free_data(cacheSession, crypto_ex_cb_ctx_session, - &cacheSession->ex_data); - cacheSession->ownExData = 0; - } -#endif - - if (!overwrite) - EvictSessionFromCache(cacheSession); - - cacheSession->type = WOLFSSL_SESSION_TYPE_CACHE; - cacheSession->cacheRow = row; - -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - /* Save the peer field to free after unlocking the row */ - if (cacheSession->peer != NULL) - cachePeer = cacheSession->peer; - cacheSession->peer = NULL; -#endif -#ifdef HAVE_SESSION_TICKET - /* If we can reuse the existing buffer in cacheSession then we won't touch - * ticBuff at all making it a very cheap malloc/free. The page on a modern - * OS will most likely not even be allocated to the process. */ - if (ticBuff != NULL && cacheSession->ticketLenAlloc < ticLen) { - /* Save pointer only if separately allocated */ - if (cacheSession->ticket != cacheSession->staticTicket) - cacheTicBuff = cacheSession->ticket; - ticBuffUsed = 1; - cacheSession->ticket = ticBuff; - cacheSession->ticketLenAlloc = (word16) ticLen; - } -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - /* cache entry never used */ - if (cacheSession->ticketNonce.data == NULL) - cacheSession->ticketNonce.data = cacheSession->ticketNonce.dataStatic; - - if (cacheSession->ticketNonce.data != - cacheSession->ticketNonce.dataStatic) { - toFree = cacheSession->ticketNonce.data; - cacheSession->ticketNonce.data = cacheSession->ticketNonce.dataStatic; - cacheSession->ticketNonce.len = 0; - } -#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ -#endif -#ifdef SESSION_CERTS - if (overwrite && - addSession->chain.count == 0 && - cacheSession->chain.count > 0) { - /* Copy in the certs from the session */ - addSession->chain.count = cacheSession->chain.count; - XMEMCPY(addSession->chain.certs, cacheSession->chain.certs, - sizeof(x509_buffer) * cacheSession->chain.count); - } -#endif /* SESSION_CERTS */ -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - /* Don't copy the peer cert into cache */ - addPeer = addSession->peer; - addSession->peer = NULL; -#endif - cacheSession->heap = NULL; - /* Copy data into the cache object */ -#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ - defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - ret = wolfSSL_DupSessionEx(addSession, cacheSession, 1, preallocNonce, - &preallocNonceLen, &preallocNonceUsed) == WOLFSSL_FAILURE; -#else - ret = wolfSSL_DupSession(addSession, cacheSession, 1) == WOLFSSL_FAILURE; -#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC - && FIPS_VERSION_GE(5,3)*/ -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - addSession->peer = addPeer; -#endif - - if (ret == 0) { - if (!overwrite) { - /* Increment the totalCount and the nextIdx */ - if (sessRow->totalCount < SESSIONS_PER_ROW) - sessRow->totalCount++; - sessRow->nextIdx = (sessRow->nextIdx + 1) % SESSIONS_PER_ROW; - } - if (id != addSession->sessionID) { - /* ssl->session->sessionID may contain the bogus ID or we want the - * ID from the arrays object */ - XMEMCPY(cacheSession->sessionID, id, ID_LEN); - cacheSession->sessionIDSz = ID_LEN; - } -#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) - if (ctx->rem_sess_cb != NULL) - cacheSession->rem_sess_cb = ctx->rem_sess_cb; -#endif -#ifdef HAVE_EX_DATA - /* The session in cache now owns the ex_data */ - addSession->ownExData = 0; - cacheSession->ownExData = 1; -#endif -#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ - defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - if (preallocNonce != NULL && preallocNonceUsed) { - cacheSession->ticketNonce.data = preallocNonce; - cacheSession->ticketNonce.len = preallocNonceLen; - preallocNonce = NULL; - preallocNonceLen = 0; - } -#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC - * && FIPS_VERSION_GE(5,3)*/ - } -#ifdef HAVE_SESSION_TICKET - else if (ticBuffUsed) { - /* Error occurred. Need to clean up the ticket buffer. */ - cacheSession->ticket = cacheSession->staticTicket; - cacheSession->ticketLenAlloc = 0; - cacheSession->ticketLen = 0; - } -#endif - SESSION_ROW_UNLOCK(sessRow); - cacheSession = NULL; /* Can't access after unlocked */ - -#ifndef NO_CLIENT_CACHE - if (ret == 0 && clientCacheEntry != NULL) { - ClientSession* clientCache = AddSessionToClientCache(side, row, idx, - addSession->serverID, addSession->idLen, id, useTicket); - if (clientCache != NULL) - *clientCacheEntry = clientCache; - } -#endif - -#ifdef HAVE_SESSION_TICKET - if (ticBuff != NULL && !ticBuffUsed) - XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); - XFREE(cacheTicBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); - XFREE(toFree, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); -#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ -#endif - -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - if (cachePeer != NULL) { - wolfSSL_X509_free(cachePeer); - cachePeer = NULL; /* Make sure not use after this point */ - } -#endif - - return ret; -} - -void AddSession(WOLFSSL* ssl) -{ - int error = 0; - const byte* id = NULL; - byte idSz = 0; - WOLFSSL_SESSION* session = ssl->session; - - (void)error; - - WOLFSSL_ENTER("AddSession"); - - if (SslSessionCacheOff(ssl, session)) { - WOLFSSL_MSG("Cache off"); - return; - } - - if (session->haveAltSessionID) { - id = session->altSessionID; - idSz = ID_LEN; - } - else { - id = session->sessionID; - idSz = session->sessionIDSz; - } - - /* Do this only for the client because if the server doesn't have an ID at - * this point, it won't on resumption. */ - if (idSz == 0 && ssl->options.side == WOLFSSL_CLIENT_END) { - WC_RNG* rng = NULL; - if (ssl->rng != NULL) - rng = ssl->rng; -#if defined(HAVE_GLOBAL_RNG) && defined(OPENSSL_EXTRA) - else if (initGlobalRNG == 1 || wolfSSL_RAND_Init() == WOLFSSL_SUCCESS) { - rng = &globalRNG; - } -#endif - if (wc_RNG_GenerateBlock(rng, ssl->session->altSessionID, - ID_LEN) != 0) - return; - ssl->session->haveAltSessionID = 1; - id = ssl->session->altSessionID; - idSz = ID_LEN; - } - -#ifdef HAVE_EXT_CACHE - if (!ssl->options.internalCacheOff) -#endif - { - /* Try to add the session to internal cache or external cache - if a new_sess_cb is set. Its ok if we don't succeed. */ - (void)AddSessionToCache(ssl->ctx, session, id, idSz, -#ifdef SESSION_INDEX - &ssl->sessionIndex, -#else - NULL, -#endif - ssl->options.side, -#ifdef HAVE_SESSION_TICKET - ssl->options.useTicket, -#else - 0, -#endif -#ifdef NO_SESSION_CACHE_REF - NULL -#else - (ssl->options.side == WOLFSSL_CLIENT_END) ? - &ssl->clientSession : NULL -#endif - ); - } - -#ifdef HAVE_EXT_CACHE - if (error == 0 && ssl->ctx->new_sess_cb != NULL) { - int cbRet = 0; - wolfSSL_SESSION_up_ref(session); - cbRet = ssl->ctx->new_sess_cb(ssl, session); - if (cbRet == 0) - wolfSSL_FreeSession(ssl->ctx, session); - } -#endif - -#if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) - if (error == 0) { - word32 active = 0; - - error = get_locked_session_stats(&active, NULL, NULL); - if (error == WOLFSSL_SUCCESS) { - error = 0; /* back to this function ok */ - - if (PeakSessions < active) { - PeakSessions = active; - } - } - } -#endif /* WOLFSSL_SESSION_STATS && WOLFSSL_PEAK_SESSIONS */ - (void)error; -} - - -#ifdef SESSION_INDEX - -int wolfSSL_GetSessionIndex(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_GetSessionIndex"); - WOLFSSL_LEAVE("wolfSSL_GetSessionIndex", ssl->sessionIndex); - return ssl->sessionIndex; -} - - -int wolfSSL_GetSessionAtIndex(int idx, WOLFSSL_SESSION* session) -{ - int row, col, result = WOLFSSL_FAILURE; - SessionRow* sessRow; - WOLFSSL_SESSION* cacheSession; - - WOLFSSL_ENTER("wolfSSL_GetSessionAtIndex"); - - session = ClientSessionToSession(session); - - row = idx >> SESSIDX_ROW_SHIFT; - col = idx & SESSIDX_IDX_MASK; - - if (session == NULL || - row < 0 || row >= SESSION_ROWS || col >= SESSIONS_PER_ROW) { - return WOLFSSL_FAILURE; - } - - sessRow = &SessionCache[row]; - if (SESSION_ROW_RD_LOCK(sessRow) != 0) { - return BAD_MUTEX_E; - } - -#ifdef SESSION_CACHE_DYNAMIC_MEM - cacheSession = sessRow->Sessions[col]; -#else - cacheSession = &sessRow->Sessions[col]; -#endif - if (cacheSession) { - XMEMCPY(session, cacheSession, sizeof(WOLFSSL_SESSION)); - result = WOLFSSL_SUCCESS; - } - else { - result = WOLFSSL_FAILURE; - } - - SESSION_ROW_UNLOCK(sessRow); - - WOLFSSL_LEAVE("wolfSSL_GetSessionAtIndex", result); - return result; -} - -#endif /* SESSION_INDEX */ - -#if defined(SESSION_CERTS) - -WOLFSSL_X509_CHAIN* wolfSSL_SESSION_get_peer_chain(WOLFSSL_SESSION* session) -{ - WOLFSSL_X509_CHAIN* chain = NULL; - - WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain"); - - session = ClientSessionToSession(session); - - if (session) - chain = &session->chain; - - WOLFSSL_LEAVE("wolfSSL_SESSION_get_peer_chain", chain ? 1 : 0); - return chain; -} - - -#ifdef OPENSSL_EXTRA -/* gets the peer certificate associated with the session passed in - * returns null on failure, the caller should not free the returned pointer */ -WOLFSSL_X509* wolfSSL_SESSION_get0_peer(WOLFSSL_SESSION* session) -{ - WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain"); - - session = ClientSessionToSession(session); - if (session) { - int count; - - count = wolfSSL_get_chain_count(&session->chain); - if (count < 1 || count >= MAX_CHAIN_DEPTH) { - WOLFSSL_MSG("bad count found"); - return NULL; - } - - if (session->peer == NULL) { - session->peer = wolfSSL_get_chain_X509(&session->chain, 0); - } - return session->peer; - } - WOLFSSL_MSG("No session passed in"); - - return NULL; -} -#endif /* OPENSSL_EXTRA */ -#endif /* SESSION_INDEX && SESSION_CERTS */ - - -#ifdef WOLFSSL_SESSION_STATS - -static int get_locked_session_stats(word32* active, word32* total, word32* peak) -{ - int result = WOLFSSL_SUCCESS; - int i; - int count; - int idx; - word32 now = 0; - word32 seen = 0; - word32 ticks = LowResTimer(); - - WOLFSSL_ENTER("get_locked_session_stats"); - -#ifndef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_RD_LOCK(&SessionCache[0]); -#endif - for (i = 0; i < SESSION_ROWS; i++) { - SessionRow* row = &SessionCache[i]; - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - if (SESSION_ROW_RD_LOCK(row) != 0) { - WOLFSSL_MSG("Session row cache mutex lock failed"); - return BAD_MUTEX_E; - } - #endif - - seen += row->totalCount; - - if (active == NULL) { - SESSION_ROW_UNLOCK(row); - continue; - } - - count = min((word32)row->totalCount, SESSIONS_PER_ROW); - idx = row->nextIdx - 1; - if (idx < 0 || idx >= SESSIONS_PER_ROW) { - idx = SESSIONS_PER_ROW - 1; /* if back to front previous was end */ - } - - for (; count > 0; --count) { - /* if not expired then good */ -#ifdef SESSION_CACHE_DYNAMIC_MEM - if (row->Sessions[idx] && - ticks < (row->Sessions[idx]->bornOn + - row->Sessions[idx]->timeout) ) -#else - if (ticks < (row->Sessions[idx].bornOn + - row->Sessions[idx].timeout) ) -#endif - { - now++; - } - - idx = idx > 0 ? idx - 1 : SESSIONS_PER_ROW - 1; - } - - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_UNLOCK(row); - #endif - } -#ifndef ENABLE_SESSION_CACHE_ROW_LOCK - SESSION_ROW_UNLOCK(&SessionCache[0]); -#endif - - if (active) { - *active = now; - } - if (total) { - *total = seen; - } - -#ifdef WOLFSSL_PEAK_SESSIONS - if (peak) { - *peak = PeakSessions; - } -#else - (void)peak; -#endif - - WOLFSSL_LEAVE("get_locked_session_stats", result); - - return result; -} - - -/* return WOLFSSL_SUCCESS on ok */ -int wolfSSL_get_session_stats(word32* active, word32* total, word32* peak, - word32* maxSessions) -{ - int result = WOLFSSL_SUCCESS; - - WOLFSSL_ENTER("wolfSSL_get_session_stats"); - - if (maxSessions) { - *maxSessions = SESSIONS_PER_ROW * SESSION_ROWS; - - if (active == NULL && total == NULL && peak == NULL) - return result; /* we're done */ - } - - /* user must provide at least one query value */ - if (active == NULL && total == NULL && peak == NULL) { - return BAD_FUNC_ARG; - } - - result = get_locked_session_stats(active, total, peak); - - WOLFSSL_LEAVE("wolfSSL_get_session_stats", result); - - return result; -} - -#endif /* WOLFSSL_SESSION_STATS */ - - - #ifdef PRINT_SESSION_STATS - - /* WOLFSSL_SUCCESS on ok */ - int wolfSSL_PrintSessionStats(void) - { - word32 totalSessionsSeen = 0; - word32 totalSessionsNow = 0; - word32 peak = 0; - word32 maxSessions = 0; - int i; - int ret; - double E; /* expected freq */ - double chiSquare = 0; - - ret = wolfSSL_get_session_stats(&totalSessionsNow, &totalSessionsSeen, - &peak, &maxSessions); - if (ret != WOLFSSL_SUCCESS) - return ret; - printf("Total Sessions Seen = %u\n", totalSessionsSeen); - printf("Total Sessions Now = %u\n", totalSessionsNow); -#ifdef WOLFSSL_PEAK_SESSIONS - printf("Peak Sessions = %u\n", peak); -#endif - printf("Max Sessions = %u\n", maxSessions); - - E = (double)totalSessionsSeen / SESSION_ROWS; - - for (i = 0; i < SESSION_ROWS; i++) { - double diff = SessionCache[i].totalCount - E; - diff *= diff; /* square */ - diff /= E; /* normalize */ - - chiSquare += diff; - } - printf(" chi-square = %5.1f, d.f. = %d\n", chiSquare, - SESSION_ROWS - 1); - #if (SESSION_ROWS == 11) - printf(" .05 p value = 18.3, chi-square should be less\n"); - #elif (SESSION_ROWS == 211) - printf(".05 p value = 244.8, chi-square should be less\n"); - #elif (SESSION_ROWS == 5981) - printf(".05 p value = 6161.0, chi-square should be less\n"); - #elif (SESSION_ROWS == 3) - printf(".05 p value = 6.0, chi-square should be less\n"); - #elif (SESSION_ROWS == 2861) - printf(".05 p value = 2985.5, chi-square should be less\n"); - #endif - printf("\n"); - - return ret; - } - - #endif /* SESSION_STATS */ - -#else /* NO_SESSION_CACHE */ - -WOLFSSL_SESSION* ClientSessionToSession(const WOLFSSL_SESSION* session) -{ - return (WOLFSSL_SESSION*)session; -} - -/* No session cache version */ -WOLFSSL_SESSION* wolfSSL_GetSession(WOLFSSL* ssl, byte* masterSecret, - byte restoreSessionCerts) -{ - (void)ssl; - (void)masterSecret; - (void)restoreSessionCerts; - - return NULL; -} - -#endif /* NO_SESSION_CACHE */ - /* call before SSL_connect, if verifying will add name check to date check and signature check */ @@ -16463,630 +10681,7 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #endif /* HAVE_ANON */ - #ifndef NO_CERTS -/* used to be defined on NO_FILESYSTEM only, but are generally useful */ - - int wolfSSL_CTX_load_verify_buffer_ex(WOLFSSL_CTX* ctx, - const unsigned char* in, - long sz, int format, int userChain, - word32 flags) - { - int verify; - int ret = WOLFSSL_FAILURE; - - WOLFSSL_ENTER("wolfSSL_CTX_load_verify_buffer_ex"); - - verify = GET_VERIFY_SETTING_CTX(ctx); - if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) - verify = VERIFY_SKIP_DATE; - - if (format == WOLFSSL_FILETYPE_PEM) - ret = ProcessChainBuffer(ctx, in, sz, format, CA_TYPE, NULL, - verify); - else - ret = ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL, NULL, - userChain, verify); -#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS) - if (ret == WOLFSSL_SUCCESS) - ret = wolfSSL_CTX_trust_peer_buffer(ctx, in, sz, format); -#endif - - WOLFSSL_LEAVE("wolfSSL_CTX_load_verify_buffer_ex", ret); - return ret; - } - - /* wolfSSL extension allows DER files to be loaded from buffers as well */ - int wolfSSL_CTX_load_verify_buffer(WOLFSSL_CTX* ctx, - const unsigned char* in, - long sz, int format) - { - return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 0, - WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); - } - - int wolfSSL_CTX_load_verify_chain_buffer_format(WOLFSSL_CTX* ctx, - const unsigned char* in, - long sz, int format) - { - return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 1, - WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); - } - - -#ifdef WOLFSSL_TRUST_PEER_CERT - int wolfSSL_CTX_trust_peer_buffer(WOLFSSL_CTX* ctx, - const unsigned char* in, - long sz, int format) - { - int verify; - WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_buffer"); - - /* sanity check on arguments */ - if (sz < 0 || in == NULL || ctx == NULL) { - return BAD_FUNC_ARG; - } - - #if (WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) - verify = VERIFY_SKIP_DATE; - #else - verify = GET_VERIFY_SETTING_CTX(ctx); - #endif - - if (format == WOLFSSL_FILETYPE_PEM) - return ProcessChainBuffer(ctx, in, sz, format, TRUSTED_PEER_TYPE, - NULL, verify); - else - return ProcessBuffer(ctx, in, sz, format, TRUSTED_PEER_TYPE, NULL, - NULL, 0, verify); - } -#endif /* WOLFSSL_TRUST_PEER_CERT */ - - - int wolfSSL_CTX_use_certificate_buffer(WOLFSSL_CTX* ctx, - const unsigned char* in, long sz, int format) - { - int ret = WOLFSSL_FAILURE; - - WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_buffer"); - ret = ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 0, - GET_VERIFY_SETTING_CTX(ctx)); - WOLFSSL_LEAVE("wolfSSL_CTX_use_certificate_buffer", ret); - return ret; - } - - - int wolfSSL_CTX_use_PrivateKey_buffer(WOLFSSL_CTX* ctx, - const unsigned char* in, long sz, int format) - { - int ret = WOLFSSL_FAILURE; - long consumed = 0; - - WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_buffer"); - ret = ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL, - &consumed, 0, GET_VERIFY_SETTING_CTX(ctx)); - - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (ret == WOLFSSL_SUCCESS && consumed < sz) { - /* When support for dual algorithm certificates is enabled, the - * buffer may contain both the primary and the alternative - * private key. Hence, we have to parse both of them. - */ - ret = ProcessBuffer(ctx, in + consumed, sz - consumed, format, - ALT_PRIVATEKEY_TYPE, NULL, NULL, 0, - GET_VERIFY_SETTING_CTX(ctx)); - } - #endif - - WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_buffer", ret); - return ret; - } - - -#ifdef WOLFSSL_DUAL_ALG_CERTS - int wolfSSL_CTX_use_AltPrivateKey_buffer(WOLFSSL_CTX* ctx, - const unsigned char* in, long sz, int format) - { - int ret = WOLFSSL_FAILURE; - - WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_buffer"); - ret = ProcessBuffer(ctx, in, sz, format, ALT_PRIVATEKEY_TYPE, NULL, - NULL, 0, GET_VERIFY_SETTING_CTX(ctx)); - WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_buffer", ret); - return ret; - } -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - - -#ifdef WOLF_PRIVATE_KEY_ID - int wolfSSL_CTX_use_PrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id, - long sz, int devId, long keySz) - { - int ret = wolfSSL_CTX_use_PrivateKey_Id(ctx, id, sz, devId); - - if (ret == WOLFSSL_SUCCESS) - ctx->privateKeySz = (word32)keySz; - - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (ret == WOLFSSL_SUCCESS) - /* Set the ID for the alternative key, too. User can still - * override that afterwards. */ - ret = wolfSSL_CTX_use_AltPrivateKey_id(ctx, id, sz, devId, keySz); - #endif - - return ret; - } - - int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, - long sz, int devId) - { - int ret = WOLFSSL_FAILURE; - - FreeDer(&ctx->privateKey); - if (AllocDer(&ctx->privateKey, (word32)sz, PRIVATEKEY_TYPE, - ctx->heap) == 0) { - XMEMCPY(ctx->privateKey->buffer, id, sz); - ctx->privateKeyId = 1; - if (devId != INVALID_DEVID) - ctx->privateKeyDevId = devId; - else - ctx->privateKeyDevId = ctx->devId; - - ret = WOLFSSL_SUCCESS; - } - - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (ret == WOLFSSL_SUCCESS) - /* Set the ID for the alternative key, too. User can still - * override that afterwards. */ - ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId); - #endif - - return ret; - } - - int wolfSSL_CTX_use_PrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, - int devId) - { - int ret = WOLFSSL_FAILURE; - word32 sz = (word32)XSTRLEN(label) + 1; - - FreeDer(&ctx->privateKey); - if (AllocDer(&ctx->privateKey, (word32)sz, PRIVATEKEY_TYPE, - ctx->heap) == 0) { - XMEMCPY(ctx->privateKey->buffer, label, sz); - ctx->privateKeyLabel = 1; - if (devId != INVALID_DEVID) - ctx->privateKeyDevId = devId; - else - ctx->privateKeyDevId = ctx->devId; - - ret = WOLFSSL_SUCCESS; - } - - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (ret == WOLFSSL_SUCCESS) - /* Set the label for the alternative key, too. User can still - * override that afterwards. */ - ret = wolfSSL_CTX_use_AltPrivateKey_Label(ctx, label, devId); - #endif - - return ret; - } -#endif /* WOLF_PRIVATE_KEY_ID */ - -#if defined(WOLF_PRIVATE_KEY_ID) && defined(WOLFSSL_DUAL_ALG_CERTS) - int wolfSSL_CTX_use_AltPrivateKey_id(WOLFSSL_CTX* ctx, - const unsigned char* id, - long sz, int devId, long keySz) - { - int ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId); - - if (ret == WOLFSSL_SUCCESS) - ctx->altPrivateKeySz = (word32)keySz; - - return ret; - } - - int wolfSSL_CTX_use_AltPrivateKey_Id(WOLFSSL_CTX* ctx, - const unsigned char* id, - long sz, int devId) - { - int ret = WOLFSSL_FAILURE; - - if (ctx == NULL || id == NULL) { - return ret; - } - - FreeDer(&ctx->altPrivateKey); - if (AllocDer(&ctx->altPrivateKey, (word32)sz, ALT_PRIVATEKEY_TYPE, - ctx->heap) == 0) { - XMEMCPY(ctx->altPrivateKey->buffer, id, sz); - ctx->altPrivateKeyId = 1; - if (devId != INVALID_DEVID) - ctx->altPrivateKeyDevId = devId; - else - ctx->altPrivateKeyDevId = ctx->devId; - - ret = WOLFSSL_SUCCESS; - } - - return ret; - } - - int wolfSSL_CTX_use_AltPrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, - int devId) - { - int ret = WOLFSSL_FAILURE; - word32 sz; - - if (ctx == NULL || label == NULL) { - return ret; - } - - sz = (word32)XSTRLEN(label) + 1; - FreeDer(&ctx->altPrivateKey); - if (AllocDer(&ctx->altPrivateKey, (word32)sz, ALT_PRIVATEKEY_TYPE, - ctx->heap) == 0) { - XMEMCPY(ctx->altPrivateKey->buffer, label, sz); - ctx->altPrivateKeyLabel = 1; - if (devId != INVALID_DEVID) - ctx->altPrivateKeyDevId = devId; - else - ctx->altPrivateKeyDevId = ctx->devId; - - ret = WOLFSSL_SUCCESS; - } - - return ret; - } -#endif /* WOLF_PRIVATE_KEY_ID && WOLFSSL_DUAL_ALG_CERTS */ - - int wolfSSL_CTX_use_certificate_chain_buffer_format(WOLFSSL_CTX* ctx, - const unsigned char* in, long sz, int format) - { - WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_buffer_format"); - return ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 1, - GET_VERIFY_SETTING_CTX(ctx)); - } - - int wolfSSL_CTX_use_certificate_chain_buffer(WOLFSSL_CTX* ctx, - const unsigned char* in, long sz) - { - return wolfSSL_CTX_use_certificate_chain_buffer_format(ctx, in, sz, - WOLFSSL_FILETYPE_PEM); - } - - -#ifndef NO_DH - - /* server wrapper for ctx or ssl Diffie-Hellman parameters */ - static int wolfSSL_SetTmpDH_buffer_wrapper(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - const unsigned char* buf, - long sz, int format) - { - DerBuffer* der = NULL; - int ret = 0; - word32 pSz = MAX_DH_SIZE; - word32 gSz = MAX_DH_SIZE; - #ifdef WOLFSSL_SMALL_STACK - byte* p = NULL; - byte* g = NULL; - #else - byte p[MAX_DH_SIZE]; - byte g[MAX_DH_SIZE]; - #endif - - if (ctx == NULL || buf == NULL) - return BAD_FUNC_ARG; - - ret = AllocDer(&der, 0, DH_PARAM_TYPE, ctx->heap); - if (ret != 0) { - return ret; - } - der->buffer = (byte*)buf; - der->length = (word32)sz; - - #ifdef WOLFSSL_SMALL_STACK - p = (byte*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - g = (byte*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - - if (p == NULL || g == NULL) { - XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - return MEMORY_E; - } - #endif - - if (format != WOLFSSL_FILETYPE_ASN1 && format != WOLFSSL_FILETYPE_PEM) - ret = WOLFSSL_BAD_FILETYPE; - else { - if (format == WOLFSSL_FILETYPE_PEM) { -#ifdef WOLFSSL_PEM_TO_DER - FreeDer(&der); - ret = PemToDer(buf, sz, DH_PARAM_TYPE, &der, ctx->heap, - NULL, NULL); - if (ret < 0) { - /* Also try X9.42 format */ - ret = PemToDer(buf, sz, X942_PARAM_TYPE, &der, ctx->heap, - NULL, NULL); - } - #ifdef WOLFSSL_WPAS - #ifndef NO_DSA - if (ret < 0) { - ret = PemToDer(buf, sz, DSA_PARAM_TYPE, &der, ctx->heap, - NULL, NULL); - } - #endif - #endif /* WOLFSSL_WPAS */ -#else - ret = NOT_COMPILED_IN; -#endif /* WOLFSSL_PEM_TO_DER */ - } - - if (ret == 0) { - if (wc_DhParamsLoad(der->buffer, der->length, p, &pSz, g, &gSz) < 0) - ret = WOLFSSL_BAD_FILETYPE; - else if (ssl) - ret = wolfSSL_SetTmpDH(ssl, p, pSz, g, gSz); - else - ret = wolfSSL_CTX_SetTmpDH(ctx, p, pSz, g, gSz); - } - } - - FreeDer(&der); - - #ifdef WOLFSSL_SMALL_STACK - XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - #endif - - return ret; - } - - - /* server Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ - int wolfSSL_SetTmpDH_buffer(WOLFSSL* ssl, const unsigned char* buf, long sz, - int format) - { - if (ssl == NULL) - return BAD_FUNC_ARG; - - return wolfSSL_SetTmpDH_buffer_wrapper(ssl->ctx, ssl, buf, sz, format); - } - - - /* server ctx Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ - int wolfSSL_CTX_SetTmpDH_buffer(WOLFSSL_CTX* ctx, const unsigned char* buf, - long sz, int format) - { - return wolfSSL_SetTmpDH_buffer_wrapper(ctx, NULL, buf, sz, format); - } - -#endif /* NO_DH */ - - - int wolfSSL_use_certificate_buffer(WOLFSSL* ssl, - const unsigned char* in, long sz, int format) - { - WOLFSSL_ENTER("wolfSSL_use_certificate_buffer"); - if (ssl == NULL) - return BAD_FUNC_ARG; - - return ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, ssl, NULL, 0, - GET_VERIFY_SETTING_SSL(ssl)); - } - - - int wolfSSL_use_PrivateKey_buffer(WOLFSSL* ssl, - const unsigned char* in, long sz, int format) - { - int ret = WOLFSSL_FAILURE; - long consumed = 0; - - WOLFSSL_ENTER("wolfSSL_use_PrivateKey_buffer"); - if (ssl == NULL) - return BAD_FUNC_ARG; - - ret = ProcessBuffer(ssl->ctx, in, sz, format, PRIVATEKEY_TYPE, - ssl, &consumed, 0, GET_VERIFY_SETTING_SSL(ssl)); - - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (ret == WOLFSSL_SUCCESS && consumed < sz) { - /* When support for dual algorithm certificates is enabled, the - * buffer may contain both the primary and the alternative - * private key. Hence, we have to parse both of them. - */ - ret = ProcessBuffer(ssl->ctx, in + consumed, sz - consumed, format, - ALT_PRIVATEKEY_TYPE, ssl, NULL, 0, - GET_VERIFY_SETTING_SSL(ssl)); - } - #endif - - return ret; - } - -#ifdef WOLFSSL_DUAL_ALG_CERTS - int wolfSSL_use_AltPrivateKey_buffer(WOLFSSL* ssl, const unsigned char* in, - long sz, int format) - { - int ret = WOLFSSL_FAILURE; - - WOLFSSL_ENTER("wolfSSL_use_AltPrivateKey_buffer"); - ret = ProcessBuffer(ssl->ctx, in, sz, format, ALT_PRIVATEKEY_TYPE, ssl, - NULL, 0, GET_VERIFY_SETTING_SSL(ssl)); - WOLFSSL_LEAVE("wolfSSL_use_AltPrivateKey_buffer", ret); - return ret; - } -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - -#ifdef WOLF_PRIVATE_KEY_ID - int wolfSSL_use_PrivateKey_id(WOLFSSL* ssl, const unsigned char* id, - long sz, int devId, long keySz) - { - int ret = wolfSSL_use_PrivateKey_Id(ssl, id, sz, devId); - - if (ret == WOLFSSL_SUCCESS) - ssl->buffers.keySz = (word32)keySz; - - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (ret == WOLFSSL_SUCCESS) - /* Set the ID for the alternative key, too. User can still - * override that afterwards. */ - ret = wolfSSL_use_AltPrivateKey_id(ssl, id, sz, devId, keySz); - #endif - - return ret; - } - - int wolfSSL_use_PrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, - long sz, int devId) - { - int ret = WOLFSSL_FAILURE; - - if (ssl->buffers.weOwnKey) - FreeDer(&ssl->buffers.key); - if (AllocDer(&ssl->buffers.key, (word32)sz, PRIVATEKEY_TYPE, - ssl->heap) == 0) { - XMEMCPY(ssl->buffers.key->buffer, id, sz); - ssl->buffers.weOwnKey = 1; - ssl->buffers.keyId = 1; - if (devId != INVALID_DEVID) - ssl->buffers.keyDevId = devId; - else - ssl->buffers.keyDevId = ssl->devId; - - ret = WOLFSSL_SUCCESS; - } - - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (ret == WOLFSSL_SUCCESS) - /* Set the ID for the alternative key, too. User can still - * override that afterwards. */ - ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId); - #endif - - return ret; - } - - int wolfSSL_use_PrivateKey_Label(WOLFSSL* ssl, const char* label, int devId) - { - int ret = WOLFSSL_FAILURE; - word32 sz = (word32)XSTRLEN(label) + 1; - - if (ssl->buffers.weOwnKey) - FreeDer(&ssl->buffers.key); - if (AllocDer(&ssl->buffers.key, (word32)sz, PRIVATEKEY_TYPE, - ssl->heap) == 0) { - XMEMCPY(ssl->buffers.key->buffer, label, sz); - ssl->buffers.weOwnKey = 1; - ssl->buffers.keyLabel = 1; - if (devId != INVALID_DEVID) - ssl->buffers.keyDevId = devId; - else - ssl->buffers.keyDevId = ssl->devId; - - ret = WOLFSSL_SUCCESS; - } - - #ifdef WOLFSSL_DUAL_ALG_CERTS - if (ret == WOLFSSL_SUCCESS) - /* Set the label for the alternative key, too. User can still - * override that afterwards. */ - ret = wolfSSL_use_AltPrivateKey_Label(ssl, label, devId); - #endif - - return ret; - } -#endif /* WOLF_PRIVATE_KEY_ID */ - -#if defined(WOLF_PRIVATE_KEY_ID) && defined(WOLFSSL_DUAL_ALG_CERTS) - int wolfSSL_use_AltPrivateKey_id(WOLFSSL* ssl, const unsigned char* id, - long sz, int devId, long keySz) - { - int ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId); - - if (ret == WOLFSSL_SUCCESS) - ssl->buffers.altKeySz = (word32)keySz; - - return ret; - } - - int wolfSSL_use_AltPrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, - long sz, int devId) - { - int ret = WOLFSSL_FAILURE; - - if (ssl == NULL || id == NULL) { - return ret; - } - - if (ssl->buffers.weOwnAltKey) - FreeDer(&ssl->buffers.altKey); - if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE, - ssl->heap) == 0) { - XMEMCPY(ssl->buffers.altKey->buffer, id, sz); - ssl->buffers.weOwnAltKey = 1; - ssl->buffers.altKeyId = 1; - if (devId != INVALID_DEVID) - ssl->buffers.altKeyDevId = devId; - else - ssl->buffers.altKeyDevId = ssl->devId; - - ret = WOLFSSL_SUCCESS; - } - - return ret; - } - - int wolfSSL_use_AltPrivateKey_Label(WOLFSSL* ssl, const char* label, - int devId) - { - int ret = WOLFSSL_FAILURE; - word32 sz; - - if (ssl == NULL || label == NULL) { - return ret; - } - - sz = (word32)XSTRLEN(label) + 1; - if (ssl->buffers.weOwnAltKey) - FreeDer(&ssl->buffers.altKey); - if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE, - ssl->heap) == 0) { - XMEMCPY(ssl->buffers.altKey->buffer, label, sz); - ssl->buffers.weOwnAltKey = 1; - ssl->buffers.altKeyLabel = 1; - if (devId != INVALID_DEVID) - ssl->buffers.altKeyDevId = devId; - else - ssl->buffers.altKeyDevId = ssl->devId; - - ret = WOLFSSL_SUCCESS; - } - - return ret; - } -#endif /* WOLF_PRIVATE_KEY_ID && WOLFSSL_DUAL_ALG_CERTS */ - - int wolfSSL_use_certificate_chain_buffer_format(WOLFSSL* ssl, - const unsigned char* in, long sz, int format) - { - WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format"); - if (ssl == NULL) - return BAD_FUNC_ARG; - - return ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, - ssl, NULL, 1, GET_VERIFY_SETTING_SSL(ssl)); - } - - int wolfSSL_use_certificate_chain_buffer(WOLFSSL* ssl, - const unsigned char* in, long sz) - { - return wolfSSL_use_certificate_chain_buffer_format(ssl, in, sz, - WOLFSSL_FILETYPE_PEM); - } - /* unload any certs or keys that SSL owns, leave CTX as is WOLFSSL_SUCCESS on ok */ @@ -17223,20 +10818,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return WOLFSSL_SUCCESS; } - /* returns previous set cache size which stays constant */ - long wolfSSL_CTX_sess_set_cache_size(WOLFSSL_CTX* ctx, long sz) - { - /* cache size fixed at compile time in wolfSSL */ - (void)ctx; - (void)sz; - WOLFSSL_MSG("session cache is set at compile time"); - #ifndef NO_SESSION_CACHE - return (long)(SESSIONS_PER_ROW * SESSION_ROWS); - #else - return 0; - #endif - } - #endif #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ @@ -17553,7 +11134,8 @@ int wolfSSL_set_compression(WOLFSSL* ssl) WOLFSSL_ENTER("wolfSSL_CTX_get_client_CA_list"); if (ctx == NULL) { - WOLFSSL_MSG("Bad argument passed to wolfSSL_CTX_get_client_CA_list"); + WOLFSSL_MSG("Bad argument passed to " + "wolfSSL_CTX_get_client_CA_list"); return NULL; } @@ -17601,7 +11183,8 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return WOLFSSL_FAILURE; } - if (wolfSSL_sk_X509_NAME_push(ctx->client_ca_names, nameCopy) != WOLFSSL_SUCCESS) { + if (wolfSSL_sk_X509_NAME_push(ctx->client_ca_names, nameCopy) != + WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); wolfSSL_X509_NAME_free(nameCopy); return WOLFSSL_FAILURE; @@ -17613,7 +11196,8 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #ifndef NO_BIO #if !defined(NO_RSA) && !defined(NO_CERTS) - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname) + WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file( + const char* fname) { /* The webserver build is using this to load a CA into the server * for client authentication as an option. Have this return NULL in @@ -17692,75 +11276,6 @@ cleanup: #ifdef OPENSSL_EXTRA - #ifdef WOLFSSL_SYS_CA_CERTS - /* - * This is an OpenSSL compatibility layer function, but it doesn't mirror - * the exact functionality of its OpenSSL counterpart. We don't support the - * notion of an "OpenSSL directory". This function will attempt to load the - * environment variables SSL_CERT_DIR and SSL_CERT_FILE, if either are found, - * they will be loaded. Otherwise, it will act as a wrapper around our - * native wolfSSL_CTX_load_system_CA_certs function. This function does - * conform to OpenSSL's return value conventions. - */ - int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx) - { - int ret; -#ifdef XGETENV - char* certDir; - char* certFile; - word32 flags; -#endif - - WOLFSSL_ENTER("wolfSSL_CTX_set_default_verify_paths"); - -#ifdef XGETENV - certDir = XGETENV("SSL_CERT_DIR"); - certFile = XGETENV("SSL_CERT_FILE"); - flags = WOLFSSL_LOAD_FLAG_PEM_CA_ONLY; - - if (certDir || certFile) { - if (certDir) { - /* - * We want to keep trying to load more CAs even if one cert in - * the directory is bad and can't be used (e.g. if one is expired), - * so we use WOLFSSL_LOAD_FLAG_IGNORE_ERR. - */ - flags |= WOLFSSL_LOAD_FLAG_IGNORE_ERR; - } - - ret = wolfSSL_CTX_load_verify_locations_ex(ctx, certFile, certDir, - flags); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG_EX("Failed to load CA certs from SSL_CERT_FILE: %s" - " SSL_CERT_DIR: %s. Error: %d", certFile, - certDir, ret); - return WOLFSSL_FAILURE; - } - return ret; - } -#endif - -#ifdef NO_FILESYSTEM - WOLFSSL_MSG("wolfSSL_CTX_set_default_verify_paths not supported" - " with NO_FILESYSTEM enabled"); - ret = WOLFSSL_FATAL_ERROR; -#else - ret = wolfSSL_CTX_load_system_CA_certs(ctx); - if (ret == WOLFSSL_BAD_PATH) { - /* - * OpenSSL doesn't treat the lack of a system CA cert directory as a - * failure. We do the same here. - */ - ret = WOLFSSL_SUCCESS; - } -#endif - - WOLFSSL_LEAVE("wolfSSL_CTX_set_default_verify_paths", ret); - - return ret; - } - #endif /* WOLFSSL_SYS_CA_CERTS */ - #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \ && !defined(WC_NO_RNG) static const byte srp_N[] = { @@ -17949,7 +11464,8 @@ cleanup: #endif /* OPENSSL_EXTRA */ -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || \ + defined(WOLFSSL_WPAS_SMALL) /* store keys returns WOLFSSL_SUCCESS or -1 on error */ int wolfSSL_get_keys(WOLFSSL* ssl, unsigned char** ms, unsigned int* msLen, @@ -18031,8 +11547,8 @@ cleanup: if (ssl == NULL) return 0; - /* Can't use ssl->options.connectState and ssl->options.acceptState because - * they differ in meaning for TLS <=1.2 and 1.3 */ + /* Can't use ssl->options.connectState and ssl->options.acceptState + * because they differ in meaning for TLS <=1.2 and 1.3 */ if (ssl->options.handShakeState == HANDSHAKE_DONE) return 1; @@ -18140,7 +11656,8 @@ cleanup: } #endif /* OPENSSL_EXTRA */ -#if !defined(NO_CERTS) && (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) +#if !defined(NO_CERTS) && (defined(OPENSSL_EXTRA) || \ + defined(WOLFSSL_WPAS_SMALL)) #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) /** @@ -18238,7 +11755,8 @@ cleanup: } #ifdef OPENSSL_ALL - int wolfSSL_CTX_set1_verify_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str) + int wolfSSL_CTX_set1_verify_cert_store(WOLFSSL_CTX* ctx, + WOLFSSL_X509_STORE* str) { WOLFSSL_ENTER("wolfSSL_CTX_set1_verify_cert_store"); @@ -19500,59 +13018,6 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, } #endif -#ifdef WOLFSSL_SESSION_ID_CTX - /* Storing app session context id, this value is inherited by WOLFSSL - * objects created from WOLFSSL_CTX. Any session that is imported with a - * different session context id will be rejected. - * - * ctx structure to set context in - * sid_ctx value of context to set - * sid_ctx_len length of sid_ctx buffer - * - * Returns WOLFSSL_SUCCESS in success case and WOLFSSL_FAILURE when failing - */ - int wolfSSL_CTX_set_session_id_context(WOLFSSL_CTX* ctx, - const unsigned char* sid_ctx, - unsigned int sid_ctx_len) - { - WOLFSSL_ENTER("wolfSSL_CTX_set_session_id_context"); - - /* No application specific context needed for wolfSSL */ - if (sid_ctx_len > ID_LEN || ctx == NULL || sid_ctx == NULL) { - return WOLFSSL_FAILURE; - } - XMEMCPY(ctx->sessionCtx, sid_ctx, sid_ctx_len); - ctx->sessionCtxSz = (byte)sid_ctx_len; - - return WOLFSSL_SUCCESS; - } - - - - /* Storing app session context id. Any session that is imported with a - * different session context id will be rejected. - * - * ssl structure to set context in - * id value of context to set - * len length of sid_ctx buffer - * - * Returns WOLFSSL_SUCCESS in success case and WOLFSSL_FAILURE when failing - */ - int wolfSSL_set_session_id_context(WOLFSSL* ssl, const unsigned char* id, - unsigned int len) - { - WOLFSSL_ENTER("wolfSSL_set_session_id_context"); - - if (len > ID_LEN || ssl == NULL || id == NULL) { - return WOLFSSL_FAILURE; - } - XMEMCPY(ssl->sessionCtx, id, len); - ssl->sessionCtxSz = (byte)len; - - return WOLFSSL_SUCCESS; - } -#endif - #ifdef OPENSSL_EXTRA #ifndef NO_WOLFSSL_STUB @@ -19586,17 +13051,6 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #endif - long wolfSSL_CTX_sess_get_cache_size(WOLFSSL_CTX* ctx) - { - (void)ctx; - #ifndef NO_SESSION_CACHE - return (long)(SESSIONS_PER_ROW * SESSION_ROWS); - #else - return 0; - #endif - } - - /* returns the unsigned error value and increments the pointer into the * error queue. * @@ -19817,7 +13271,8 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) /* Return stack of peer certs. - * Caller does not need to free return. The stack is Free'd when WOLFSSL* ssl is. + * Caller does not need to free return. The stack is Free'd when WOLFSSL* ssl + * is. */ WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_get_peer_cert_chain(const WOLFSSL* ssl) { @@ -20393,532 +13848,6 @@ int wolfSSL_session_reused(WOLFSSL* ssl) return resuming; } -/* return a new malloc'd session with default settings on success */ -WOLFSSL_SESSION* wolfSSL_NewSession(void* heap) -{ - WOLFSSL_SESSION* ret = NULL; - - WOLFSSL_ENTER("wolfSSL_NewSession"); - - ret = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), heap, - DYNAMIC_TYPE_SESSION); - if (ret != NULL) { - int err; - XMEMSET(ret, 0, sizeof(WOLFSSL_SESSION)); - wolfSSL_RefInit(&ret->ref, &err); - #ifdef WOLFSSL_REFCNT_ERROR_RETURN - if (err != 0) { - WOLFSSL_MSG("Error setting up session reference mutex"); - XFREE(ret, ret->heap, DYNAMIC_TYPE_SESSION); - return NULL; - } - #else - (void)err; - #endif -#ifndef NO_SESSION_CACHE - ret->cacheRow = INVALID_SESSION_ROW; /* not in cache */ -#endif - ret->type = WOLFSSL_SESSION_TYPE_HEAP; - ret->heap = heap; -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("SESSION master secret", ret->masterSecret, SECRET_LEN); - wc_MemZero_Add("SESSION id", ret->sessionID, ID_LEN); -#endif - #ifdef HAVE_SESSION_TICKET - ret->ticket = ret->staticTicket; - #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - ret->ticketNonce.data = ret->ticketNonce.dataStatic; - #endif - #endif -#ifdef HAVE_EX_DATA - ret->ownExData = 1; - if (crypto_ex_cb_ctx_session != NULL) { - crypto_ex_cb_setup_new_data(ret, crypto_ex_cb_ctx_session, - &ret->ex_data); - } -#endif - } - return ret; -} - - -WOLFSSL_SESSION* wolfSSL_SESSION_new_ex(void* heap) -{ - return wolfSSL_NewSession(heap); -} - -WOLFSSL_SESSION* wolfSSL_SESSION_new(void) -{ - return wolfSSL_SESSION_new_ex(NULL); -} - -/* add one to session reference count - * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error */ -int wolfSSL_SESSION_up_ref(WOLFSSL_SESSION* session) -{ - int ret; - - session = ClientSessionToSession(session); - - if (session == NULL || session->type != WOLFSSL_SESSION_TYPE_HEAP) - return WOLFSSL_FAILURE; - - wolfSSL_RefInc(&session->ref, &ret); -#ifdef WOLFSSL_REFCNT_ERROR_RETURN - if (ret != 0) { - WOLFSSL_MSG("Failed to lock session mutex"); - return WOLFSSL_FAILURE; - } -#else - (void)ret; -#endif - - return WOLFSSL_SUCCESS; -} - -/** - * Deep copy the contents from input to output. - * @param input The source of the copy. - * @param output The destination of the copy. - * @param avoidSysCalls If true, then system calls will be avoided or an error - * will be returned if it is not possible to proceed - * without a system call. This is useful for fetching - * sessions from cache. When a cache row is locked, we - * don't want to block other threads with long running - * system calls. - * @param ticketNonceBuf If not null and @avoidSysCalls is true, the copy of the - * ticketNonce will happen in this pre allocated buffer - * @param ticketNonceLen @ticketNonceBuf len as input, used length on output - * @param ticketNonceUsed if @ticketNonceBuf was used to copy the ticket noncet - * @return WOLFSSL_SUCCESS on success - * WOLFSSL_FAILURE on failure - */ -static int wolfSSL_DupSessionEx(const WOLFSSL_SESSION* input, - WOLFSSL_SESSION* output, int avoidSysCalls, byte* ticketNonceBuf, - byte* ticketNonceLen, byte* preallocUsed) -{ -#ifdef HAVE_SESSION_TICKET - int ticLenAlloc = 0; - byte *ticBuff = NULL; -#endif - const size_t copyOffset = OFFSETOF(WOLFSSL_SESSION, heap) + sizeof(input->heap); - int ret = WOLFSSL_SUCCESS; - - (void)avoidSysCalls; - (void)ticketNonceBuf; - (void)ticketNonceLen; - (void)preallocUsed; - - input = ClientSessionToSession(input); - output = ClientSessionToSession(output); - - if (input == NULL || output == NULL || input == output) { - WOLFSSL_MSG("input or output are null or same"); - return WOLFSSL_FAILURE; - } - -#ifdef HAVE_SESSION_TICKET - if (output->ticket != output->staticTicket) { - ticBuff = output->ticket; - ticLenAlloc = output->ticketLenAlloc; - } -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - /* free the data, it would be better to reuse the buffer but this - * maintain the code simpler. A smart allocator should reuse the free'd - * buffer in the next malloc without much performance penalties. */ - if (output->ticketNonce.data != output->ticketNonce.dataStatic) { - - /* Callers that avoid syscall should never calls this with - * output->tickeNonce.data being a dynamic buffer.*/ - if (avoidSysCalls) { - WOLFSSL_MSG("can't avoid syscalls with dynamic TicketNonce buffer"); - return WOLFSSL_FAILURE; - } - - XFREE(output->ticketNonce.data, - output->heap, DYNAMIC_TYPE_SESSION_TICK); - output->ticketNonce.data = output->ticketNonce.dataStatic; - output->ticketNonce.len = 0; - } -#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ -#endif /* HAVE_SESSION_TICKET */ - -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - if (output->peer != NULL) { - if (avoidSysCalls) { - WOLFSSL_MSG("Can't free cert when avoiding syscalls"); - return WOLFSSL_FAILURE; - } - wolfSSL_X509_free(output->peer); - output->peer = NULL; - } -#endif - - XMEMCPY((byte*)output + copyOffset, (byte*)input + copyOffset, - sizeof(WOLFSSL_SESSION) - copyOffset); - -#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ - defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - /* fix pointer to static after the copy */ - output->ticketNonce.data = output->ticketNonce.dataStatic; -#endif - /* Set sane values for copy */ -#ifndef NO_SESSION_CACHE - if (output->type != WOLFSSL_SESSION_TYPE_CACHE) - output->cacheRow = INVALID_SESSION_ROW; -#endif -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - if (input->peer != NULL && input->peer->dynamicMemory) { - if (wolfSSL_X509_up_ref(input->peer) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Can't increase peer cert ref count"); - output->peer = NULL; - } - } - else if (!avoidSysCalls) - output->peer = wolfSSL_X509_dup(input->peer); - else - /* output->peer is not that important to copy */ - output->peer = NULL; -#endif -#ifdef HAVE_SESSION_TICKET - if (input->ticketLen > SESSION_TICKET_LEN) { - /* Need dynamic buffer */ - if (ticBuff == NULL || ticLenAlloc < input->ticketLen) { - /* allocate new one */ - byte* tmp; - if (avoidSysCalls) { - WOLFSSL_MSG("Failed to allocate memory for ticket when avoiding" - " syscalls"); - output->ticket = ticBuff; - output->ticketLenAlloc = (word16) ticLenAlloc; - output->ticketLen = 0; - ret = WOLFSSL_FAILURE; - } - else { -#ifdef WOLFSSL_NO_REALLOC - tmp = (byte*)XMALLOC(input->ticketLen, - output->heap, DYNAMIC_TYPE_SESSION_TICK); - XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK); - ticBuff = NULL; -#else - tmp = (byte*)XREALLOC(ticBuff, input->ticketLen, - output->heap, DYNAMIC_TYPE_SESSION_TICK); -#endif /* WOLFSSL_NO_REALLOC */ - if (tmp == NULL) { - WOLFSSL_MSG("Failed to allocate memory for ticket"); -#ifndef WOLFSSL_NO_REALLOC - XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK); - ticBuff = NULL; -#endif /* WOLFSSL_NO_REALLOC */ - output->ticket = NULL; - output->ticketLen = 0; - output->ticketLenAlloc = 0; - ret = WOLFSSL_FAILURE; - } - else { - ticBuff = tmp; - ticLenAlloc = input->ticketLen; - } - } - } - if (ticBuff != NULL && ret == WOLFSSL_SUCCESS) { - XMEMCPY(ticBuff, input->ticket, input->ticketLen); - output->ticket = ticBuff; - output->ticketLenAlloc = (word16) ticLenAlloc; - } - } - else { - /* Default ticket to non dynamic */ - if (avoidSysCalls) { - /* Try to use ticBuf if available. Caller can later move it to - * the static buffer. */ - if (ticBuff != NULL) { - if (ticLenAlloc >= input->ticketLen) { - output->ticket = ticBuff; - output->ticketLenAlloc = ticLenAlloc; - } - else { - WOLFSSL_MSG("ticket dynamic buffer too small but we are " - "avoiding system calls"); - ret = WOLFSSL_FAILURE; - output->ticket = ticBuff; - output->ticketLenAlloc = (word16) ticLenAlloc; - output->ticketLen = 0; - } - } - else { - output->ticket = output->staticTicket; - output->ticketLenAlloc = 0; - } - } - else { - if (ticBuff != NULL) - XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK); - output->ticket = output->staticTicket; - output->ticketLenAlloc = 0; - } - if (input->ticketLenAlloc > 0 && ret == WOLFSSL_SUCCESS) { - /* Shouldn't happen as session should have placed this in - * the static buffer */ - XMEMCPY(output->ticket, input->ticket, - input->ticketLen); - } - } - ticBuff = NULL; - -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - if (preallocUsed != NULL) - *preallocUsed = 0; - - if (input->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ && - ret == WOLFSSL_SUCCESS) { - /* TicketNonce does not fit in the static buffer */ - if (!avoidSysCalls) { - output->ticketNonce.data = (byte*)XMALLOC(input->ticketNonce.len, - output->heap, DYNAMIC_TYPE_SESSION_TICK); - - if (output->ticketNonce.data == NULL) { - WOLFSSL_MSG("Failed to allocate space for ticket nonce"); - output->ticketNonce.data = output->ticketNonce.dataStatic; - output->ticketNonce.len = 0; - ret = WOLFSSL_FAILURE; - } - else { - output->ticketNonce.len = input->ticketNonce.len; - XMEMCPY(output->ticketNonce.data, input->ticketNonce.data, - input->ticketNonce.len); - ret = WOLFSSL_SUCCESS; - } - } - /* we can't do syscalls. Use prealloc buffers if provided from the - * caller. */ - else if (ticketNonceBuf != NULL && - *ticketNonceLen >= input->ticketNonce.len) { - XMEMCPY(ticketNonceBuf, input->ticketNonce.data, - input->ticketNonce.len); - *ticketNonceLen = input->ticketNonce.len; - if (preallocUsed != NULL) - *preallocUsed = 1; - ret = WOLFSSL_SUCCESS; - } - else { - WOLFSSL_MSG("TicketNonce bigger than static buffer, and we can't " - "do syscalls"); - ret = WOLFSSL_FAILURE; - } - } -#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ - -#endif /* HAVE_SESSION_TICKET */ - -#ifdef HAVE_EX_DATA - if (input->type != WOLFSSL_SESSION_TYPE_CACHE && - output->type != WOLFSSL_SESSION_TYPE_CACHE) { - /* Not called with cache as that passes ownership of ex_data */ - ret = crypto_ex_cb_dup_data(&input->ex_data, &output->ex_data, - crypto_ex_cb_ctx_session); - } -#endif - - return ret; -} - -/** - * Deep copy the contents from input to output. - * @param input The source of the copy. - * @param output The destination of the copy. - * @param avoidSysCalls If true, then system calls will be avoided or an error - * will be returned if it is not possible to proceed - * without a system call. This is useful for fetching - * sessions from cache. When a cache row is locked, we - * don't want to block other threads with long running - * system calls. - * @return WOLFSSL_SUCCESS on success - * WOLFSSL_FAILURE on failure - */ -int wolfSSL_DupSession(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output, - int avoidSysCalls) -{ - return wolfSSL_DupSessionEx(input, output, avoidSysCalls, NULL, NULL, NULL); -} - -WOLFSSL_SESSION* wolfSSL_SESSION_dup(WOLFSSL_SESSION* session) -{ - WOLFSSL_SESSION* copy; - - WOLFSSL_ENTER("wolfSSL_SESSION_dup"); - - session = ClientSessionToSession(session); - if (session == NULL) - return NULL; - -#ifdef HAVE_SESSION_TICKET - if (session->ticketLenAlloc > 0 && !session->ticket) { - WOLFSSL_MSG("Session dynamic flag is set but ticket pointer is null"); - return NULL; - } -#endif - - copy = wolfSSL_NewSession(session->heap); - if (copy != NULL && - wolfSSL_DupSession(session, copy, 0) != WOLFSSL_SUCCESS) { - wolfSSL_FreeSession(NULL, copy); - copy = NULL; - } - return copy; -} - -void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) -{ - session = ClientSessionToSession(session); - if (session == NULL) - return; - - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_FreeSession"); - - if (session->ref.count > 0) { - int ret; - int isZero; - wolfSSL_RefDec(&session->ref, &isZero, &ret); - (void)ret; - if (!isZero) { - return; - } - wolfSSL_RefFree(&session->ref); - } - - WOLFSSL_MSG("wolfSSL_FreeSession full free"); - -#ifdef HAVE_EX_DATA - if (session->ownExData) { - crypto_ex_cb_free_data(session, crypto_ex_cb_ctx_session, - &session->ex_data); - } -#endif - -#ifdef HAVE_EX_DATA_CLEANUP_HOOKS - wolfSSL_CRYPTO_cleanup_ex_data(&session->ex_data); -#endif - -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) - if (session->peer) { - wolfSSL_X509_free(session->peer); - session->peer = NULL; - } -#endif - -#ifdef HAVE_SESSION_TICKET - if (session->ticketLenAlloc > 0) { - XFREE(session->ticket, session->heap, DYNAMIC_TYPE_SESSION_TICK); - session->ticket = session->staticTicket; - session->ticketLen = 0; - session->ticketLenAlloc = 0; - } -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - if (session->ticketNonce.data != session->ticketNonce.dataStatic) { - XFREE(session->ticketNonce.data, session->heap, - DYNAMIC_TYPE_SESSION_TICK); - session->ticketNonce.data = session->ticketNonce.dataStatic; - session->ticketNonce.len = 0; - } -#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ -#endif - -#ifdef HAVE_EX_DATA_CLEANUP_HOOKS - wolfSSL_CRYPTO_cleanup_ex_data(&session->ex_data); -#endif - - /* Make sure masterSecret is zeroed. */ - ForceZero(session->masterSecret, SECRET_LEN); - /* Session ID is sensitive information too. */ - ForceZero(session->sessionID, ID_LEN); - - if (session->type == WOLFSSL_SESSION_TYPE_HEAP) { - XFREE(session, session->heap, DYNAMIC_TYPE_SESSION); - } -} - -/* DO NOT use this API internally. Use wolfSSL_FreeSession directly instead - * and pass in the ctx parameter if possible (like from ssl->ctx). */ -void wolfSSL_SESSION_free(WOLFSSL_SESSION* session) -{ - session = ClientSessionToSession(session); - wolfSSL_FreeSession(NULL, session); -} - -#ifndef NO_SESSION_CACHE -int wolfSSL_CTX_add_session(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) -{ - int error = 0; - const byte* id = NULL; - byte idSz = 0; - - WOLFSSL_ENTER("wolfSSL_CTX_add_session"); - - session = ClientSessionToSession(session); - if (session == NULL) - return WOLFSSL_FAILURE; - - /* Session cache is global */ - (void)ctx; - - if (session->haveAltSessionID) { - id = session->altSessionID; - idSz = ID_LEN; - } - else { - id = session->sessionID; - idSz = session->sessionIDSz; - } - - error = AddSessionToCache(ctx, session, id, idSz, - NULL, session->side, -#ifdef HAVE_SESSION_TICKET - session->ticketLen > 0, -#else - 0, -#endif - NULL); - - return error == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} -#endif - -#if defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE) - -/** -* set cipher to WOLFSSL_SESSION from WOLFSSL_CIPHER -* @param session a pointer to WOLFSSL_SESSION structure -* @param cipher a function pointer to WOLFSSL_CIPHER -* @return WOLFSSL_SUCCESS on success, otherwise WOLFSSL_FAILURE -*/ -int wolfSSL_SESSION_set_cipher(WOLFSSL_SESSION* session, - const WOLFSSL_CIPHER* cipher) -{ - WOLFSSL_ENTER("wolfSSL_SESSION_set_cipher"); - - session = ClientSessionToSession(session); - /* sanity check */ - if (session == NULL || cipher == NULL) { - WOLFSSL_MSG("bad argument"); - return WOLFSSL_FAILURE; - } - session->cipherSuite0 = cipher->cipherSuite0; - session->cipherSuite = cipher->cipherSuite; - - WOLFSSL_LEAVE("wolfSSL_SESSION_set_cipher", WOLFSSL_SUCCESS); - return WOLFSSL_SUCCESS; -} -#endif /* OPENSSL_EXTRA || HAVE_EXT_CACHE */ - - /* helper function that takes in a protocol version struct and returns string */ static const char* wolfSSL_internal_get_version(const ProtocolVersion* version) { @@ -21054,25 +13983,6 @@ const char* wolfSSL_CIPHER_get_version(const WOLFSSL_CIPHER* cipher) return wolfSSL_get_version(cipher->ssl); } -const char* wolfSSL_SESSION_CIPHER_get_name(const WOLFSSL_SESSION* session) -{ - session = ClientSessionToSession(session); - if (session == NULL) { - return NULL; - } - -#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ - (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) - #if !defined(WOLFSSL_CIPHER_INTERNALNAME) && !defined(NO_ERROR_STRINGS) - return GetCipherNameIana(session->cipherSuite0, session->cipherSuite); - #else - return GetCipherNameInternal(session->cipherSuite0, session->cipherSuite); - #endif -#else - return NULL; -#endif -} - const char* wolfSSL_get_cipher(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_cipher"); @@ -21902,26 +14812,6 @@ int wolfSSL_OCSP_parse_url(char* url, char** host, char** port, char** path, } #endif -#ifndef NO_WOLFSSL_STUB -void wolfSSL_RAND_screen(void) -{ - WOLFSSL_STUB("RAND_screen"); -} -#endif - - - -int wolfSSL_RAND_load_file(const char* fname, long len) -{ - (void)fname; - /* wolfCrypt provides enough entropy internally or will report error */ - if (len == -1) - return 1024; - else - return (int)len; -} - - #ifndef NO_WOLFSSL_STUB WOLFSSL_COMP_METHOD* wolfSSL_COMP_zlib(void) { @@ -22690,29 +15580,6 @@ const char* wolfSSL_state_string_long(const WOLFSSL* ssl) } } -/* - * Sets default PEM callback password if null is passed into - * the callback parameter of a PEM_read_bio_* function. - * - * Returns callback phrase size on success or WOLFSSL_FAILURE otherwise. - */ -int wolfSSL_PEM_def_callback(char* name, int num, int w, void* key) -{ - (void)w; - WOLFSSL_ENTER("wolfSSL_PEM_def_callback"); - - /* We assume that the user passes a default password as userdata */ - if (key) { - int sz = (int)XSTRLEN((const char*)key); - sz = (sz > num) ? num : sz; - XMEMCPY(name, key, sz); - return sz; - } else { - WOLFSSL_MSG("Error, default password cannot be created."); - return WOLFSSL_FAILURE; - } -} - #endif /* OPENSSL_EXTRA */ static long wolf_set_options(long old_op, long op) @@ -22919,47 +15786,6 @@ long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) } #endif /* HAVE_PK_CALLBACKS */ -#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) -const unsigned char *wolfSSL_SESSION_get0_id_context( - const WOLFSSL_SESSION *sess, unsigned int *sid_ctx_length) -{ - return wolfSSL_SESSION_get_id((WOLFSSL_SESSION *)sess, sid_ctx_length); -} -int wolfSSL_SESSION_set1_id(WOLFSSL_SESSION *s, - const unsigned char *sid, unsigned int sid_len) -{ - if (s == NULL) { - return WOLFSSL_FAILURE; - } - if (sid_len > ID_LEN) { - return WOLFSSL_FAILURE; - } - s->sessionIDSz = sid_len; - if (sid != s->sessionID) { - XMEMCPY(s->sessionID, sid, sid_len); - } - return WOLFSSL_SUCCESS; -} - -int wolfSSL_SESSION_set1_id_context(WOLFSSL_SESSION *s, - const unsigned char *sid_ctx, unsigned int sid_ctx_len) -{ - if (s == NULL) { - return WOLFSSL_FAILURE; - } - if (sid_ctx_len > ID_LEN) { - return WOLFSSL_FAILURE; - } - s->sessionCtxSz = sid_ctx_len; - if (sid_ctx != s->sessionCtx) { - XMEMCPY(s->sessionCtx, sid_ctx, sid_ctx_len); - } - - return WOLFSSL_SUCCESS; -} - -#endif - /*** TBD ***/ #ifndef NO_WOLFSSL_STUB int wolfSSL_sk_SSL_COMP_zero(WOLFSSL_STACK* st) @@ -22981,8 +15807,8 @@ long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type) } if (type == TLSEXT_STATUSTYPE_ocsp){ - int r = TLSX_UseCertificateStatusRequest(&s->extensions, (byte)type, 0, s, - s->heap, s->devId); + int r = TLSX_UseCertificateStatusRequest(&s->extensions, (byte)type, 0, + s, s->heap, s->devId); return (long)r; } else { WOLFSSL_MSG( @@ -23330,117 +16156,7 @@ long wolfSSL_CTX_sess_timeouts(WOLFSSL_CTX* ctx) } #endif - -/* Return the total number of sessions */ -long wolfSSL_CTX_sess_number(WOLFSSL_CTX* ctx) -{ - word32 total = 0; - - WOLFSSL_ENTER("wolfSSL_CTX_sess_number"); - (void)ctx; - -#if defined(WOLFSSL_SESSION_STATS) && !defined(NO_SESSION_CACHE) - if (wolfSSL_get_session_stats(NULL, &total, NULL, NULL) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Error getting session stats"); - } -#else - WOLFSSL_MSG("Please use macro WOLFSSL_SESSION_STATS for session stats"); -#endif - - return (long)total; -} - - #ifndef NO_CERTS -long wolfSSL_CTX_add_extra_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) -{ - byte* chain = NULL; - int derSz; - const byte* der; - int ret; - DerBuffer *derBuffer = NULL; - - WOLFSSL_ENTER("wolfSSL_CTX_add_extra_chain_cert"); - - if (ctx == NULL || x509 == NULL) { - WOLFSSL_MSG("Bad Argument"); - return WOLFSSL_FAILURE; - } - - der = wolfSSL_X509_get_der(x509, &derSz); - if (der == NULL || derSz <= 0) { - WOLFSSL_MSG("Error getting X509 DER"); - return WOLFSSL_FAILURE; - } - - if (ctx->certificate == NULL) { - WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format"); - - /* Process buffer makes first certificate the leaf. */ - ret = ProcessBuffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, - NULL, NULL, 1, GET_VERIFY_SETTING_CTX(ctx)); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_LEAVE("wolfSSL_CTX_add_extra_chain_cert", ret); - return WOLFSSL_FAILURE; - } - } - else { - long chainSz = 0; - int idx = 0; - - /* TODO: Do this elsewhere. */ - ret = AllocDer(&derBuffer, derSz, CERT_TYPE, ctx->heap); - if (ret != 0) { - WOLFSSL_MSG("Memory Error"); - return WOLFSSL_FAILURE; - } - XMEMCPY(derBuffer->buffer, der, derSz); - ret = AddCA(ctx->cm, &derBuffer, WOLFSSL_USER_CA, - GET_VERIFY_SETTING_CTX(ctx)); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_LEAVE("wolfSSL_CTX_add_extra_chain_cert", ret); - return WOLFSSL_FAILURE; - } - - /* adding cert to existing chain */ - if (ctx->certChain != NULL && ctx->certChain->length > 0) { - chainSz += ctx->certChain->length; - } - chainSz += OPAQUE24_LEN + derSz; - - chain = (byte*)XMALLOC(chainSz, ctx->heap, DYNAMIC_TYPE_DER); - if (chain == NULL) { - WOLFSSL_MSG("Memory Error"); - return WOLFSSL_FAILURE; - } - - if (ctx->certChain != NULL && ctx->certChain->length > 0) { - XMEMCPY(chain, ctx->certChain->buffer, ctx->certChain->length); - idx = ctx->certChain->length; - } - c32to24(derSz, chain + idx); - idx += OPAQUE24_LEN; - XMEMCPY(chain + idx, der, derSz); - idx += derSz; -#ifdef WOLFSSL_TLS13 - ctx->certChainCnt++; -#endif - - FreeDer(&ctx->certChain); - ret = AllocDer(&ctx->certChain, idx, CERT_TYPE, ctx->heap); - if (ret == 0) { - XMEMCPY(ctx->certChain->buffer, chain, idx); - } - } - - /* on success WOLFSSL_X509 memory is responsibility of ctx */ - wolfSSL_X509_free(x509); - if (chain != NULL) - XFREE(chain, ctx->heap, DYNAMIC_TYPE_DER); - - return WOLFSSL_SUCCESS; -} - long wolfSSL_CTX_set_tlsext_status_arg(WOLFSSL_CTX* ctx, void* arg) { @@ -23952,579 +16668,6 @@ int wolfSSL_sk_SSL_COMP_num(WOLF_STACK_OF(WOLFSSL_COMP)* sk) #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ -#if !defined(NO_SESSION_CACHE) && (defined(OPENSSL_EXTRA) || \ - defined(HAVE_EXT_CACHE)) -/* stunnel 4.28 needs - * - * Callback that is called if a session tries to resume but could not find - * the session to resume it. - */ -void wolfSSL_CTX_sess_set_get_cb(WOLFSSL_CTX* ctx, - WOLFSSL_SESSION*(*f)(WOLFSSL*, const unsigned char*, int, int*)) -{ - if (ctx == NULL) - return; - -#ifdef HAVE_EXT_CACHE - ctx->get_sess_cb = f; -#else - (void)f; -#endif -} - -void wolfSSL_CTX_sess_set_new_cb(WOLFSSL_CTX* ctx, - int (*f)(WOLFSSL*, WOLFSSL_SESSION*)) -{ - if (ctx == NULL) - return; - -#ifdef HAVE_EXT_CACHE - ctx->new_sess_cb = f; -#else - (void)f; -#endif -} - -void wolfSSL_CTX_sess_set_remove_cb(WOLFSSL_CTX* ctx, void (*f)(WOLFSSL_CTX*, - WOLFSSL_SESSION*)) -{ - if (ctx == NULL) - return; - -#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) - ctx->rem_sess_cb = f; -#else - (void)f; -#endif -} - - -/* - * - * Note: It is expected that the importing and exporting function have been - * built with the same settings. For example if session tickets was - * enabled with the wolfSSL library exporting a session then it is - * expected to be turned on with the wolfSSL library importing the session. - */ -int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p) -{ - int size = 0; -#ifdef HAVE_EXT_CACHE - int idx = 0; -#ifdef SESSION_CERTS - int i; -#endif - - WOLFSSL_ENTER("wolfSSL_i2d_SSL_SESSION"); - - sess = ClientSessionToSession(sess); - if (sess == NULL) { - return BAD_FUNC_ARG; - } - - /* side | bornOn | timeout | sessionID len | sessionID | masterSecret | - * haveEMS */ - size += OPAQUE8_LEN + OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN + - sess->sessionIDSz + SECRET_LEN + OPAQUE8_LEN; - /* altSessionID */ - size += OPAQUE8_LEN + (sess->haveAltSessionID ? ID_LEN : 0); -#ifdef SESSION_CERTS - /* Peer chain */ - size += OPAQUE8_LEN; - for (i = 0; i < sess->chain.count; i++) - size += OPAQUE16_LEN + sess->chain.certs[i].length; -#endif -#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET)) - /* Protocol version */ - size += OPAQUE16_LEN; -#endif -#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ - (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) - /* cipher suite */ - size += OPAQUE16_LEN; -#endif -#ifndef NO_CLIENT_CACHE - /* ServerID len | ServerID */ - size += OPAQUE16_LEN + sess->idLen; -#endif -#ifdef WOLFSSL_SESSION_ID_CTX - /* session context ID len | session context ID */ - size += OPAQUE8_LEN + sess->sessionCtxSz; -#endif -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - /* peerVerifyRet */ - size += OPAQUE8_LEN; -#endif -#ifdef WOLFSSL_TLS13 - /* namedGroup */ - size += OPAQUE16_LEN; -#endif -#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) -#ifdef WOLFSSL_TLS13 -#ifdef WOLFSSL_32BIT_MILLI_TIME - /* ticketSeen | ticketAdd */ - size += OPAQUE32_LEN + OPAQUE32_LEN; -#else - /* ticketSeen Hi 32 bits | ticketSeen Lo 32 bits | ticketAdd */ - size += OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE32_LEN; -#endif - /* ticketNonce */ - size += OPAQUE8_LEN + sess->ticketNonce.len; -#endif -#ifdef WOLFSSL_EARLY_DATA - size += OPAQUE32_LEN; -#endif -#endif -#ifdef HAVE_SESSION_TICKET - /* ticket len | ticket */ - size += OPAQUE16_LEN + sess->ticketLen; -#endif - - if (p != NULL) { - unsigned char *data; - - if (*p == NULL) - *p = (unsigned char*)XMALLOC(size, NULL, DYNAMIC_TYPE_OPENSSL); - if (*p == NULL) - return 0; - data = *p; - - data[idx++] = sess->side; - c32toa(sess->bornOn, data + idx); idx += OPAQUE32_LEN; - c32toa(sess->timeout, data + idx); idx += OPAQUE32_LEN; - data[idx++] = sess->sessionIDSz; - XMEMCPY(data + idx, sess->sessionID, sess->sessionIDSz); - idx += sess->sessionIDSz; - XMEMCPY(data + idx, sess->masterSecret, SECRET_LEN); idx += SECRET_LEN; - data[idx++] = (byte)sess->haveEMS; - data[idx++] = sess->haveAltSessionID ? ID_LEN : 0; - if (sess->haveAltSessionID) { - XMEMCPY(data + idx, sess->altSessionID, ID_LEN); - idx += ID_LEN; - } -#ifdef SESSION_CERTS - data[idx++] = (byte)sess->chain.count; - for (i = 0; i < sess->chain.count; i++) { - c16toa((word16)sess->chain.certs[i].length, data + idx); - idx += OPAQUE16_LEN; - XMEMCPY(data + idx, sess->chain.certs[i].buffer, - sess->chain.certs[i].length); - idx += sess->chain.certs[i].length; - } -#endif -#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET)) - data[idx++] = sess->version.major; - data[idx++] = sess->version.minor; -#endif -#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ - (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) - data[idx++] = sess->cipherSuite0; - data[idx++] = sess->cipherSuite; -#endif -#ifndef NO_CLIENT_CACHE - c16toa(sess->idLen, data + idx); idx += OPAQUE16_LEN; - XMEMCPY(data + idx, sess->serverID, sess->idLen); - idx += sess->idLen; -#endif -#ifdef WOLFSSL_SESSION_ID_CTX - data[idx++] = sess->sessionCtxSz; - XMEMCPY(data + idx, sess->sessionCtx, sess->sessionCtxSz); - idx += sess->sessionCtxSz; -#endif -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - data[idx++] = sess->peerVerifyRet; -#endif -#ifdef WOLFSSL_TLS13 - c16toa(sess->namedGroup, data + idx); - idx += OPAQUE16_LEN; -#endif -#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) -#ifdef WOLFSSL_TLS13 -#ifdef WOLFSSL_32BIT_MILLI_TIME - c32toa(sess->ticketSeen, data + idx); - idx += OPAQUE32_LEN; -#else - c32toa((word32)(sess->ticketSeen >> 32), data + idx); - idx += OPAQUE32_LEN; - c32toa((word32)sess->ticketSeen, data + idx); - idx += OPAQUE32_LEN; -#endif - c32toa(sess->ticketAdd, data + idx); - idx += OPAQUE32_LEN; - data[idx++] = sess->ticketNonce.len; - XMEMCPY(data + idx, sess->ticketNonce.data, sess->ticketNonce.len); - idx += sess->ticketNonce.len; -#endif -#ifdef WOLFSSL_EARLY_DATA - c32toa(sess->maxEarlyDataSz, data + idx); - idx += OPAQUE32_LEN; -#endif -#endif -#ifdef HAVE_SESSION_TICKET - c16toa(sess->ticketLen, data + idx); idx += OPAQUE16_LEN; - XMEMCPY(data + idx, sess->ticket, sess->ticketLen); - idx += sess->ticketLen; -#endif - } -#endif - - (void)sess; - (void)p; -#ifdef HAVE_EXT_CACHE - (void)idx; -#endif - - return size; -} - - -/* TODO: no function to free new session. - * - * Note: It is expected that the importing and exporting function have been - * built with the same settings. For example if session tickets was - * enabled with the wolfSSL library exporting a session then it is - * expected to be turned on with the wolfSSL library importing the session. - */ -WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess, - const unsigned char** p, long i) -{ - WOLFSSL_SESSION* s = NULL; - int ret = 0; -#if defined(HAVE_EXT_CACHE) - int idx = 0; - byte* data; -#ifdef SESSION_CERTS - int j; - word16 length; -#endif -#endif /* HAVE_EXT_CACHE */ - - (void)p; - (void)i; - (void)ret; - (void)sess; - -#ifdef HAVE_EXT_CACHE - if (p == NULL || *p == NULL) - return NULL; - - s = wolfSSL_SESSION_new(); - if (s == NULL) - return NULL; - - idx = 0; - data = (byte*)*p; - - /* side | bornOn | timeout | sessionID len */ - if (i < OPAQUE8_LEN + OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN) { - ret = BUFFER_ERROR; - goto end; - } - s->side = data[idx++]; - ato32(data + idx, &s->bornOn); idx += OPAQUE32_LEN; - ato32(data + idx, &s->timeout); idx += OPAQUE32_LEN; - s->sessionIDSz = data[idx++]; - - /* sessionID | secret | haveEMS | haveAltSessionID */ - if (i - idx < s->sessionIDSz + SECRET_LEN + OPAQUE8_LEN + OPAQUE8_LEN) { - ret = BUFFER_ERROR; - goto end; - } - XMEMCPY(s->sessionID, data + idx, s->sessionIDSz); - idx += s->sessionIDSz; - XMEMCPY(s->masterSecret, data + idx, SECRET_LEN); idx += SECRET_LEN; - s->haveEMS = data[idx++]; - if (data[idx] != ID_LEN && data[idx] != 0) { - ret = BUFFER_ERROR; - goto end; - } - s->haveAltSessionID = data[idx++] == ID_LEN; - - /* altSessionID */ - if (s->haveAltSessionID) { - if (i - idx < ID_LEN) { - ret = BUFFER_ERROR; - goto end; - } - XMEMCPY(s->altSessionID, data + idx, ID_LEN); idx += ID_LEN; - } - -#ifdef SESSION_CERTS - /* Certificate chain */ - if (i - idx == 0) { - ret = BUFFER_ERROR; - goto end; - } - s->chain.count = data[idx++]; - for (j = 0; j < s->chain.count; j++) { - if (i - idx < OPAQUE16_LEN) { - ret = BUFFER_ERROR; - goto end; - } - ato16(data + idx, &length); idx += OPAQUE16_LEN; - s->chain.certs[j].length = length; - if (i - idx < length) { - ret = BUFFER_ERROR; - goto end; - } - XMEMCPY(s->chain.certs[j].buffer, data + idx, length); - idx += length; - } -#endif -#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET)) - /* Protocol Version */ - if (i - idx < OPAQUE16_LEN) { - ret = BUFFER_ERROR; - goto end; - } - s->version.major = data[idx++]; - s->version.minor = data[idx++]; -#endif -#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ - (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) - /* Cipher suite */ - if (i - idx < OPAQUE16_LEN) { - ret = BUFFER_ERROR; - goto end; - } - s->cipherSuite0 = data[idx++]; - s->cipherSuite = data[idx++]; -#endif -#ifndef NO_CLIENT_CACHE - /* ServerID len */ - if (i - idx < OPAQUE16_LEN) { - ret = BUFFER_ERROR; - goto end; - } - ato16(data + idx, &s->idLen); idx += OPAQUE16_LEN; - - /* ServerID */ - if (i - idx < s->idLen) { - ret = BUFFER_ERROR; - goto end; - } - XMEMCPY(s->serverID, data + idx, s->idLen); idx += s->idLen; -#endif -#ifdef WOLFSSL_SESSION_ID_CTX - /* byte for length of session context ID */ - if (i - idx < OPAQUE8_LEN) { - ret = BUFFER_ERROR; - goto end; - } - s->sessionCtxSz = data[idx++]; - - /* app session context ID */ - if (i - idx < s->sessionCtxSz) { - ret = BUFFER_ERROR; - goto end; - } - XMEMCPY(s->sessionCtx, data + idx, s->sessionCtxSz); idx += s->sessionCtxSz; -#endif -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - /* byte for peerVerifyRet */ - if (i - idx < OPAQUE8_LEN) { - ret = BUFFER_ERROR; - goto end; - } - s->peerVerifyRet = data[idx++]; -#endif -#ifdef WOLFSSL_TLS13 - if (i - idx < OPAQUE16_LEN) { - ret = BUFFER_ERROR; - goto end; - } - ato16(data + idx, &s->namedGroup); - idx += OPAQUE16_LEN; -#endif -#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) -#ifdef WOLFSSL_TLS13 - if (i - idx < (OPAQUE32_LEN * 2)) { - ret = BUFFER_ERROR; - goto end; - } -#ifdef WOLFSSL_32BIT_MILLI_TIME - ato32(data + idx, &s->ticketSeen); - idx += OPAQUE32_LEN; -#else - { - word32 seenHi, seenLo; - - ato32(data + idx, &seenHi); - idx += OPAQUE32_LEN; - ato32(data + idx, &seenLo); - idx += OPAQUE32_LEN; - s->ticketSeen = ((sword64)seenHi << 32) + seenLo; - } -#endif - ato32(data + idx, &s->ticketAdd); - idx += OPAQUE32_LEN; - if (i - idx < OPAQUE8_LEN) { - ret = BUFFER_ERROR; - goto end; - } - s->ticketNonce.len = data[idx++]; - - if (i - idx < s->ticketNonce.len) { - ret = BUFFER_ERROR; - goto end; - } -#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) - ret = SessionTicketNoncePopulate(s, data + idx, s->ticketNonce.len); - if (ret != 0) - goto end; -#else - if (s->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ) { - ret = BUFFER_ERROR; - goto end; - } - XMEMCPY(s->ticketNonce.data, data + idx, s->ticketNonce.len); -#endif /* defined(WOLFSSL_TICKET_NONCE_MALLOC) && FIPS_VERSION_GE(5,3) */ - - idx += s->ticketNonce.len; -#endif -#ifdef WOLFSSL_EARLY_DATA - if (i - idx < OPAQUE32_LEN) { - ret = BUFFER_ERROR; - goto end; - } - ato32(data + idx, &s->maxEarlyDataSz); - idx += OPAQUE32_LEN; -#endif -#endif -#ifdef HAVE_SESSION_TICKET - /* ticket len */ - if (i - idx < OPAQUE16_LEN) { - ret = BUFFER_ERROR; - goto end; - } - ato16(data + idx, &s->ticketLen); idx += OPAQUE16_LEN; - - /* Dispose of ol dynamic ticket and ensure space for new ticket. */ - if (s->ticketLenAlloc > 0) { - XFREE(s->ticket, NULL, DYNAMIC_TYPE_SESSION_TICK); - } - if (s->ticketLen <= SESSION_TICKET_LEN) - s->ticket = s->staticTicket; - else { - s->ticket = (byte*)XMALLOC(s->ticketLen, NULL, - DYNAMIC_TYPE_SESSION_TICK); - if (s->ticket == NULL) { - ret = MEMORY_ERROR; - goto end; - } - s->ticketLenAlloc = (word16)s->ticketLen; - } - - /* ticket */ - if (i - idx < s->ticketLen) { - ret = BUFFER_ERROR; - goto end; - } - XMEMCPY(s->ticket, data + idx, s->ticketLen); idx += s->ticketLen; -#endif - (void)idx; - - if (sess != NULL) { - *sess = s; - } - - s->isSetup = 1; - - *p += idx; - -end: - if (ret != 0 && (sess == NULL || *sess != s)) { - wolfSSL_FreeSession(NULL, s); - s = NULL; - } -#endif /* HAVE_EXT_CACHE */ - return s; -} - -/* Check if there is a session ticket associated with this WOLFSSL_SESSION. - * - * sess - pointer to WOLFSSL_SESSION struct - * - * Returns 1 if has session ticket, otherwise 0 */ -int wolfSSL_SESSION_has_ticket(const WOLFSSL_SESSION* sess) -{ - WOLFSSL_ENTER("wolfSSL_SESSION_has_ticket"); -#ifdef HAVE_SESSION_TICKET - sess = ClientSessionToSession(sess); - if (sess) { - if ((sess->ticketLen > 0) && (sess->ticket != NULL)) { - return WOLFSSL_SUCCESS; - } - } -#else - (void)sess; -#endif - return WOLFSSL_FAILURE; -} - -unsigned long wolfSSL_SESSION_get_ticket_lifetime_hint( - const WOLFSSL_SESSION* sess) -{ - WOLFSSL_ENTER("wolfSSL_SESSION_get_ticket_lifetime_hint"); - sess = ClientSessionToSession(sess); - if (sess) { - return sess->timeout; - } - return 0; -} - -long wolfSSL_SESSION_get_timeout(const WOLFSSL_SESSION* sess) -{ - long timeout = 0; - WOLFSSL_ENTER("wolfSSL_SESSION_get_timeout"); - sess = ClientSessionToSession(sess); - if (sess) - timeout = sess->timeout; - return timeout; -} - -long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* ses, long t) -{ - word32 tmptime; - - ses = ClientSessionToSession(ses); - if (ses == NULL || t < 0) { - return BAD_FUNC_ARG; - } - - tmptime = t & 0xFFFFFFFF; - ses->timeout = tmptime; - - return WOLFSSL_SUCCESS; -} - -long wolfSSL_SESSION_get_time(const WOLFSSL_SESSION* sess) -{ - long bornOn = 0; - WOLFSSL_ENTER("wolfSSL_SESSION_get_time"); - sess = ClientSessionToSession(sess); - if (sess) - bornOn = sess->bornOn; - return bornOn; -} - -long wolfSSL_SESSION_set_time(WOLFSSL_SESSION *ses, long t) -{ - - ses = ClientSessionToSession(ses); - if (ses == NULL || t < 0) { - return 0; - } - ses->bornOn = (word32)t; - return t; -} - -#endif /* !NO_SESSION_CACHE && OPENSSL_EXTRA || HAVE_EXT_CACHE */ - #ifdef OPENSSL_EXTRA #if defined(HAVE_EX_DATA) && !defined(NO_FILESYSTEM) @@ -24604,50 +16747,50 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = { #ifndef NO_CERTS /* oidCertExtType */ { NID_basic_constraints, BASIC_CA_OID, oidCertExtType, "basicConstraints", - "X509v3 Basic Constraints"}, + "X509v3 Basic Constraints"}, { NID_subject_alt_name, ALT_NAMES_OID, oidCertExtType, "subjectAltName", - "X509v3 Subject Alternative Name"}, - { NID_crl_distribution_points, CRL_DIST_OID, oidCertExtType, "crlDistributionPoints", - "X509v3 CRL Distribution Points"}, + "X509v3 Subject Alternative Name"}, + { NID_crl_distribution_points, CRL_DIST_OID, oidCertExtType, + "crlDistributionPoints", "X509v3 CRL Distribution Points"}, { NID_info_access, AUTH_INFO_OID, oidCertExtType, "authorityInfoAccess", - "Authority Information Access"}, + "Authority Information Access"}, { NID_authority_key_identifier, AUTH_KEY_OID, oidCertExtType, - "authorityKeyIdentifier", "X509v3 Authority Key Identifier"}, + "authorityKeyIdentifier", "X509v3 Authority Key Identifier"}, { NID_subject_key_identifier, SUBJ_KEY_OID, oidCertExtType, - "subjectKeyIdentifier", "X509v3 Subject Key Identifier"}, + "subjectKeyIdentifier", "X509v3 Subject Key Identifier"}, { NID_key_usage, KEY_USAGE_OID, oidCertExtType, "keyUsage", - "X509v3 Key Usage"}, + "X509v3 Key Usage"}, { NID_inhibit_any_policy, INHIBIT_ANY_OID, oidCertExtType, - "inhibitAnyPolicy", "X509v3 Inhibit Any Policy"}, + "inhibitAnyPolicy", "X509v3 Inhibit Any Policy"}, { NID_ext_key_usage, EXT_KEY_USAGE_OID, oidCertExtType, - "extendedKeyUsage", "X509v3 Extended Key Usage"}, + "extendedKeyUsage", "X509v3 Extended Key Usage"}, { NID_name_constraints, NAME_CONS_OID, oidCertExtType, - "nameConstraints", "X509v3 Name Constraints"}, + "nameConstraints", "X509v3 Name Constraints"}, { NID_certificate_policies, CERT_POLICY_OID, oidCertExtType, - "certificatePolicies", "X509v3 Certificate Policies"}, + "certificatePolicies", "X509v3 Certificate Policies"}, /* oidCertAuthInfoType */ { NID_ad_OCSP, AIA_OCSP_OID, oidCertAuthInfoType, "OCSP", - "OCSP"}, + "OCSP"}, { NID_ad_ca_issuers, AIA_CA_ISSUER_OID, oidCertAuthInfoType, - "caIssuers", "CA Issuers"}, + "caIssuers", "CA Issuers"}, /* oidCertPolicyType */ { NID_any_policy, CP_ANY_OID, oidCertPolicyType, "anyPolicy", - "X509v3 Any Policy"}, + "X509v3 Any Policy"}, /* oidCertAltNameType */ { NID_hw_name_oid, HW_NAME_OID, oidCertAltNameType, "Hardware name",""}, /* oidCertKeyUseType */ { NID_anyExtendedKeyUsage, EKU_ANY_OID, oidCertKeyUseType, - "anyExtendedKeyUsage", "Any Extended Key Usage"}, + "anyExtendedKeyUsage", "Any Extended Key Usage"}, { EKU_SERVER_AUTH_OID, EKU_SERVER_AUTH_OID, oidCertKeyUseType, - "serverAuth", "TLS Web Server Authentication"}, + "serverAuth", "TLS Web Server Authentication"}, { EKU_CLIENT_AUTH_OID, EKU_CLIENT_AUTH_OID, oidCertKeyUseType, - "clientAuth", "TLS Web Client Authentication"}, + "clientAuth", "TLS Web Client Authentication"}, { EKU_OCSP_SIGN_OID, EKU_OCSP_SIGN_OID, oidCertKeyUseType, - "OCSPSigning", "OCSP Signing"}, + "OCSPSigning", "OCSP Signing"}, /* oidCertNameType */ { NID_commonName, NID_commonName, oidCertNameType, "CN", "commonName"}, @@ -24655,31 +16798,32 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = { { NID_surname, NID_surname, oidCertNameType, "SN", "surname"}, #endif { NID_serialNumber, NID_serialNumber, oidCertNameType, "serialNumber", - "serialNumber"}, + "serialNumber"}, { NID_userId, NID_userId, oidCertNameType, "UID", "userid"}, { NID_countryName, NID_countryName, oidCertNameType, "C", "countryName"}, { NID_localityName, NID_localityName, oidCertNameType, "L", "localityName"}, { NID_stateOrProvinceName, NID_stateOrProvinceName, oidCertNameType, "ST", - "stateOrProvinceName"}, + "stateOrProvinceName"}, { NID_streetAddress, NID_streetAddress, oidCertNameType, "street", - "streetAddress"}, + "streetAddress"}, { NID_organizationName, NID_organizationName, oidCertNameType, "O", - "organizationName"}, + "organizationName"}, { NID_organizationalUnitName, NID_organizationalUnitName, oidCertNameType, - "OU", "organizationalUnitName"}, + "OU", "organizationalUnitName"}, { NID_emailAddress, NID_emailAddress, oidCertNameType, "emailAddress", - "emailAddress"}, + "emailAddress"}, { NID_domainComponent, NID_domainComponent, oidCertNameType, "DC", - "domainComponent"}, + "domainComponent"}, { NID_favouriteDrink, NID_favouriteDrink, oidCertNameType, "favouriteDrink", - "favouriteDrink"}, - { NID_businessCategory, NID_businessCategory, oidCertNameType, "businessCategory", - "businessCategory"}, - { NID_jurisdictionCountryName, NID_jurisdictionCountryName, oidCertNameType, "jurisdictionC", - "jurisdictionCountryName"}, + "favouriteDrink"}, + { NID_businessCategory, NID_businessCategory, oidCertNameType, + "businessCategory", "businessCategory"}, + { NID_jurisdictionCountryName, NID_jurisdictionCountryName, oidCertNameType, + "jurisdictionC", "jurisdictionCountryName"}, { NID_jurisdictionStateOrProvinceName, NID_jurisdictionStateOrProvinceName, - oidCertNameType, "jurisdictionST", "jurisdictionStateOrProvinceName"}, - { NID_postalCode, NID_postalCode, oidCertNameType, "postalCode", "postalCode"}, + oidCertNameType, "jurisdictionST", "jurisdictionStateOrProvinceName"}, + { NID_postalCode, NID_postalCode, oidCertNameType, "postalCode", + "postalCode"}, { NID_userId, NID_userId, oidCertNameType, "UID", "userId"}, #if defined(WOLFSSL_CERT_REQ) || defined(WOLFSSL_CERT_NAME_ALL) @@ -24745,54 +16889,54 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = { #ifndef NO_SHA { NID_dsaWithSHA1, CTC_SHAwDSA, oidSigType, "DSA-SHA1", "dsaWithSHA1"}, { NID_dsa_with_SHA256, CTC_SHA256wDSA, oidSigType, "dsa_with_SHA256", - "dsa_with_SHA256"}, + "dsa_with_SHA256"}, #endif #endif /* NO_DSA */ #ifndef NO_RSA #ifdef WOLFSSL_MD2 { NID_md2WithRSAEncryption, CTC_MD2wRSA, oidSigType, "RSA-MD2", - "md2WithRSAEncryption"}, + "md2WithRSAEncryption"}, #endif #ifndef NO_MD5 { NID_md5WithRSAEncryption, CTC_MD5wRSA, oidSigType, "RSA-MD5", - "md5WithRSAEncryption"}, + "md5WithRSAEncryption"}, #endif #ifndef NO_SHA { NID_sha1WithRSAEncryption, CTC_SHAwRSA, oidSigType, "RSA-SHA1", - "sha1WithRSAEncryption"}, + "sha1WithRSAEncryption"}, #endif #ifdef WOLFSSL_SHA224 { NID_sha224WithRSAEncryption, CTC_SHA224wRSA, oidSigType, "RSA-SHA224", - "sha224WithRSAEncryption"}, + "sha224WithRSAEncryption"}, #endif #ifndef NO_SHA256 { NID_sha256WithRSAEncryption, CTC_SHA256wRSA, oidSigType, "RSA-SHA256", - "sha256WithRSAEncryption"}, + "sha256WithRSAEncryption"}, #endif #ifdef WOLFSSL_SHA384 { NID_sha384WithRSAEncryption, CTC_SHA384wRSA, oidSigType, "RSA-SHA384", - "sha384WithRSAEncryption"}, + "sha384WithRSAEncryption"}, #endif #ifdef WOLFSSL_SHA512 { NID_sha512WithRSAEncryption, CTC_SHA512wRSA, oidSigType, "RSA-SHA512", - "sha512WithRSAEncryption"}, + "sha512WithRSAEncryption"}, #endif #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 { NID_RSA_SHA3_224, CTC_SHA3_224wRSA, oidSigType, "RSA-SHA3-224", - "sha3-224WithRSAEncryption"}, + "sha3-224WithRSAEncryption"}, #endif #ifndef WOLFSSL_NOSHA3_256 { NID_RSA_SHA3_256, CTC_SHA3_256wRSA, oidSigType, "RSA-SHA3-256", - "sha3-256WithRSAEncryption"}, + "sha3-256WithRSAEncryption"}, #endif #ifndef WOLFSSL_NOSHA3_384 { NID_RSA_SHA3_384, CTC_SHA3_384wRSA, oidSigType, "RSA-SHA3-384", - "sha3-384WithRSAEncryption"}, + "sha3-384WithRSAEncryption"}, #endif #ifndef WOLFSSL_NOSHA3_512 { NID_RSA_SHA3_512, CTC_SHA3_512wRSA, oidSigType, "RSA-SHA3-512", - "sha3-512WithRSAEncryption"}, + "sha3-512WithRSAEncryption"}, #endif #endif #ifdef WC_RSA_PSS @@ -24801,36 +16945,41 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = { #endif /* NO_RSA */ #ifdef HAVE_ECC #ifndef NO_SHA - { NID_ecdsa_with_SHA1, CTC_SHAwECDSA, oidSigType, "ecdsa-with-SHA1", "shaWithECDSA"}, + { NID_ecdsa_with_SHA1, CTC_SHAwECDSA, oidSigType, "ecdsa-with-SHA1", + "shaWithECDSA"}, #endif #ifdef WOLFSSL_SHA224 - { NID_ecdsa_with_SHA224, CTC_SHA224wECDSA, oidSigType, "ecdsa-with-SHA224","sha224WithECDSA"}, + { NID_ecdsa_with_SHA224, CTC_SHA224wECDSA, oidSigType, + "ecdsa-with-SHA224","sha224WithECDSA"}, #endif #ifndef NO_SHA256 - { NID_ecdsa_with_SHA256, CTC_SHA256wECDSA, oidSigType, "ecdsa-with-SHA256","sha256WithECDSA"}, + { NID_ecdsa_with_SHA256, CTC_SHA256wECDSA, oidSigType, + "ecdsa-with-SHA256","sha256WithECDSA"}, #endif #ifdef WOLFSSL_SHA384 - { NID_ecdsa_with_SHA384, CTC_SHA384wECDSA, oidSigType, "ecdsa-with-SHA384","sha384WithECDSA"}, + { NID_ecdsa_with_SHA384, CTC_SHA384wECDSA, oidSigType, + "ecdsa-with-SHA384","sha384WithECDSA"}, #endif #ifdef WOLFSSL_SHA512 - { NID_ecdsa_with_SHA512, CTC_SHA512wECDSA, oidSigType, "ecdsa-with-SHA512","sha512WithECDSA"}, + { NID_ecdsa_with_SHA512, CTC_SHA512wECDSA, oidSigType, + "ecdsa-with-SHA512","sha512WithECDSA"}, #endif #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 - { NID_ecdsa_with_SHA3_224, CTC_SHA3_224wECDSA, oidSigType, "id-ecdsa-with-SHA3-224", - "ecdsa_with_SHA3-224"}, + { NID_ecdsa_with_SHA3_224, CTC_SHA3_224wECDSA, oidSigType, + "id-ecdsa-with-SHA3-224", "ecdsa_with_SHA3-224"}, #endif #ifndef WOLFSSL_NOSHA3_256 - { NID_ecdsa_with_SHA3_256, CTC_SHA3_256wECDSA, oidSigType, "id-ecdsa-with-SHA3-256", - "ecdsa_with_SHA3-256"}, + { NID_ecdsa_with_SHA3_256, CTC_SHA3_256wECDSA, oidSigType, + "id-ecdsa-with-SHA3-256", "ecdsa_with_SHA3-256"}, #endif #ifndef WOLFSSL_NOSHA3_384 - { NID_ecdsa_with_SHA3_384, CTC_SHA3_384wECDSA, oidSigType, "id-ecdsa-with-SHA3-384", - "ecdsa_with_SHA3-384"}, + { NID_ecdsa_with_SHA3_384, CTC_SHA3_384wECDSA, oidSigType, + "id-ecdsa-with-SHA3-384", "ecdsa_with_SHA3-384"}, #endif #ifndef WOLFSSL_NOSHA3_512 - { NID_ecdsa_with_SHA3_512, CTC_SHA3_512wECDSA, oidSigType, "id-ecdsa-with-SHA3-512", - "ecdsa_with_SHA3-512"}, + { NID_ecdsa_with_SHA3_512, CTC_SHA3_512wECDSA, oidSigType, + "id-ecdsa-with-SHA3-512", "ecdsa_with_SHA3-512"}, #endif #endif #endif /* HAVE_ECC */ @@ -24840,7 +16989,8 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = { { NID_dsa, DSAk, oidKeyType, "DSA", "dsaEncryption"}, #endif /* NO_DSA */ #ifndef NO_RSA - { NID_rsaEncryption, RSAk, oidKeyType, "rsaEncryption", "rsaEncryption"}, + { NID_rsaEncryption, RSAk, oidKeyType, "rsaEncryption", + "rsaEncryption"}, #ifdef WC_RSA_PSS { NID_rsassaPss, RSAPSSk, oidKeyType, "RSASSA-PSS", "rsassaPss"}, #endif @@ -24850,7 +17000,8 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = { "id-ecPublicKey"}, #endif /* HAVE_ECC */ #ifndef NO_DH - { NID_dhKeyAgreement, DHk, oidKeyType, "dhKeyAgreement", "dhKeyAgreement"}, + { NID_dhKeyAgreement, DHk, oidKeyType, "dhKeyAgreement", + "dhKeyAgreement"}, #endif #ifdef HAVE_ED448 { NID_ED448, ED448k, oidKeyType, "ED448", "ED448"}, @@ -24877,41 +17028,68 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = { /* oidCurveType */ #ifdef HAVE_ECC - { NID_X9_62_prime192v1, ECC_SECP192R1_OID, oidCurveType, "prime192v1", "prime192v1"}, - { NID_X9_62_prime192v2, ECC_PRIME192V2_OID, oidCurveType, "prime192v2", "prime192v2"}, - { NID_X9_62_prime192v3, ECC_PRIME192V3_OID, oidCurveType, "prime192v3", "prime192v3"}, + { NID_X9_62_prime192v1, ECC_SECP192R1_OID, oidCurveType, "prime192v1", + "prime192v1"}, + { NID_X9_62_prime192v2, ECC_PRIME192V2_OID, oidCurveType, "prime192v2", + "prime192v2"}, + { NID_X9_62_prime192v3, ECC_PRIME192V3_OID, oidCurveType, "prime192v3", + "prime192v3"}, - { NID_X9_62_prime239v1, ECC_PRIME239V1_OID, oidCurveType, "prime239v1", "prime239v1"}, - { NID_X9_62_prime239v2, ECC_PRIME239V2_OID, oidCurveType, "prime239v2", "prime239v2"}, - { NID_X9_62_prime239v3, ECC_PRIME239V3_OID, oidCurveType, "prime239v3", "prime239v3"}, + { NID_X9_62_prime239v1, ECC_PRIME239V1_OID, oidCurveType, "prime239v1", + "prime239v1"}, + { NID_X9_62_prime239v2, ECC_PRIME239V2_OID, oidCurveType, "prime239v2", + "prime239v2"}, + { NID_X9_62_prime239v3, ECC_PRIME239V3_OID, oidCurveType, "prime239v3", + "prime239v3"}, - { NID_X9_62_prime256v1, ECC_SECP256R1_OID, oidCurveType, "prime256v1", "prime256v1"}, + { NID_X9_62_prime256v1, ECC_SECP256R1_OID, oidCurveType, "prime256v1", + "prime256v1"}, - { NID_secp112r1, ECC_SECP112R1_OID, oidCurveType, "secp112r1", "secp112r1"}, - { NID_secp112r2, ECC_SECP112R2_OID, oidCurveType, "secp112r2", "secp112r2"}, + { NID_secp112r1, ECC_SECP112R1_OID, oidCurveType, "secp112r1", + "secp112r1"}, + { NID_secp112r2, ECC_SECP112R2_OID, oidCurveType, "secp112r2", + "secp112r2"}, - { NID_secp128r1, ECC_SECP128R1_OID, oidCurveType, "secp128r1", "secp128r1"}, - { NID_secp128r2, ECC_SECP128R2_OID, oidCurveType, "secp128r2", "secp128r2"}, + { NID_secp128r1, ECC_SECP128R1_OID, oidCurveType, "secp128r1", + "secp128r1"}, + { NID_secp128r2, ECC_SECP128R2_OID, oidCurveType, "secp128r2", + "secp128r2"}, - { NID_secp160r1, ECC_SECP160R1_OID, oidCurveType, "secp160r1", "secp160r1"}, - { NID_secp160r2, ECC_SECP160R2_OID, oidCurveType, "secp160r2", "secp160r2"}, + { NID_secp160r1, ECC_SECP160R1_OID, oidCurveType, "secp160r1", + "secp160r1"}, + { NID_secp160r2, ECC_SECP160R2_OID, oidCurveType, "secp160r2", + "secp160r2"}, - { NID_secp224r1, ECC_SECP224R1_OID, oidCurveType, "secp224r1", "secp224r1"}, - { NID_secp384r1, ECC_SECP384R1_OID, oidCurveType, "secp384r1", "secp384r1"}, - { NID_secp521r1, ECC_SECP521R1_OID, oidCurveType, "secp521r1", "secp521r1"}, + { NID_secp224r1, ECC_SECP224R1_OID, oidCurveType, "secp224r1", + "secp224r1"}, + { NID_secp384r1, ECC_SECP384R1_OID, oidCurveType, "secp384r1", + "secp384r1"}, + { NID_secp521r1, ECC_SECP521R1_OID, oidCurveType, "secp521r1", + "secp521r1"}, - { NID_secp160k1, ECC_SECP160K1_OID, oidCurveType, "secp160k1", "secp160k1"}, - { NID_secp192k1, ECC_SECP192K1_OID, oidCurveType, "secp192k1", "secp192k1"}, - { NID_secp224k1, ECC_SECP224K1_OID, oidCurveType, "secp224k1", "secp224k1"}, - { NID_secp256k1, ECC_SECP256K1_OID, oidCurveType, "secp256k1", "secp256k1"}, + { NID_secp160k1, ECC_SECP160K1_OID, oidCurveType, "secp160k1", + "secp160k1"}, + { NID_secp192k1, ECC_SECP192K1_OID, oidCurveType, "secp192k1", + "secp192k1"}, + { NID_secp224k1, ECC_SECP224K1_OID, oidCurveType, "secp224k1", + "secp224k1"}, + { NID_secp256k1, ECC_SECP256K1_OID, oidCurveType, "secp256k1", + "secp256k1"}, - { NID_brainpoolP160r1, ECC_BRAINPOOLP160R1_OID, oidCurveType, "brainpoolP160r1", "brainpoolP160r1"}, - { NID_brainpoolP192r1, ECC_BRAINPOOLP192R1_OID, oidCurveType, "brainpoolP192r1", "brainpoolP192r1"}, - { NID_brainpoolP224r1, ECC_BRAINPOOLP224R1_OID, oidCurveType, "brainpoolP224r1", "brainpoolP224r1"}, - { NID_brainpoolP256r1, ECC_BRAINPOOLP256R1_OID, oidCurveType, "brainpoolP256r1", "brainpoolP256r1"}, - { NID_brainpoolP320r1, ECC_BRAINPOOLP320R1_OID, oidCurveType, "brainpoolP320r1", "brainpoolP320r1"}, - { NID_brainpoolP384r1, ECC_BRAINPOOLP384R1_OID, oidCurveType, "brainpoolP384r1", "brainpoolP384r1"}, - { NID_brainpoolP512r1, ECC_BRAINPOOLP512R1_OID, oidCurveType, "brainpoolP512r1", "brainpoolP512r1"}, + { NID_brainpoolP160r1, ECC_BRAINPOOLP160R1_OID, oidCurveType, + "brainpoolP160r1", "brainpoolP160r1"}, + { NID_brainpoolP192r1, ECC_BRAINPOOLP192R1_OID, oidCurveType, + "brainpoolP192r1", "brainpoolP192r1"}, + { NID_brainpoolP224r1, ECC_BRAINPOOLP224R1_OID, oidCurveType, + "brainpoolP224r1", "brainpoolP224r1"}, + { NID_brainpoolP256r1, ECC_BRAINPOOLP256R1_OID, oidCurveType, + "brainpoolP256r1", "brainpoolP256r1"}, + { NID_brainpoolP320r1, ECC_BRAINPOOLP320R1_OID, oidCurveType, + "brainpoolP320r1", "brainpoolP320r1"}, + { NID_brainpoolP384r1, ECC_BRAINPOOLP384R1_OID, oidCurveType, + "brainpoolP384r1", "brainpoolP384r1"}, + { NID_brainpoolP512r1, ECC_BRAINPOOLP512R1_OID, oidCurveType, + "brainpoolP512r1", "brainpoolP512r1"}, #ifdef WOLFSSL_SM2 { NID_sm2, ECC_SM2P256V1_OID, oidCurveType, "sm2", "sm2"}, @@ -24933,15 +17111,15 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = { { NID_des3, DES3b, oidBlkType, "DES-EDE3-CBC", "des-ede3-cbc"}, #endif /* !NO_DES3 */ #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) - { NID_chacha20_poly1305, NID_chacha20_poly1305, oidBlkType, "ChaCha20-Poly1305", "chacha20-poly1305"}, + { NID_chacha20_poly1305, NID_chacha20_poly1305, oidBlkType, + "ChaCha20-Poly1305", "chacha20-poly1305"}, #endif /* oidOcspType */ #ifdef HAVE_OCSP - { NID_id_pkix_OCSP_basic, OCSP_BASIC_OID, oidOcspType, "basicOCSPResponse", - "Basic OCSP Response"}, - { OCSP_NONCE_OID, OCSP_NONCE_OID, oidOcspType, "Nonce", - "OCSP Nonce"}, + { NID_id_pkix_OCSP_basic, OCSP_BASIC_OID, oidOcspType, + "basicOCSPResponse", "Basic OCSP Response"}, + { OCSP_NONCE_OID, OCSP_NONCE_OID, oidOcspType, "Nonce", "OCSP Nonce"}, #endif /* HAVE_OCSP */ #ifndef NO_PWDBASED @@ -24950,22 +17128,25 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = { /* oidPBEType */ { PBE_SHA1_RC4_128, PBE_SHA1_RC4_128, oidPBEType, - "PBE-SHA1-RC4-128", "pbeWithSHA1And128BitRC4"}, + "PBE-SHA1-RC4-128", "pbeWithSHA1And128BitRC4"}, { PBE_SHA1_DES, PBE_SHA1_DES, oidPBEType, "PBE-SHA1-DES", - "pbeWithSHA1AndDES-CBC"}, + "pbeWithSHA1AndDES-CBC"}, { PBE_SHA1_DES3, PBE_SHA1_DES3, oidPBEType, "PBE-SHA1-3DES", - "pbeWithSHA1And3-KeyTripleDES-CBC"}, + "pbeWithSHA1And3-KeyTripleDES-CBC"}, #endif /* oidKeyWrapType */ #ifdef WOLFSSL_AES_128 - { AES128_WRAP, AES128_WRAP, oidKeyWrapType, "AES-128 wrap", "aes128-wrap"}, + { AES128_WRAP, AES128_WRAP, oidKeyWrapType, "AES-128 wrap", + "aes128-wrap"}, #endif #ifdef WOLFSSL_AES_192 - { AES192_WRAP, AES192_WRAP, oidKeyWrapType, "AES-192 wrap", "aes192-wrap"}, + { AES192_WRAP, AES192_WRAP, oidKeyWrapType, "AES-192 wrap", + "aes192-wrap"}, #endif #ifdef WOLFSSL_AES_256 - { AES256_WRAP, AES256_WRAP, oidKeyWrapType, "AES-256 wrap", "aes256-wrap"}, + { AES256_WRAP, AES256_WRAP, oidKeyWrapType, "AES-256 wrap", + "aes256-wrap"}, #endif #ifndef NO_PKCS7 @@ -24973,27 +17154,32 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = { /* oidCmsKeyAgreeType */ #ifndef NO_SHA { dhSinglePass_stdDH_sha1kdf_scheme, dhSinglePass_stdDH_sha1kdf_scheme, - oidCmsKeyAgreeType, "dhSinglePass-stdDH-sha1kdf-scheme", "dhSinglePass-stdDH-sha1kdf-scheme"}, + oidCmsKeyAgreeType, "dhSinglePass-stdDH-sha1kdf-scheme", + "dhSinglePass-stdDH-sha1kdf-scheme"}, #endif #ifdef WOLFSSL_SHA224 { dhSinglePass_stdDH_sha224kdf_scheme, - dhSinglePass_stdDH_sha224kdf_scheme, oidCmsKeyAgreeType, - "dhSinglePass-stdDH-sha224kdf-scheme", "dhSinglePass-stdDH-sha224kdf-scheme"}, + dhSinglePass_stdDH_sha224kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha224kdf-scheme", + "dhSinglePass-stdDH-sha224kdf-scheme"}, #endif #ifndef NO_SHA256 { dhSinglePass_stdDH_sha256kdf_scheme, - dhSinglePass_stdDH_sha256kdf_scheme, oidCmsKeyAgreeType, - "dhSinglePass-stdDH-sha256kdf-scheme", "dhSinglePass-stdDH-sha256kdf-scheme"}, + dhSinglePass_stdDH_sha256kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha256kdf-scheme", + "dhSinglePass-stdDH-sha256kdf-scheme"}, #endif #ifdef WOLFSSL_SHA384 { dhSinglePass_stdDH_sha384kdf_scheme, - dhSinglePass_stdDH_sha384kdf_scheme, oidCmsKeyAgreeType, - "dhSinglePass-stdDH-sha384kdf-scheme", "dhSinglePass-stdDH-sha384kdf-scheme"}, + dhSinglePass_stdDH_sha384kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha384kdf-scheme", + "dhSinglePass-stdDH-sha384kdf-scheme"}, #endif #ifdef WOLFSSL_SHA512 { dhSinglePass_stdDH_sha512kdf_scheme, - dhSinglePass_stdDH_sha512kdf_scheme, oidCmsKeyAgreeType, - "dhSinglePass-stdDH-sha512kdf-scheme", "dhSinglePass-stdDH-sha512kdf-scheme"}, + dhSinglePass_stdDH_sha512kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha512kdf-scheme", + "dhSinglePass-stdDH-sha512kdf-scheme"}, #endif #endif #endif @@ -25073,7 +17259,8 @@ unsigned char *wolfSSL_OPENSSL_hexstr2buf(const char *str, long *len) return NULL; } - targetBuf[targetIdx++] = (unsigned char)((srcDigitHigh << 4) | srcDigitLow); + targetBuf[targetIdx++] = (unsigned char)((srcDigitHigh << 4) | + srcDigitLow ); } if (len != NULL) @@ -25089,297 +17276,14 @@ int wolfSSL_OPENSSL_init_ssl(word64 opts, const OPENSSL_INIT_SETTINGS *settings) return wolfSSL_library_init(); } -int wolfSSL_OPENSSL_init_crypto(word64 opts, const OPENSSL_INIT_SETTINGS* settings) +int wolfSSL_OPENSSL_init_crypto(word64 opts, + const OPENSSL_INIT_SETTINGS* settings) { (void)opts; (void)settings; return wolfSSL_library_init(); } -#if defined(WOLFSSL_KEY_GEN) && defined(WOLFSSL_PEM_TO_DER) - -int EncryptDerKey(byte *der, int *derSz, const EVP_CIPHER* cipher, - unsigned char* passwd, int passwdSz, byte **cipherInfo, - int maxDerSz) -{ - int ret, paddingSz; - word32 idx, cipherInfoSz; -#ifdef WOLFSSL_SMALL_STACK - EncryptedInfo* info = NULL; -#else - EncryptedInfo info[1]; -#endif - - WOLFSSL_ENTER("EncryptDerKey"); - - if (der == NULL || derSz == NULL || cipher == NULL || - passwd == NULL || cipherInfo == NULL) - return BAD_FUNC_ARG; - -#ifdef WOLFSSL_SMALL_STACK - info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL, - DYNAMIC_TYPE_ENCRYPTEDINFO); - if (info == NULL) { - WOLFSSL_MSG("malloc failed"); - return WOLFSSL_FAILURE; - } -#endif - - XMEMSET(info, 0, sizeof(EncryptedInfo)); - - /* set the cipher name on info */ - XSTRNCPY(info->name, cipher, NAME_SZ-1); - info->name[NAME_SZ-1] = '\0'; /* null term */ - - ret = wc_EncryptedInfoGet(info, info->name); - if (ret != 0) { - WOLFSSL_MSG("unsupported cipher"); - #ifdef WOLFSSL_SMALL_STACK - XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); - #endif - return WOLFSSL_FAILURE; - } - - /* Generate a random salt */ - if (wolfSSL_RAND_bytes(info->iv, info->ivSz) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("generate iv failed"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); -#endif - return WOLFSSL_FAILURE; - } - - /* add the padding before encryption */ - paddingSz = ((*derSz)/info->ivSz + 1) * info->ivSz - (*derSz); - if (paddingSz == 0) - paddingSz = info->ivSz; - if (maxDerSz < *derSz + paddingSz) { - WOLFSSL_MSG("not enough DER buffer allocated"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); -#endif - return WOLFSSL_FAILURE; - } - XMEMSET(der+(*derSz), (byte)paddingSz, paddingSz); - (*derSz) += paddingSz; - - /* encrypt buffer */ - if (wc_BufferKeyEncrypt(info, der, *derSz, passwd, passwdSz, WC_MD5) != 0) { - WOLFSSL_MSG("encrypt key failed"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); -#endif - return WOLFSSL_FAILURE; - } - - /* create cipher info : 'cipher_name,Salt(hex)' */ - cipherInfoSz = (word32)(2*info->ivSz + XSTRLEN(info->name) + 2); - *cipherInfo = (byte*)XMALLOC(cipherInfoSz, NULL, - DYNAMIC_TYPE_STRING); - if (*cipherInfo == NULL) { - WOLFSSL_MSG("malloc failed"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); -#endif - return WOLFSSL_FAILURE; - } - XSTRLCPY((char*)*cipherInfo, info->name, cipherInfoSz); - XSTRLCAT((char*)*cipherInfo, ",", cipherInfoSz); - - idx = (word32)XSTRLEN((char*)*cipherInfo); - cipherInfoSz -= idx; - ret = Base16_Encode(info->iv, info->ivSz, *cipherInfo+idx, &cipherInfoSz); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); -#endif - if (ret != 0) { - WOLFSSL_MSG("Base16_Encode failed"); - XFREE(*cipherInfo, NULL, DYNAMIC_TYPE_STRING); - return WOLFSSL_FAILURE; - } - - return WOLFSSL_SUCCESS; -} -#endif /* WOLFSSL_KEY_GEN || WOLFSSL_PEM_TO_DER */ - -#if !defined(NO_BIO) -static int pem_write_pubkey(WOLFSSL_EVP_PKEY* key, void* heap, byte** derBuf, - int* derSz) -{ - byte* buf = NULL; - int sz = 0; - - (void)heap; - - if (key == NULL) { - WOLFSSL_MSG("Bad parameters"); - return WOLFSSL_FAILURE; - } - - switch (key->type) { -#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) - case EVP_PKEY_RSA: - if ((sz = wolfSSL_RSA_To_Der(key->rsa, &buf, 1, heap)) - < 0) { - WOLFSSL_MSG("wolfSSL_RSA_To_Der failed"); - break; - } - break; -#endif /* WOLFSSL_KEY_GEN && !NO_RSA */ -#if !defined(NO_DSA) && !defined(HAVE_SELFTEST) && (defined(WOLFSSL_KEY_GEN) || \ - defined(WOLFSSL_CERT_GEN)) - case EVP_PKEY_DSA: - if (key->dsa == NULL) { - WOLFSSL_MSG("key->dsa is null"); - break; - } - sz = MAX_DSA_PUBKEY_SZ; - buf = (byte*)XMALLOC(sz, heap, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - WOLFSSL_MSG("malloc failed"); - break; - } - /* Key to DER */ - sz = wc_DsaKeyToPublicDer((DsaKey*)key->dsa->internal, buf, sz); - if (sz < 0) { - WOLFSSL_MSG("wc_DsaKeyToDer failed"); - break; - } - break; -#endif /* !NO_DSA && !HAVE_SELFTEST && (WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN) */ -#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) - case EVP_PKEY_EC: - { - if (key->ecc == NULL) { - WOLFSSL_MSG("key->ecc is null"); - break; - } - if ((sz = wolfssl_ec_key_to_pubkey_der(key->ecc, &buf, heap)) <= - 0) { - WOLFSSL_MSG("wolfssl_ec_key_to_pubkey_der failed"); - break; - } - break; - } -#endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT */ -#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) - case EVP_PKEY_DH: - WOLFSSL_MSG("Writing DH PUBKEY not supported!"); - break; -#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ - default: - WOLFSSL_MSG("Unknown Key type!"); - break; - } - - if (buf == NULL || sz <= 0) { - if (buf != NULL) - XFREE(buf, heap, DYNAMIC_TYPE_DER); - return WOLFSSL_FAILURE; - } - - *derBuf = buf; - *derSz = sz; - return WOLFSSL_SUCCESS; -} -#endif - -#ifndef NO_BIO -static int pem_write_bio_pubkey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) -{ - int ret; - int derSz = 0; - byte* derBuf = NULL; - - ret = pem_write_pubkey(key, bio->heap, &derBuf, &derSz); - if (ret == WOLFSSL_SUCCESS) { - ret = der_write_to_bio_as_pem(derBuf, derSz, bio, PUBLICKEY_TYPE); - XFREE(derBuf, bio->heap, DYNAMIC_TYPE_DER); - } - - return ret; -} - -/* Takes a public key and writes it out to a WOLFSSL_BIO - * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE - */ -int wolfSSL_PEM_write_bio_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PUBKEY"); - - if ((bio == NULL) || (key == NULL)) { - ret = WOLFSSL_FAILURE; - } - else { - ret = pem_write_bio_pubkey(bio, key); - } - - return ret; -} - -/* Takes a private key and writes it out to a WOLFSSL_BIO - * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE - */ -int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, - const WOLFSSL_EVP_CIPHER* cipher, - unsigned char* passwd, int len, - wc_pem_password_cb* cb, void* arg) -{ - byte* keyDer; - int type; - - (void)cipher; - (void)passwd; - (void)len; - (void)cb; - (void)arg; - - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PrivateKey"); - - if (bio == NULL || key == NULL) { - WOLFSSL_MSG("Bad Function Arguments"); - return WOLFSSL_FAILURE; - } - - keyDer = (byte*)key->pkey.ptr; - - switch (key->type) { -#ifndef NO_RSA - case EVP_PKEY_RSA: - type = PRIVATEKEY_TYPE; - break; -#endif - -#ifndef NO_DSA - case EVP_PKEY_DSA: - type = DSA_PRIVATEKEY_TYPE; - break; -#endif - -#ifdef HAVE_ECC - case EVP_PKEY_EC: - type = ECC_PRIVATEKEY_TYPE; - break; -#endif - -#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) - case EVP_PKEY_DH: - type = DH_PRIVATEKEY_TYPE; - break; -#endif - - default: - WOLFSSL_MSG("Unknown Key type!"); - type = PRIVATEKEY_TYPE; - } - - return der_write_to_bio_as_pem(keyDer, key->pkey_sz, bio, type); -} -#endif /* !NO_BIO */ - /* Colon separated list of + algorithms. * Replaces list in context. */ @@ -25653,138 +17557,6 @@ int wolfSSL_set1_groups_list(WOLFSSL *ssl, const char *list) #endif /* HAVE_ECC */ -#ifndef NO_BIO -WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_bio_PrivateKey(WOLFSSL_BIO* bio, - WOLFSSL_EVP_PKEY** key, - wc_pem_password_cb* cb, - void* pass) -{ - WOLFSSL_EVP_PKEY* pkey = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PrivateKey"); - - if (bio == NULL) - return pkey; - - if (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, &keyFormat, &der) - >= 0) { - const unsigned char* ptr = der->buffer; - int type = -1; - - if (keyFormat) { - /* keyFormat is Key_Sum enum */ - if (keyFormat == RSAk) - type = EVP_PKEY_RSA; - else if (keyFormat == ECDSAk) - type = EVP_PKEY_EC; - else if (keyFormat == DSAk) - type = EVP_PKEY_DSA; - else if (keyFormat == DHk) - type = EVP_PKEY_DH; - } - else { - /* Default to RSA if format is not set */ - type = EVP_PKEY_RSA; - } - - /* handle case where reuse is attempted */ - if (key != NULL && *key != NULL) - pkey = *key; - - wolfSSL_d2i_PrivateKey(type, &pkey, &ptr, der->length); - if (pkey == NULL) { - WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); - } - } - - FreeDer(&der); - - if (key != NULL && pkey != NULL) - *key = pkey; - - WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PrivateKey", 0); - - return pkey; -} - -WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_bio_PUBKEY(WOLFSSL_BIO* bio, - WOLFSSL_EVP_PKEY **key, - wc_pem_password_cb *cb, - void *pass) -{ - WOLFSSL_EVP_PKEY* pkey = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PUBKEY"); - - if (bio == NULL) - return pkey; - - if (pem_read_bio_key(bio, cb, pass, PUBLICKEY_TYPE, &keyFormat, &der) - >= 0) { - const unsigned char* ptr = der->buffer; - - /* handle case where reuse is attempted */ - if (key != NULL && *key != NULL) - pkey = *key; - - wolfSSL_d2i_PUBKEY(&pkey, &ptr, der->length); - if (pkey == NULL) { - WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); - } - } - - FreeDer(&der); - - if (key != NULL && pkey != NULL) - *key = pkey; - - WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PUBKEY", 0); - - return pkey; -} -#endif /* !NO_BIO */ - -#if !defined(NO_FILESYSTEM) -WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PUBKEY(XFILE fp, WOLFSSL_EVP_PKEY **key, - wc_pem_password_cb *cb, void *pass) -{ - WOLFSSL_EVP_PKEY* pkey = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_PUBKEY"); - - if ((pem_read_file_key(fp, cb, pass, PUBLICKEY_TYPE, &keyFormat, &der) - >= 0) && (der != NULL)) { - const unsigned char* ptr = der->buffer; - - /* handle case where reuse is attempted */ - if ((key != NULL) && (*key != NULL)) { - pkey = *key; - } - - if ((wolfSSL_d2i_PUBKEY(&pkey, &ptr, der->length) == NULL) || - (pkey == NULL)) { - WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); - pkey = NULL; - } - } - - FreeDer(&der); - - if ((key != NULL) && (pkey != NULL)) { - *key = pkey; - } - - WOLFSSL_LEAVE("wolfSSL_PEM_read_PUBKEY", 0); - - return pkey; -} -#endif /* NO_FILESYSTEM */ #endif /* OPENSSL_EXTRA */ #ifdef WOLFSSL_ALT_CERT_CHAINS @@ -25981,20 +17753,6 @@ int wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx, #endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ } - -/* get session ID */ -WOLFSSL_ABI -const byte* wolfSSL_get_sessionID(const WOLFSSL_SESSION* session) -{ - WOLFSSL_ENTER("wolfSSL_get_sessionID"); - session = ClientSessionToSession(session); - if (session) - return session->sessionID; - - return NULL; -} - - #endif /* SESSION_CERTS */ #ifdef HAVE_FUZZER @@ -26078,7 +17836,8 @@ void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl) return NULL; } -void wolfSSL_CTX_SetEccSharedSecretCb(WOLFSSL_CTX* ctx, CallbackEccSharedSecret cb) +void wolfSSL_CTX_SetEccSharedSecretCb(WOLFSSL_CTX* ctx, + CallbackEccSharedSecret cb) { if (ctx) ctx->EccSharedSecretCb = cb; @@ -26302,7 +18061,8 @@ void wolfSSL_CTX_SetRsaPssSignCb(WOLFSSL_CTX* ctx, CallbackRsaPssSign cb) if (ctx) ctx->RsaPssSignCb = cb; } -void wolfSSL_CTX_SetRsaPssSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb) +void wolfSSL_CTX_SetRsaPssSignCheckCb(WOLFSSL_CTX* ctx, + CallbackRsaPssVerify cb) { if (ctx) ctx->RsaPssSignCheckCb = cb; @@ -26398,7 +18158,8 @@ void* wolfSSL_GetGenPreMasterCtx(WOLFSSL* ssl) } /* callback for master secret generation */ -void wolfSSL_CTX_SetGenMasterSecretCb(WOLFSSL_CTX* ctx, CallbackGenMasterSecret cb) +void wolfSSL_CTX_SetGenMasterSecretCb(WOLFSSL_CTX* ctx, + CallbackGenMasterSecret cb) { if (ctx) ctx->GenMasterCb = cb; @@ -26595,427 +18356,6 @@ void* wolfSSL_GetHKDFExtractCtx(WOLFSSL* ssl) #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ !defined(WOLFCRYPT_ONLY) -#ifndef NO_CERTS - -#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) -#if !defined(NO_FILESYSTEM) - WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_PrivateKey(XFILE fp, - WOLFSSL_EVP_PKEY **key, wc_pem_password_cb *cb, void *pass) - { - WOLFSSL_EVP_PKEY* pkey = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_PrivateKey"); - - if (pem_read_file_key(fp, cb, pass, PRIVATEKEY_TYPE, &keyFormat, - &der) >= 0) { - const unsigned char* ptr = der->buffer; - int type = -1; - - if (keyFormat) { - /* keyFormat is Key_Sum enum */ - if (keyFormat == RSAk) - type = EVP_PKEY_RSA; - else if (keyFormat == ECDSAk) - type = EVP_PKEY_EC; - else if (keyFormat == DSAk) - type = EVP_PKEY_DSA; - else if (keyFormat == DHk) - type = EVP_PKEY_DH; - } - else { - /* Default to RSA if format is not set */ - type = EVP_PKEY_RSA; - } - - /* handle case where reuse is attempted */ - if (key != NULL && *key != NULL) - pkey = *key; - - wolfSSL_d2i_PrivateKey(type, &pkey, &ptr, der->length); - if (pkey == NULL) { - WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); - } - } - - FreeDer(&der); - - if (key != NULL && pkey != NULL) - *key = pkey; - - WOLFSSL_LEAVE("wolfSSL_PEM_read_PrivateKey", 0); - - return pkey; - } -#endif -#endif - -#endif /* OPENSSL_ALL || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL*/ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) - - #define PEM_BEGIN "-----BEGIN " - #define PEM_BEGIN_SZ 11 - #define PEM_END "-----END " - #define PEM_END_SZ 9 - #define PEM_HDR_FIN "-----" - #define PEM_HDR_FIN_SZ 5 - #define PEM_HDR_FIN_EOL_NEWLINE "-----\n" - #define PEM_HDR_FIN_EOL_NULL_TERM "-----\0" - #define PEM_HDR_FIN_EOL_SZ 6 - -#ifndef NO_BIO - - int wolfSSL_PEM_read_bio(WOLFSSL_BIO* bio, char **name, char **header, - unsigned char **data, long *len) - { - int ret = WOLFSSL_SUCCESS; - char pem[256]; - int pemLen; - char* p; - char* nameStr = NULL; - int nameLen = 0; - char* headerStr = NULL; - int headerFound = 0; - unsigned char* der = NULL; - word32 derLen = 0; - - if (bio == NULL || name == NULL || header == NULL || data == NULL || - len == NULL) { - return WOLFSSL_FAILURE; - } - - /* Find header line. */ - pem[sizeof(pem) - 1] = '\0'; - while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) { - if (XSTRNCMP(pem, PEM_BEGIN, PEM_BEGIN_SZ) == 0) - break; - } - if (pemLen <= 0) - ret = WOLFSSL_FAILURE; - /* Have a header line. */ - if (ret == WOLFSSL_SUCCESS) { - while (pem[pemLen - 1] == '\r' || pem[pemLen - 1] == '\n') - pemLen--; - pem[pemLen] = '\0'; - if (XSTRNCMP(pem + pemLen - PEM_HDR_FIN_SZ, PEM_HDR_FIN, - PEM_HDR_FIN_SZ) != 0) { - ret = WOLFSSL_FAILURE; - } - } - - /* Get out name. */ - if (ret == WOLFSSL_SUCCESS) { - nameLen = pemLen - PEM_BEGIN_SZ - PEM_HDR_FIN_SZ; - nameStr = (char*)XMALLOC(nameLen + 1, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (nameStr == NULL) - ret = WOLFSSL_FAILURE; - } - if (ret == WOLFSSL_SUCCESS) { - int headerLen; - - XSTRNCPY(nameStr, pem + PEM_BEGIN_SZ, nameLen); - nameStr[nameLen] = '\0'; - - /* Get header of PEM - encryption header. */ - headerLen = 0; - while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) { - while (pemLen > 0 && (pem[pemLen - 1] == '\r' || - pem[pemLen - 1] == '\n')) { - pemLen--; - } - pem[pemLen++] = '\n'; - pem[pemLen] = '\0'; - - /* Header separator is a blank line. */ - if (pem[0] == '\n') { - headerFound = 1; - break; - } - - /* Didn't find a blank line - no header. */ - if (XSTRNCMP(pem, PEM_END, PEM_END_SZ) == 0) { - der = (unsigned char*)headerStr; - derLen = headerLen; - /* Empty header - empty string. */ - headerStr = (char*)XMALLOC(1, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (headerStr == NULL) - ret = WOLFSSL_FAILURE; - else - headerStr[0] = '\0'; - break; - } - - p = (char*)XREALLOC(headerStr, headerLen + pemLen + 1, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (p == NULL) { - ret = WOLFSSL_FAILURE; - break; - } - - headerStr = p; - XMEMCPY(headerStr + headerLen, pem, pemLen + 1); - headerLen += pemLen; - } - if (pemLen <= 0) - ret = WOLFSSL_FAILURE; - } - - /* Get body of PEM - if there was a header */ - if (ret == WOLFSSL_SUCCESS && headerFound) { - derLen = 0; - while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) { - while (pemLen > 0 && (pem[pemLen - 1] == '\r' || - pem[pemLen - 1] == '\n')) { - pemLen--; - } - pem[pemLen++] = '\n'; - pem[pemLen] = '\0'; - - if (XSTRNCMP(pem, PEM_END, PEM_END_SZ) == 0) - break; - - p = (char*)XREALLOC(der, derLen + pemLen + 1, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (p == NULL) { - ret = WOLFSSL_FAILURE; - break; - } - - der = (unsigned char*)p; - XMEMCPY(der + derLen, pem, pemLen + 1); - derLen += pemLen; - } - if (pemLen <= 0) - ret = WOLFSSL_FAILURE; - } - - /* Check trailer. */ - if (ret == WOLFSSL_SUCCESS) { - if (XSTRNCMP(pem + PEM_END_SZ, nameStr, nameLen) != 0) - ret = WOLFSSL_FAILURE; - } - if (ret == WOLFSSL_SUCCESS) { - if (XSTRNCMP(pem + PEM_END_SZ + nameLen, - PEM_HDR_FIN_EOL_NEWLINE, - PEM_HDR_FIN_EOL_SZ) != 0 && - XSTRNCMP(pem + PEM_END_SZ + nameLen, - PEM_HDR_FIN_EOL_NULL_TERM, - PEM_HDR_FIN_EOL_SZ) != 0) { - ret = WOLFSSL_FAILURE; - } - } - - /* Base64 decode body. */ - if (ret == WOLFSSL_SUCCESS) { - if (Base64_Decode(der, derLen, der, &derLen) != 0) - ret = WOLFSSL_FAILURE; - } - - if (ret == WOLFSSL_SUCCESS) { - *name = nameStr; - *header = headerStr; - *data = der; - *len = derLen; - nameStr = NULL; - headerStr = NULL; - der = NULL; - } - - if (nameStr != NULL) - XFREE(nameStr, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (headerStr != NULL) - XFREE(headerStr, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (der != NULL) - XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; - } - - int wolfSSL_PEM_write_bio(WOLFSSL_BIO* bio, const char *name, - const char *header, const unsigned char *data, - long len) - { - int err = 0; - int outSz = 0; - int nameLen; - int headerLen; - byte* pem = NULL; - word32 pemLen; - word32 derLen = (word32)len; - - if (bio == NULL || name == NULL || header == NULL || data == NULL) - return 0; - - nameLen = (int)XSTRLEN(name); - headerLen = (int)XSTRLEN(header); - - pemLen = (derLen + 2) / 3 * 4; - pemLen += (pemLen + 63) / 64; - - pem = (byte*)XMALLOC(pemLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); - err = pem == NULL; - if (!err) - err = Base64_Encode(data, derLen, pem, &pemLen) != 0; - - if (!err) { - err = wolfSSL_BIO_write(bio, PEM_BEGIN, PEM_BEGIN_SZ) != - (int)PEM_BEGIN_SZ; - } - if (!err) - err = wolfSSL_BIO_write(bio, name, nameLen) != nameLen; - if (!err) { - err = wolfSSL_BIO_write(bio, PEM_HDR_FIN_EOL_NEWLINE, - PEM_HDR_FIN_EOL_SZ) != (int)PEM_HDR_FIN_EOL_SZ; - } - if (!err && headerLen > 0) { - err = wolfSSL_BIO_write(bio, header, headerLen) != headerLen; - /* Blank line after a header and before body. */ - if (!err) - err = wolfSSL_BIO_write(bio, "\n", 1) != 1; - headerLen++; - } - if (!err) - err = wolfSSL_BIO_write(bio, pem, pemLen) != (int)pemLen; - if (!err) - err = wolfSSL_BIO_write(bio, PEM_END, PEM_END_SZ) != - (int)PEM_END_SZ; - if (!err) - err = wolfSSL_BIO_write(bio, name, nameLen) != nameLen; - if (!err) { - err = wolfSSL_BIO_write(bio, PEM_HDR_FIN_EOL_NEWLINE, - PEM_HDR_FIN_EOL_SZ) != (int)PEM_HDR_FIN_EOL_SZ; - } - - if (!err) { - outSz = PEM_BEGIN_SZ + nameLen + PEM_HDR_FIN_EOL_SZ + headerLen + - pemLen + PEM_END_SZ + nameLen + PEM_HDR_FIN_EOL_SZ; - } - - if (pem != NULL) - XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - return outSz; - } - -#if !defined(NO_FILESYSTEM) - int wolfSSL_PEM_read(XFILE fp, char **name, char **header, - unsigned char **data, long *len) - { - int ret; - WOLFSSL_BIO* bio; - - if (name == NULL || header == NULL || data == NULL || len == NULL) - return WOLFSSL_FAILURE; - - bio = wolfSSL_BIO_new_fp(fp, BIO_NOCLOSE); - if (bio == NULL) - return 0; - - ret = wolfSSL_PEM_read_bio(bio, name, header, data, len); - - if (bio != NULL) - wolfSSL_BIO_free(bio); - - return ret; - } - - int wolfSSL_PEM_write(XFILE fp, const char *name, const char *header, - const unsigned char *data, long len) - { - int ret; - WOLFSSL_BIO* bio; - - if (name == NULL || header == NULL || data == NULL) - return 0; - - bio = wolfSSL_BIO_new_fp(fp, BIO_NOCLOSE); - if (bio == NULL) - return 0; - - ret = wolfSSL_PEM_write_bio(bio, name, header, data, len); - - if (bio != NULL) - wolfSSL_BIO_free(bio); - - return ret; - } -#endif -#endif /* !NO_BIO */ - - int wolfSSL_PEM_get_EVP_CIPHER_INFO(const char* header, - EncryptedInfo* cipher) - { - if (header == NULL || cipher == NULL) - return WOLFSSL_FAILURE; - - XMEMSET(cipher, 0, sizeof(*cipher)); - - if (wc_EncryptedInfoParse(cipher, &header, XSTRLEN(header)) != 0) - return WOLFSSL_FAILURE; - - return WOLFSSL_SUCCESS; - } - - int wolfSSL_PEM_do_header(EncryptedInfo* cipher, unsigned char* data, - long* len, wc_pem_password_cb* callback, - void* ctx) - { - int ret = WOLFSSL_SUCCESS; - char password[NAME_SZ]; - int passwordSz; - - if (cipher == NULL || data == NULL || len == NULL || callback == NULL) - return WOLFSSL_FAILURE; - - passwordSz = callback(password, sizeof(password), PEM_PASS_READ, ctx); - if (passwordSz < 0) - ret = WOLFSSL_FAILURE; - - if (ret == WOLFSSL_SUCCESS) { - if (wc_BufferKeyDecrypt(cipher, data, (word32)*len, (byte*)password, - passwordSz, WC_MD5) != 0) { - ret = WOLFSSL_FAILURE; - } - } - - if (passwordSz > 0) - XMEMSET(password, 0, passwordSz); - - return ret; - } - -#ifndef NO_BIO - /* - * bp : bio to read X509 from - * x : x509 to write to - * cb : password call back for reading PEM - * u : password - * _AUX is for working with a trusted X509 certificate - */ - WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509_AUX(WOLFSSL_BIO *bp, - WOLFSSL_X509 **x, wc_pem_password_cb *cb, - void *u) - { - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509"); - - /* AUX info is; trusted/rejected uses, friendly name, private key id, - * and potentially a stack of "other" info. wolfSSL does not store - * friendly name or private key id yet in WOLFSSL_X509 for human - * readability and does not support extra trusted/rejected uses for - * root CA. */ - return wolfSSL_PEM_read_bio_X509(bp, x, cb, u); - } -#endif /* !NO_BIO */ - - -#endif /* OPENSSL_EXTRA || OPENSSL_ALL */ -#endif /* !NO_CERTS */ /* NID variables are dependent on compatibility header files currently * @@ -27115,10 +18455,10 @@ void* wolfSSL_GetHKDFExtractCtx(WOLFSSL* ssl) wolfSSL_ASN1_OBJECT_free(obj); return NULL; } - obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA ; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA; } else { - obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA ; + obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA; } } XMEMCPY((byte*)obj->obj, objBuf, obj->objSz); @@ -27283,224 +18623,6 @@ void* wolfSSL_GetHKDFExtractCtx(WOLFSSL* ssl) defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ defined(WOLFSSL_HAPROXY) - char wolfSSL_CTX_use_certificate(WOLFSSL_CTX *ctx, WOLFSSL_X509 *x) - { - int ret; - - WOLFSSL_ENTER("wolfSSL_CTX_use_certificate"); - if (!ctx || !x || !x->derCert) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - FreeDer(&ctx->certificate); /* Make sure previous is free'd */ - ret = AllocDer(&ctx->certificate, x->derCert->length, CERT_TYPE, - ctx->heap); - if (ret != 0) - return WOLFSSL_FAILURE; - - XMEMCPY(ctx->certificate->buffer, x->derCert->buffer, - x->derCert->length); -#ifdef KEEP_OUR_CERT - if (ctx->ourCert != NULL && ctx->ownOurCert) { - wolfSSL_X509_free(ctx->ourCert); - } - #ifndef WOLFSSL_X509_STORE_CERTS - ctx->ourCert = x; - if (wolfSSL_X509_up_ref(x) != 1) { - return WOLFSSL_FAILURE; - } - #else - ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, x->derCert->buffer, - x->derCert->length, ctx->heap); - if(ctx->ourCert == NULL){ - return WOLFSSL_FAILURE; - } - #endif - - /* We own the cert because either we up its reference counter - * or we create our own copy of the cert object. */ - ctx->ownOurCert = 1; -#endif - - /* Update the available options with public keys. */ - switch (x->pubKeyOID) { - #ifndef NO_RSA - #ifdef WC_RSA_PSS - case RSAPSSk: - #endif - case RSAk: - ctx->haveRSA = 1; - break; - #endif - #ifdef HAVE_ED25519 - case ED25519k: - #endif - #ifdef HAVE_ED448 - case ED448k: - #endif - case ECDSAk: - ctx->haveECC = 1; - #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) - ctx->pkCurveOID = x->pkCurveOID; - #endif - break; - } - - return WOLFSSL_SUCCESS; - } - - static int PushCertToDerBuffer(DerBuffer** inOutDer, int weOwn, - byte* cert, word32 certSz, void* heap) - { - int ret; - DerBuffer* inChain = NULL; - DerBuffer* der = NULL; - word32 len = 0; - if (inOutDer == NULL) - return BAD_FUNC_ARG; - inChain = *inOutDer; - if (inChain != NULL) - len = inChain->length; - ret = AllocDer(&der, len + CERT_HEADER_SZ + certSz, CERT_TYPE, - heap); - if (ret != 0) { - WOLFSSL_MSG("AllocDer error"); - return ret; - } - if (inChain != NULL) - XMEMCPY(der->buffer, inChain->buffer, len); - c32to24(certSz, der->buffer + len); - XMEMCPY(der->buffer + len + CERT_HEADER_SZ, cert, certSz); - if (weOwn) - FreeDer(inOutDer); - *inOutDer = der; - return WOLFSSL_SUCCESS; - } - - /** - * wolfSSL_CTX_add1_chain_cert makes a copy of the cert so we free it - * on success - */ - int wolfSSL_CTX_add0_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) - { - WOLFSSL_ENTER("wolfSSL_CTX_add0_chain_cert"); - if (wolfSSL_CTX_add1_chain_cert(ctx, x509) != WOLFSSL_SUCCESS) { - return WOLFSSL_FAILURE; - } - wolfSSL_X509_free(x509); - return WOLFSSL_SUCCESS; - } - - int wolfSSL_CTX_add1_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) - { - int ret; - WOLFSSL_ENTER("wolfSSL_CTX_add1_chain_cert"); - if (ctx == NULL || x509 == NULL || x509->derCert == NULL) { - return WOLFSSL_FAILURE; - } - - if (ctx->certificate == NULL) - ret = (int)wolfSSL_CTX_use_certificate(ctx, x509); - else { - if (wolfSSL_X509_up_ref(x509) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_X509_up_ref error"); - return WOLFSSL_FAILURE; - } - ret = wolfSSL_CTX_load_verify_buffer(ctx, x509->derCert->buffer, - x509->derCert->length, WOLFSSL_FILETYPE_ASN1); - if (ret == WOLFSSL_SUCCESS) { - /* push to ctx->certChain */ - ret = PushCertToDerBuffer(&ctx->certChain, 1, - x509->derCert->buffer, x509->derCert->length, ctx->heap); - } - /* Store cert to free it later */ - if (ret == WOLFSSL_SUCCESS && ctx->x509Chain == NULL) { - ctx->x509Chain = wolfSSL_sk_X509_new_null(); - if (ctx->x509Chain == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_new_null error"); - ret = WOLFSSL_FAILURE; - } - } - if (ret == WOLFSSL_SUCCESS && - wolfSSL_sk_X509_push(ctx->x509Chain, x509) - != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_sk_X509_push error"); - ret = WOLFSSL_FAILURE; - } - if (ret != WOLFSSL_SUCCESS) - wolfSSL_X509_free(x509); /* Decrease ref counter */ - } - - return (ret == WOLFSSL_SUCCESS) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; - } - -#ifdef KEEP_OUR_CERT - int wolfSSL_add0_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509) - { - int ret; - - WOLFSSL_ENTER("wolfSSL_add0_chain_cert"); - - if (ssl == NULL || ssl->ctx == NULL || x509 == NULL || - x509->derCert == NULL) - return WOLFSSL_FAILURE; - - if (ssl->buffers.certificate == NULL) { - ret = wolfSSL_use_certificate(ssl, x509); - /* Store cert to free it later */ - if (ret == WOLFSSL_SUCCESS) { - if (ssl->buffers.weOwnCert) - wolfSSL_X509_free(ssl->ourCert); - ssl->ourCert = x509; - ssl->buffers.weOwnCert = 1; - } - } - else { - ret = PushCertToDerBuffer(&ssl->buffers.certChain, - ssl->buffers.weOwnCertChain, x509->derCert->buffer, - x509->derCert->length, ssl->heap); - if (ret == WOLFSSL_SUCCESS) { - ssl->buffers.weOwnCertChain = 1; - /* Store cert to free it later */ - if (ssl->ourCertChain == NULL) { - ssl->ourCertChain = wolfSSL_sk_X509_new_null(); - if (ssl->ourCertChain == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_new_null error"); - return WOLFSSL_FAILURE; - } - } - if (wolfSSL_sk_X509_push(ssl->ourCertChain, x509) - != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_sk_X509_push error"); - return WOLFSSL_FAILURE; - } - } - } - return ret == WOLFSSL_SUCCESS ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; - } - - int wolfSSL_add1_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509) - { - int ret; - - WOLFSSL_ENTER("wolfSSL_add1_chain_cert"); - if (ssl == NULL || ssl->ctx == NULL || x509 == NULL || - x509->derCert == NULL) - return WOLFSSL_FAILURE; - - if (wolfSSL_X509_up_ref(x509) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_X509_up_ref error"); - return WOLFSSL_FAILURE; - } - ret = wolfSSL_add0_chain_cert(ssl, x509); - /* Decrease ref counter on error */ - if (ret != WOLFSSL_SUCCESS) - wolfSSL_X509_free(x509); - return ret; - } -#endif - /* Return the corresponding short name for the nid . * or NULL if short name can't be found. */ @@ -27827,7 +18949,7 @@ void* wolfSSL_GetHKDFExtractCtx(WOLFSSL* ssl) wolfSSL_ASN1_OBJECT_free(obj); return NULL; } - obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA ; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA; i = SetObjectId(outSz, (byte*)obj->obj); XMEMCPY((byte*)obj->obj + i, out, outSz); obj->objSz = i + outSz; @@ -27919,53 +19041,6 @@ unsigned long wolfSSL_ERR_peek_last_error_line(const char **file, int *line) #endif } - -#ifndef NO_CERTS -int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey) -{ - WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey"); - - if (ctx == NULL || pkey == NULL) { - return WOLFSSL_FAILURE; - } - - switch (pkey->type) { -#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) - case EVP_PKEY_RSA: - WOLFSSL_MSG("populating RSA key"); - if (PopulateRSAEvpPkeyDer(pkey) != WOLFSSL_SUCCESS) - return WOLFSSL_FAILURE; - break; -#endif /* (WOLFSSL_KEY_GEN || OPENSSL_EXTRA) && !NO_RSA */ -#if !defined(HAVE_SELFTEST) && (defined(WOLFSSL_KEY_GEN) || \ - defined(WOLFSSL_CERT_GEN)) && !defined(NO_DSA) - case EVP_PKEY_DSA: - break; -#endif /* !HAVE_SELFTEST && (WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN) && !NO_DSA */ -#ifdef HAVE_ECC - case EVP_PKEY_EC: - WOLFSSL_MSG("populating ECC key"); - if (ECC_populate_EVP_PKEY(pkey, pkey->ecc) - != WOLFSSL_SUCCESS) - return WOLFSSL_FAILURE; - break; -#endif - default: - return WOLFSSL_FAILURE; - } - - if (pkey->pkey.ptr != NULL) { - /* ptr for WOLFSSL_EVP_PKEY struct is expected to be DER format */ - return wolfSSL_CTX_use_PrivateKey_buffer(ctx, - (const unsigned char*)pkey->pkey.ptr, - pkey->pkey_sz, SSL_FILETYPE_ASN1); - } - - WOLFSSL_MSG("wolfSSL private key not set"); - return BAD_FUNC_ARG; -} -#endif /* !NO_CERTS */ - #endif /* OPENSSL_EXTRA */ #if defined(HAVE_EX_DATA) && \ @@ -28276,50 +19351,6 @@ void* wolfSSL_get_ex_data(const WOLFSSL* ssl, int idx) #if defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) \ || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) -#if defined(OPENSSL_EXTRA) && !defined(NO_DH) -/* Initialize ctx->dh with dh's params. Return WOLFSSL_SUCCESS on ok */ -long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL_DH* dh) -{ - int pSz, gSz; - byte *p, *g; - int ret=0; - - WOLFSSL_ENTER("wolfSSL_CTX_set_tmp_dh"); - - if(!ctx || !dh) - return BAD_FUNC_ARG; - - /* Get needed size for p and g */ - pSz = wolfSSL_BN_bn2bin(dh->p, NULL); - gSz = wolfSSL_BN_bn2bin(dh->g, NULL); - - if(pSz <= 0 || gSz <= 0) - return WOLFSSL_FATAL_ERROR; - - p = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - if(!p) - return MEMORY_E; - - g = (byte*)XMALLOC(gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - if(!g) { - XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - return MEMORY_E; - } - - pSz = wolfSSL_BN_bn2bin(dh->p, p); - gSz = wolfSSL_BN_bn2bin(dh->g, g); - - if(pSz >= 0 && gSz >= 0) /* Conversion successful */ - ret = wolfSSL_CTX_SetTmpDH(ctx, p, pSz, g, gSz); - - XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - XFREE(g, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - - return pSz > 0 && gSz > 0 ? ret : WOLFSSL_FATAL_ERROR; -} -#endif /* OPENSSL_EXTRA && !NO_DH */ - - /* returns the enum value associated with handshake state * * ssl the WOLFSSL structure to get state of @@ -28381,7 +19412,8 @@ long wolfSSL_ctrl(WOLFSSL* ssl, int cmd, long opt, void* pt) return BAD_FUNC_ARG; switch (cmd) { - #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) || \ + defined(OPENSSL_ALL) #ifdef HAVE_SNI case SSL_CTRL_SET_TLSEXT_HOSTNAME: WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TLSEXT_HOSTNAME."); @@ -28573,64 +19605,6 @@ VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl) return NULL; } -/* Adds the ASN1 certificate to the user ctx. -Returns WOLFSSL_SUCCESS if no error, returns WOLFSSL_FAILURE otherwise.*/ -int wolfSSL_CTX_use_certificate_ASN1(WOLFSSL_CTX *ctx, int derSz, - const unsigned char *der) -{ - WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_ASN1"); - if (der != NULL && ctx != NULL) { - if (wolfSSL_CTX_use_certificate_buffer(ctx, der, derSz, - WOLFSSL_FILETYPE_ASN1) == WOLFSSL_SUCCESS) { - return WOLFSSL_SUCCESS; - } - - } - return WOLFSSL_FAILURE; -} - - -#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) -/* Adds the rsa private key to the user ctx. -Returns WOLFSSL_SUCCESS if no error, returns WOLFSSL_FAILURE otherwise.*/ -int wolfSSL_CTX_use_RSAPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL_RSA* rsa) -{ - int ret; - int derSize; - unsigned char *maxDerBuf; - unsigned char* key = NULL; - - WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey"); - - if (ctx == NULL || rsa == NULL) { - WOLFSSL_MSG("one or more inputs were NULL"); - return BAD_FUNC_ARG; - } - maxDerBuf = (unsigned char*)XMALLOC(4096, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (maxDerBuf == NULL) { - WOLFSSL_MSG("Malloc failure"); - return MEMORY_E; - } - key = maxDerBuf; - /* convert RSA struct to der encoded buffer and get the size */ - if ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, &key)) <= 0) { - WOLFSSL_MSG("wolfSSL_i2d_RSAPrivateKey() failure"); - XFREE(maxDerBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_FAILURE; - } - ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, (const unsigned char*)maxDerBuf, - derSize, SSL_FILETYPE_ASN1); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_CTX_USE_PrivateKey_buffer() failure"); - XFREE(maxDerBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_FAILURE; - } - XFREE(maxDerBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return ret; -} -#endif /* WOLFSSL_KEY_GEN && !NO_RSA */ - - #ifndef NO_BIO /* Converts EVP_PKEY data from a bio buffer to a WOLFSSL_EVP_PKEY structure. Returns pointer to private EVP_PKEY struct upon success, NULL if there @@ -28667,7 +19641,8 @@ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO* bio, int derLength; /* Determines key type and returns the new private EVP_PKEY object */ - if ((key = wolfSSL_d2i_PrivateKey_EVP(NULL, &mem, (long)memSz)) == NULL) { + if ((key = wolfSSL_d2i_PrivateKey_EVP(NULL, &mem, (long)memSz)) == + NULL) { WOLFSSL_MSG("wolfSSL_d2i_PrivateKey_EVP() failure"); XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); return NULL; @@ -28719,8 +19694,9 @@ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO* bio, #endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ -#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) || \ - defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) || defined(WOLFSSL_WPAS_SMALL) +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_QT) || defined(WOLFSSL_WPAS_SMALL) /* Converts a DER encoded private key to a WOLFSSL_EVP_PKEY structure. * returns a pointer to a new WOLFSSL_EVP_PKEY structure on success and NULL @@ -28732,13 +19708,15 @@ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_EVP(WOLFSSL_EVP_PKEY** out, return d2iGenericKey(out, (const unsigned char**)in, inSz, 1); } -#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT || WOLFSSL_WPAS_SMALL*/ +#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT || + * WOLFSSL_WPAS_SMALL*/ /* stunnel compatibility functions*/ -#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \ - defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_OPENSSH))) +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH))) void wolfSSL_ERR_remove_thread_state(void* pid) { (void) pid; @@ -28756,178 +19734,12 @@ void wolfSSL_print_all_errors_fp(XFILE fp) #endif /* OPENSSL_ALL || OPENSSL_EXTRA || HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_LIGHTY || WOLFSSL_HAPROXY || WOLFSSL_OPENSSH */ - -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ - defined(HAVE_EX_DATA) - -#if defined(HAVE_EX_DATA) && !defined(NO_SESSION_CACHE) -static void SESSION_ex_data_cache_update(WOLFSSL_SESSION* session, int idx, - void* data, byte get, void** getRet, int* setRet) -{ - int row; - int i; - int error = 0; - SessionRow* sessRow = NULL; - const byte* id; - byte foundCache = 0; - - if (getRet != NULL) - *getRet = NULL; - if (setRet != NULL) - *setRet = WOLFSSL_FAILURE; - - id = session->sessionID; - if (session->haveAltSessionID) - id = session->altSessionID; - - row = (int)(HashObject(id, ID_LEN, &error) % SESSION_ROWS); - if (error != 0) { - WOLFSSL_MSG("Hash session failed"); - return; - } - - sessRow = &SessionCache[row]; - if (get) - error = SESSION_ROW_RD_LOCK(sessRow); - else - error = SESSION_ROW_WR_LOCK(sessRow); - if (error != 0) { - WOLFSSL_MSG("Session row lock failed"); - return; - } - - for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) { - WOLFSSL_SESSION* cacheSession; -#ifdef SESSION_CACHE_DYNAMIC_MEM - cacheSession = sessRow->Sessions[i]; -#else - cacheSession = &sessRow->Sessions[i]; -#endif - if (cacheSession && - XMEMCMP(id, cacheSession->sessionID, ID_LEN) == 0 - && session->side == cacheSession->side - #if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) - && (IsAtLeastTLSv1_3(session->version) == - IsAtLeastTLSv1_3(cacheSession->version)) - #endif - ) { - if (get) { - if (getRet) { - *getRet = wolfSSL_CRYPTO_get_ex_data( - &cacheSession->ex_data, idx); - } - } - else { - if (setRet) { - *setRet = wolfSSL_CRYPTO_set_ex_data( - &cacheSession->ex_data, idx, data); - } - } - foundCache = 1; - break; - } - } - SESSION_ROW_UNLOCK(sessRow); - /* If we don't have a session in cache then clear the ex_data and - * own it */ - if (!foundCache) { - XMEMSET(&session->ex_data, 0, sizeof(WOLFSSL_CRYPTO_EX_DATA)); - session->ownExData = 1; - if (!get) { - *setRet = wolfSSL_CRYPTO_set_ex_data(&session->ex_data, idx, - data); - } - } - -} -#endif - -int wolfSSL_SESSION_set_ex_data(WOLFSSL_SESSION* session, int idx, void* data) -{ - int ret = WOLFSSL_FAILURE; - WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data"); -#ifdef HAVE_EX_DATA - session = ClientSessionToSession(session); - if (session != NULL) { -#ifndef NO_SESSION_CACHE - if (!session->ownExData) { - /* Need to update in cache */ - SESSION_ex_data_cache_update(session, idx, data, 0, NULL, &ret); - } - else -#endif - { - ret = wolfSSL_CRYPTO_set_ex_data(&session->ex_data, idx, data); - } - } -#else - (void)session; - (void)idx; - (void)data; -#endif - return ret; -} - -#ifdef HAVE_EX_DATA_CLEANUP_HOOKS -int wolfSSL_SESSION_set_ex_data_with_cleanup( - WOLFSSL_SESSION* session, - int idx, - void* data, - wolfSSL_ex_data_cleanup_routine_t cleanup_routine) -{ - WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data_with_cleanup"); - session = ClientSessionToSession(session); - if(session != NULL) { - return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&session->ex_data, idx, - data, cleanup_routine); - } - return WOLFSSL_FAILURE; -} -#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ - -void* wolfSSL_SESSION_get_ex_data(const WOLFSSL_SESSION* session, int idx) -{ - void* ret = NULL; - WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_data"); -#ifdef HAVE_EX_DATA - session = ClientSessionToSession(session); - if (session != NULL) { -#ifndef NO_SESSION_CACHE - if (!session->ownExData) { - /* Need to retrieve the data from the session cache */ - SESSION_ex_data_cache_update((WOLFSSL_SESSION*)session, idx, NULL, - 1, &ret, NULL); - } - else -#endif - { - ret = wolfSSL_CRYPTO_get_ex_data(&session->ex_data, idx); - } - } -#else - (void)session; - (void)idx; -#endif - return ret; -} -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL || HAVE_EX_DATA */ - /* Note: This is a huge section of API's - through * wolfSSL_X509_OBJECT_get0_X509_CRL */ #if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB))) -#ifdef HAVE_EX_DATA -int wolfSSL_SESSION_get_ex_new_index(long ctx_l,void* ctx_ptr, - WOLFSSL_CRYPTO_EX_new* new_func, WOLFSSL_CRYPTO_EX_dup* dup_func, - WOLFSSL_CRYPTO_EX_free* free_func) -{ - WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_new_index"); - return wolfssl_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_SESSION, ctx_l, - ctx_ptr, new_func, dup_func, free_func); -} -#endif #if defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) && \ !defined(WOLFSSL_STATIC_MEMORY) @@ -29338,220 +20150,6 @@ WOLFSSL_CTX* wolfSSL_get_SSL_CTX(WOLFSSL* ssl) return ssl->ctx; } -#if defined(OPENSSL_ALL) || \ - defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) - -const byte* wolfSSL_SESSION_get_id(const WOLFSSL_SESSION* sess, - unsigned int* idLen) -{ - WOLFSSL_ENTER("wolfSSL_SESSION_get_id"); - sess = ClientSessionToSession(sess); - if (sess == NULL || idLen == NULL) { - WOLFSSL_MSG("Bad func args. Please provide idLen"); - return NULL; - } -#ifdef HAVE_SESSION_TICKET - if (sess->haveAltSessionID) { - *idLen = ID_LEN; - return sess->altSessionID; - } -#endif - *idLen = sess->sessionIDSz; - return sess->sessionID; -} - -#if (defined(HAVE_SESSION_TICKET) || defined(SESSION_CERTS)) && \ - !defined(NO_FILESYSTEM) - -#ifndef NO_BIO - -#if defined(SESSION_CERTS) || \ - (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) -/* returns a pointer to the protocol used by the session */ -static const char* wolfSSL_SESSION_get_protocol(const WOLFSSL_SESSION* in) -{ - in = ClientSessionToSession(in); - return wolfSSL_internal_get_version((ProtocolVersion*)&in->version); -} -#endif - -/* returns true (non 0) if the session has EMS (extended master secret) */ -static int wolfSSL_SESSION_haveEMS(const WOLFSSL_SESSION* in) -{ - in = ClientSessionToSession(in); - if (in == NULL) - return 0; - return in->haveEMS; -} - -#if defined(HAVE_SESSION_TICKET) -/* prints out the ticket to bio passed in - * return WOLFSSL_SUCCESS on success - */ -static int wolfSSL_SESSION_print_ticket(WOLFSSL_BIO* bio, - const WOLFSSL_SESSION* in, const char* tab) -{ - unsigned short i, j, z, sz; - short tag = 0; - byte* pt; - - - in = ClientSessionToSession(in); - if (in == NULL || bio == NULL) { - return BAD_FUNC_ARG; - } - - sz = in->ticketLen; - pt = in->ticket; - - if (wolfSSL_BIO_printf(bio, "%s\n", (sz == 0)? " NONE": "") <= 0) - return WOLFSSL_FAILURE; - - for (i = 0; i < sz;) { - char asc[16]; - XMEMSET(asc, 0, sizeof(asc)); - - if (sz - i < 16) { - if (wolfSSL_BIO_printf(bio, "%s%04X -", tab, tag + (sz - i)) <= 0) - return WOLFSSL_FAILURE; - } - else { - if (wolfSSL_BIO_printf(bio, "%s%04X -", tab, tag) <= 0) - return WOLFSSL_FAILURE; - } - for (j = 0; i < sz && j < 8; j++,i++) { - asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; - if (wolfSSL_BIO_printf(bio, " %02X", pt[i]) <= 0) - return WOLFSSL_FAILURE; - } - - if (i < sz) { - asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; - if (wolfSSL_BIO_printf(bio, "-%02X", pt[i]) <= 0) - return WOLFSSL_FAILURE; - j++; - i++; - } - - for (; i < sz && j < 16; j++,i++) { - asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; - if (wolfSSL_BIO_printf(bio, " %02X", pt[i]) <= 0) - return WOLFSSL_FAILURE; - } - - /* pad out spacing */ - for (z = j; z < 17; z++) { - if (wolfSSL_BIO_printf(bio, " ") <= 0) - return WOLFSSL_FAILURE; - } - - for (z = 0; z < j; z++) { - if (wolfSSL_BIO_printf(bio, "%c", asc[z]) <= 0) - return WOLFSSL_FAILURE; - } - if (wolfSSL_BIO_printf(bio, "\n") <= 0) - return WOLFSSL_FAILURE; - - tag += 16; - } - return WOLFSSL_SUCCESS; -} -#endif /* HAVE_SESSION_TICKET */ - - -/* prints out the session information in human readable form - * return WOLFSSL_SUCCESS on success - */ -int wolfSSL_SESSION_print(WOLFSSL_BIO *bp, const WOLFSSL_SESSION *session) -{ - const unsigned char* pt; - unsigned char buf[SECRET_LEN]; - unsigned int sz = 0, i; - int ret; - - session = ClientSessionToSession(session); - if (session == NULL) { - return WOLFSSL_FAILURE; - } - - if (wolfSSL_BIO_printf(bp, "%s\n", "SSL-Session:") <= 0) - return WOLFSSL_FAILURE; - -#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET)) - if (wolfSSL_BIO_printf(bp, " Protocol : %s\n", - wolfSSL_SESSION_get_protocol(session)) <= 0) - return WOLFSSL_FAILURE; -#endif - - if (wolfSSL_BIO_printf(bp, " Cipher : %s\n", - wolfSSL_SESSION_CIPHER_get_name(session)) <= 0) - return WOLFSSL_FAILURE; - - pt = wolfSSL_SESSION_get_id(session, &sz); - if (wolfSSL_BIO_printf(bp, " Session-ID: ") <= 0) - return WOLFSSL_FAILURE; - - for (i = 0; i < sz; i++) { - if (wolfSSL_BIO_printf(bp, "%02X", pt[i]) <= 0) - return WOLFSSL_FAILURE; - } - if (wolfSSL_BIO_printf(bp, "\n") <= 0) - return WOLFSSL_FAILURE; - - if (wolfSSL_BIO_printf(bp, " Session-ID-ctx: \n") <= 0) - return WOLFSSL_FAILURE; - - ret = wolfSSL_SESSION_get_master_key(session, buf, sizeof(buf)); - if (wolfSSL_BIO_printf(bp, " Master-Key: ") <= 0) - return WOLFSSL_FAILURE; - - if (ret > 0) { - sz = (unsigned int)ret; - for (i = 0; i < sz; i++) { - if (wolfSSL_BIO_printf(bp, "%02X", buf[i]) <= 0) - return WOLFSSL_FAILURE; - } - } - if (wolfSSL_BIO_printf(bp, "\n") <= 0) - return WOLFSSL_FAILURE; - - /* @TODO PSK identity hint and SRP */ - - if (wolfSSL_BIO_printf(bp, " TLS session ticket:") <= 0) - return WOLFSSL_FAILURE; - -#ifdef HAVE_SESSION_TICKET - if (wolfSSL_SESSION_print_ticket(bp, session, " ") != WOLFSSL_SUCCESS) - return WOLFSSL_FAILURE; -#endif - -#if !defined(NO_SESSION_CACHE) && (defined(OPENSSL_EXTRA) || \ - defined(HAVE_EXT_CACHE)) - if (wolfSSL_BIO_printf(bp, " Start Time: %ld\n", - wolfSSL_SESSION_get_time(session)) <= 0) - return WOLFSSL_FAILURE; - - if (wolfSSL_BIO_printf(bp, " Timeout : %ld (sec)\n", - wolfSSL_SESSION_get_timeout(session)) <= 0) - return WOLFSSL_FAILURE; -#endif /* !NO_SESSION_CACHE && OPENSSL_EXTRA || HAVE_EXT_CACHE */ - - /* @TODO verify return code print */ - - if (wolfSSL_BIO_printf(bp, " Extended master secret: %s\n", - (wolfSSL_SESSION_haveEMS(session) == 0)? "no" : "yes") <= 0) - return WOLFSSL_FAILURE; - - return WOLFSSL_SUCCESS; -} - -#endif /* !NO_BIO */ -#endif /* (HAVE_SESSION_TICKET || SESSION_CERTS) && !NO_FILESYSTEM */ - -#endif /* OPENSSL_ALL || OPENSSL_EXTRA || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ - #if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && defined(HAVE_STUNNEL)) \ || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) @@ -29622,709 +20220,6 @@ int wolfSSL_CTX_get_verify_mode(const WOLFSSL_CTX* ctx) } #endif -#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE25519) -/* return 1 if success, 0 if error - * output keys are little endian format - */ -int wolfSSL_EC25519_generate_key(unsigned char *priv, unsigned int *privSz, - unsigned char *pub, unsigned int *pubSz) -{ -#ifndef WOLFSSL_KEY_GEN - WOLFSSL_MSG("No Key Gen built in"); - (void) priv; - (void) privSz; - (void) pub; - (void) pubSz; - return WOLFSSL_FAILURE; -#else /* WOLFSSL_KEY_GEN */ - int ret = WOLFSSL_FAILURE; - int initTmpRng = 0; - WC_RNG *rng = NULL; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG *tmpRNG = NULL; -#else - WC_RNG tmpRNG[1]; -#endif - - WOLFSSL_ENTER("wolfSSL_EC25519_generate_key"); - - if (priv == NULL || privSz == NULL || *privSz < CURVE25519_KEYSIZE || - pub == NULL || pubSz == NULL || *pubSz < CURVE25519_KEYSIZE) { - WOLFSSL_MSG("Bad arguments"); - return WOLFSSL_FAILURE; - } - -#ifdef WOLFSSL_SMALL_STACK - tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); - if (tmpRNG == NULL) - return WOLFSSL_FAILURE; -#endif - if (wc_InitRng(tmpRNG) == 0) { - rng = tmpRNG; - initTmpRng = 1; - } - else { - WOLFSSL_MSG("Bad RNG Init, trying global"); - if (initGlobalRNG == 0) - WOLFSSL_MSG("Global RNG no Init"); - else - rng = &globalRNG; - } - - if (rng) { - curve25519_key key; - - if (wc_curve25519_init(&key) != MP_OKAY) - WOLFSSL_MSG("wc_curve25519_init failed"); - else if (wc_curve25519_make_key(rng, CURVE25519_KEYSIZE, &key)!=MP_OKAY) - WOLFSSL_MSG("wc_curve25519_make_key failed"); - /* export key pair */ - else if (wc_curve25519_export_key_raw_ex(&key, priv, privSz, pub, - pubSz, EC25519_LITTLE_ENDIAN) - != MP_OKAY) - WOLFSSL_MSG("wc_curve25519_export_key_raw_ex failed"); - else - ret = WOLFSSL_SUCCESS; - - wc_curve25519_free(&key); - } - - if (initTmpRng) - wc_FreeRng(tmpRNG); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); -#endif - - return ret; -#endif /* WOLFSSL_KEY_GEN */ -} - -/* return 1 if success, 0 if error - * input and output keys are little endian format - */ -int wolfSSL_EC25519_shared_key(unsigned char *shared, unsigned int *sharedSz, - const unsigned char *priv, unsigned int privSz, - const unsigned char *pub, unsigned int pubSz) -{ -#ifndef WOLFSSL_KEY_GEN - WOLFSSL_MSG("No Key Gen built in"); - (void) shared; - (void) sharedSz; - (void) priv; - (void) privSz; - (void) pub; - (void) pubSz; - return WOLFSSL_FAILURE; -#else /* WOLFSSL_KEY_GEN */ - int ret = WOLFSSL_FAILURE; - curve25519_key privkey, pubkey; - - WOLFSSL_ENTER("wolfSSL_EC25519_shared_key"); - - if (shared == NULL || sharedSz == NULL || *sharedSz < CURVE25519_KEYSIZE || - priv == NULL || privSz < CURVE25519_KEYSIZE || - pub == NULL || pubSz < CURVE25519_KEYSIZE) { - WOLFSSL_MSG("Bad arguments"); - return WOLFSSL_FAILURE; - } - - /* import private key */ - if (wc_curve25519_init(&privkey) != MP_OKAY) { - WOLFSSL_MSG("wc_curve25519_init privkey failed"); - return ret; - } - if (wc_curve25519_import_private_ex(priv, privSz, &privkey, - EC25519_LITTLE_ENDIAN) != MP_OKAY) { - WOLFSSL_MSG("wc_curve25519_import_private_ex failed"); - wc_curve25519_free(&privkey); - return ret; - } - - /* import public key */ - if (wc_curve25519_init(&pubkey) != MP_OKAY) { - WOLFSSL_MSG("wc_curve25519_init pubkey failed"); - wc_curve25519_free(&privkey); - return ret; - } - if (wc_curve25519_import_public_ex(pub, pubSz, &pubkey, - EC25519_LITTLE_ENDIAN) != MP_OKAY) { - WOLFSSL_MSG("wc_curve25519_import_public_ex failed"); - wc_curve25519_free(&privkey); - wc_curve25519_free(&pubkey); - return ret; - } - - if (wc_curve25519_shared_secret_ex(&privkey, &pubkey, - shared, sharedSz, - EC25519_LITTLE_ENDIAN) != MP_OKAY) - WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed"); - else - ret = WOLFSSL_SUCCESS; - - wc_curve25519_free(&privkey); - wc_curve25519_free(&pubkey); - - return ret; -#endif /* WOLFSSL_KEY_GEN */ -} -#endif /* OPENSSL_EXTRA && HAVE_CURVE25519 */ - -#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) -/* return 1 if success, 0 if error - * output keys are little endian format - */ -int wolfSSL_ED25519_generate_key(unsigned char *priv, unsigned int *privSz, - unsigned char *pub, unsigned int *pubSz) -{ -#ifndef WOLFSSL_KEY_GEN - WOLFSSL_MSG("No Key Gen built in"); - (void) priv; - (void) privSz; - (void) pub; - (void) pubSz; - return WOLFSSL_FAILURE; -#elif !defined(HAVE_ED25519_KEY_EXPORT) - WOLFSSL_MSG("No ED25519 key export built in"); - (void) priv; - (void) privSz; - (void) pub; - (void) pubSz; - return WOLFSSL_FAILURE; -#else /* WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_EXPORT */ - int ret = WOLFSSL_FAILURE; - int initTmpRng = 0; - WC_RNG *rng = NULL; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG *tmpRNG = NULL; -#else - WC_RNG tmpRNG[1]; -#endif - - WOLFSSL_ENTER("wolfSSL_ED25519_generate_key"); - - if (priv == NULL || privSz == NULL || *privSz < ED25519_PRV_KEY_SIZE || - pub == NULL || pubSz == NULL || *pubSz < ED25519_PUB_KEY_SIZE) { - WOLFSSL_MSG("Bad arguments"); - return WOLFSSL_FAILURE; - } - -#ifdef WOLFSSL_SMALL_STACK - tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); - if (tmpRNG == NULL) - return WOLFSSL_FATAL_ERROR; -#endif - if (wc_InitRng(tmpRNG) == 0) { - rng = tmpRNG; - initTmpRng = 1; - } - else { - WOLFSSL_MSG("Bad RNG Init, trying global"); - if (initGlobalRNG == 0) - WOLFSSL_MSG("Global RNG no Init"); - else - rng = &globalRNG; - } - - if (rng) { - ed25519_key key; - - if (wc_ed25519_init(&key) != MP_OKAY) - WOLFSSL_MSG("wc_ed25519_init failed"); - else if (wc_ed25519_make_key(rng, ED25519_KEY_SIZE, &key)!=MP_OKAY) - WOLFSSL_MSG("wc_ed25519_make_key failed"); - /* export private key */ - else if (wc_ed25519_export_key(&key, priv, privSz, pub, pubSz)!=MP_OKAY) - WOLFSSL_MSG("wc_ed25519_export_key failed"); - else - ret = WOLFSSL_SUCCESS; - - wc_ed25519_free(&key); - } - - if (initTmpRng) - wc_FreeRng(tmpRNG); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); -#endif - - return ret; -#endif /* WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_EXPORT */ -} - -/* return 1 if success, 0 if error - * input and output keys are little endian format - * priv is a buffer containing private and public part of key - */ -int wolfSSL_ED25519_sign(const unsigned char *msg, unsigned int msgSz, - const unsigned char *priv, unsigned int privSz, - unsigned char *sig, unsigned int *sigSz) -{ -#if !defined(HAVE_ED25519_SIGN) || !defined(WOLFSSL_KEY_GEN) || !defined(HAVE_ED25519_KEY_IMPORT) -#if !defined(HAVE_ED25519_SIGN) - WOLFSSL_MSG("No ED25519 sign built in"); -#elif !defined(WOLFSSL_KEY_GEN) - WOLFSSL_MSG("No Key Gen built in"); -#elif !defined(HAVE_ED25519_KEY_IMPORT) - WOLFSSL_MSG("No ED25519 Key import built in"); -#endif - (void) msg; - (void) msgSz; - (void) priv; - (void) privSz; - (void) sig; - (void) sigSz; - return WOLFSSL_FAILURE; -#else /* HAVE_ED25519_SIGN && WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_IMPORT */ - ed25519_key key; - int ret = WOLFSSL_FAILURE; - - WOLFSSL_ENTER("wolfSSL_ED25519_sign"); - - if (priv == NULL || privSz != ED25519_PRV_KEY_SIZE || - msg == NULL || sig == NULL || *sigSz < ED25519_SIG_SIZE) { - WOLFSSL_MSG("Bad arguments"); - return WOLFSSL_FAILURE; - } - - /* import key */ - if (wc_ed25519_init(&key) != MP_OKAY) { - WOLFSSL_MSG("wc_curve25519_init failed"); - return ret; - } - if (wc_ed25519_import_private_key(priv, privSz/2, - priv+(privSz/2), ED25519_PUB_KEY_SIZE, - &key) != MP_OKAY){ - WOLFSSL_MSG("wc_ed25519_import_private failed"); - wc_ed25519_free(&key); - return ret; - } - - if (wc_ed25519_sign_msg(msg, msgSz, sig, sigSz, &key) != MP_OKAY) - WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed"); - else - ret = WOLFSSL_SUCCESS; - - wc_ed25519_free(&key); - - return ret; -#endif /* HAVE_ED25519_SIGN && WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_IMPORT */ -} - -/* return 1 if success, 0 if error - * input and output keys are little endian format - * pub is a buffer containing public part of key - */ -int wolfSSL_ED25519_verify(const unsigned char *msg, unsigned int msgSz, - const unsigned char *pub, unsigned int pubSz, - const unsigned char *sig, unsigned int sigSz) -{ -#if !defined(HAVE_ED25519_VERIFY) || !defined(WOLFSSL_KEY_GEN) || !defined(HAVE_ED25519_KEY_IMPORT) -#if !defined(HAVE_ED25519_VERIFY) - WOLFSSL_MSG("No ED25519 verify built in"); -#elif !defined(WOLFSSL_KEY_GEN) - WOLFSSL_MSG("No Key Gen built in"); -#elif !defined(HAVE_ED25519_KEY_IMPORT) - WOLFSSL_MSG("No ED25519 Key import built in"); -#endif - (void) msg; - (void) msgSz; - (void) pub; - (void) pubSz; - (void) sig; - (void) sigSz; - return WOLFSSL_FAILURE; -#else /* HAVE_ED25519_VERIFY && WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_IMPORT */ - ed25519_key key; - int ret = WOLFSSL_FAILURE, check = 0; - - WOLFSSL_ENTER("wolfSSL_ED25519_verify"); - - if (pub == NULL || pubSz != ED25519_PUB_KEY_SIZE || - msg == NULL || sig == NULL || sigSz != ED25519_SIG_SIZE) { - WOLFSSL_MSG("Bad arguments"); - return WOLFSSL_FAILURE; - } - - /* import key */ - if (wc_ed25519_init(&key) != MP_OKAY) { - WOLFSSL_MSG("wc_curve25519_init failed"); - return ret; - } - if (wc_ed25519_import_public(pub, pubSz, &key) != MP_OKAY){ - WOLFSSL_MSG("wc_ed25519_import_public failed"); - wc_ed25519_free(&key); - return ret; - } - - if ((ret = wc_ed25519_verify_msg((byte*)sig, sigSz, msg, msgSz, - &check, &key)) != MP_OKAY) { - WOLFSSL_MSG("wc_ed25519_verify_msg failed"); - } - else if (!check) - WOLFSSL_MSG("wc_ed25519_verify_msg failed (signature invalid)"); - else - ret = WOLFSSL_SUCCESS; - - wc_ed25519_free(&key); - - return ret; -#endif /* HAVE_ED25519_VERIFY && WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_IMPORT */ -} - -#endif /* OPENSSL_EXTRA && HAVE_ED25519 */ - -#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE448) -/* return 1 if success, 0 if error - * output keys are little endian format - */ -int wolfSSL_EC448_generate_key(unsigned char *priv, unsigned int *privSz, - unsigned char *pub, unsigned int *pubSz) -{ -#ifndef WOLFSSL_KEY_GEN - WOLFSSL_MSG("No Key Gen built in"); - (void) priv; - (void) privSz; - (void) pub; - (void) pubSz; - return WOLFSSL_FAILURE; -#else /* WOLFSSL_KEY_GEN */ - int ret = WOLFSSL_FAILURE; - int initTmpRng = 0; - WC_RNG *rng = NULL; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG *tmpRNG = NULL; -#else - WC_RNG tmpRNG[1]; -#endif - - WOLFSSL_ENTER("wolfSSL_EC448_generate_key"); - - if (priv == NULL || privSz == NULL || *privSz < CURVE448_KEY_SIZE || - pub == NULL || pubSz == NULL || *pubSz < CURVE448_KEY_SIZE) { - WOLFSSL_MSG("Bad arguments"); - return WOLFSSL_FAILURE; - } - -#ifdef WOLFSSL_SMALL_STACK - tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); - if (tmpRNG == NULL) - return WOLFSSL_FAILURE; -#endif - if (wc_InitRng(tmpRNG) == 0) { - rng = tmpRNG; - initTmpRng = 1; - } - else { - WOLFSSL_MSG("Bad RNG Init, trying global"); - if (initGlobalRNG == 0) - WOLFSSL_MSG("Global RNG no Init"); - else - rng = &globalRNG; - } - - if (rng) { - curve448_key key; - - if (wc_curve448_init(&key) != MP_OKAY) - WOLFSSL_MSG("wc_curve448_init failed"); - else if (wc_curve448_make_key(rng, CURVE448_KEY_SIZE, &key)!=MP_OKAY) - WOLFSSL_MSG("wc_curve448_make_key failed"); - /* export key pair */ - else if (wc_curve448_export_key_raw_ex(&key, priv, privSz, pub, pubSz, - EC448_LITTLE_ENDIAN) - != MP_OKAY) - WOLFSSL_MSG("wc_curve448_export_key_raw_ex failed"); - else - ret = WOLFSSL_SUCCESS; - - wc_curve448_free(&key); - } - - if (initTmpRng) - wc_FreeRng(tmpRNG); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); -#endif - - return ret; -#endif /* WOLFSSL_KEY_GEN */ -} - -/* return 1 if success, 0 if error - * input and output keys are little endian format - */ -int wolfSSL_EC448_shared_key(unsigned char *shared, unsigned int *sharedSz, - const unsigned char *priv, unsigned int privSz, - const unsigned char *pub, unsigned int pubSz) -{ -#ifndef WOLFSSL_KEY_GEN - WOLFSSL_MSG("No Key Gen built in"); - (void) shared; - (void) sharedSz; - (void) priv; - (void) privSz; - (void) pub; - (void) pubSz; - return WOLFSSL_FAILURE; -#else /* WOLFSSL_KEY_GEN */ - int ret = WOLFSSL_FAILURE; - curve448_key privkey, pubkey; - - WOLFSSL_ENTER("wolfSSL_EC448_shared_key"); - - if (shared == NULL || sharedSz == NULL || *sharedSz < CURVE448_KEY_SIZE || - priv == NULL || privSz < CURVE448_KEY_SIZE || - pub == NULL || pubSz < CURVE448_KEY_SIZE) { - WOLFSSL_MSG("Bad arguments"); - return WOLFSSL_FAILURE; - } - - /* import private key */ - if (wc_curve448_init(&privkey) != MP_OKAY) { - WOLFSSL_MSG("wc_curve448_init privkey failed"); - return ret; - } - if (wc_curve448_import_private_ex(priv, privSz, &privkey, - EC448_LITTLE_ENDIAN) != MP_OKAY) { - WOLFSSL_MSG("wc_curve448_import_private_ex failed"); - wc_curve448_free(&privkey); - return ret; - } - - /* import public key */ - if (wc_curve448_init(&pubkey) != MP_OKAY) { - WOLFSSL_MSG("wc_curve448_init pubkey failed"); - wc_curve448_free(&privkey); - return ret; - } - if (wc_curve448_import_public_ex(pub, pubSz, &pubkey, - EC448_LITTLE_ENDIAN) != MP_OKAY) { - WOLFSSL_MSG("wc_curve448_import_public_ex failed"); - wc_curve448_free(&privkey); - wc_curve448_free(&pubkey); - return ret; - } - - if (wc_curve448_shared_secret_ex(&privkey, &pubkey, shared, sharedSz, - EC448_LITTLE_ENDIAN) != MP_OKAY) - WOLFSSL_MSG("wc_curve448_shared_secret_ex failed"); - else - ret = WOLFSSL_SUCCESS; - - wc_curve448_free(&privkey); - wc_curve448_free(&pubkey); - - return ret; -#endif /* WOLFSSL_KEY_GEN */ -} -#endif /* OPENSSL_EXTRA && HAVE_CURVE448 */ - -#if defined(OPENSSL_EXTRA) && defined(HAVE_ED448) -/* return 1 if success, 0 if error - * output keys are little endian format - */ -int wolfSSL_ED448_generate_key(unsigned char *priv, unsigned int *privSz, - unsigned char *pub, unsigned int *pubSz) -{ -#ifndef WOLFSSL_KEY_GEN - WOLFSSL_MSG("No Key Gen built in"); - (void) priv; - (void) privSz; - (void) pub; - (void) pubSz; - return WOLFSSL_FAILURE; -#elif !defined(HAVE_ED448_KEY_EXPORT) - WOLFSSL_MSG("No ED448 key export built in"); - (void) priv; - (void) privSz; - (void) pub; - (void) pubSz; - return WOLFSSL_FAILURE; -#else /* WOLFSSL_KEY_GEN && HAVE_ED448_KEY_EXPORT */ - int ret = WOLFSSL_FAILURE; - int initTmpRng = 0; - WC_RNG *rng = NULL; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG *tmpRNG = NULL; -#else - WC_RNG tmpRNG[1]; -#endif - - WOLFSSL_ENTER("wolfSSL_ED448_generate_key"); - - if (priv == NULL || privSz == NULL || *privSz < ED448_PRV_KEY_SIZE || - pub == NULL || pubSz == NULL || *pubSz < ED448_PUB_KEY_SIZE) { - WOLFSSL_MSG("Bad arguments"); - return WOLFSSL_FAILURE; - } - -#ifdef WOLFSSL_SMALL_STACK - tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); - if (tmpRNG == NULL) - return WOLFSSL_FATAL_ERROR; -#endif - if (wc_InitRng(tmpRNG) == 0) { - rng = tmpRNG; - initTmpRng = 1; - } - else { - WOLFSSL_MSG("Bad RNG Init, trying global"); - if (initGlobalRNG == 0) - WOLFSSL_MSG("Global RNG no Init"); - else - rng = &globalRNG; - } - - if (rng) { - ed448_key key; - - if (wc_ed448_init(&key) != MP_OKAY) - WOLFSSL_MSG("wc_ed448_init failed"); - else if (wc_ed448_make_key(rng, ED448_KEY_SIZE, &key) != MP_OKAY) - WOLFSSL_MSG("wc_ed448_make_key failed"); - /* export private key */ - else if (wc_ed448_export_key(&key, priv, privSz, pub, pubSz) != MP_OKAY) - WOLFSSL_MSG("wc_ed448_export_key failed"); - else - ret = WOLFSSL_SUCCESS; - - wc_ed448_free(&key); - } - - if (initTmpRng) - wc_FreeRng(tmpRNG); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); -#endif - - return ret; -#endif /* WOLFSSL_KEY_GEN && HAVE_ED448_KEY_EXPORT */ -} - -/* return 1 if success, 0 if error - * input and output keys are little endian format - * priv is a buffer containing private and public part of key - */ -int wolfSSL_ED448_sign(const unsigned char *msg, unsigned int msgSz, - const unsigned char *priv, unsigned int privSz, - unsigned char *sig, unsigned int *sigSz) -{ -#if !defined(HAVE_ED448_SIGN) || !defined(WOLFSSL_KEY_GEN) || !defined(HAVE_ED448_KEY_IMPORT) -#if !defined(HAVE_ED448_SIGN) - WOLFSSL_MSG("No ED448 sign built in"); -#elif !defined(WOLFSSL_KEY_GEN) - WOLFSSL_MSG("No Key Gen built in"); -#elif !defined(HAVE_ED448_KEY_IMPORT) - WOLFSSL_MSG("No ED448 Key import built in"); -#endif - (void) msg; - (void) msgSz; - (void) priv; - (void) privSz; - (void) sig; - (void) sigSz; - return WOLFSSL_FAILURE; -#else /* HAVE_ED448_SIGN && WOLFSSL_KEY_GEN && HAVE_ED448_KEY_IMPORT */ - ed448_key key; - int ret = WOLFSSL_FAILURE; - - WOLFSSL_ENTER("wolfSSL_ED448_sign"); - - if (priv == NULL || privSz != ED448_PRV_KEY_SIZE || msg == NULL || - sig == NULL || *sigSz < ED448_SIG_SIZE) { - WOLFSSL_MSG("Bad arguments"); - return WOLFSSL_FAILURE; - } - - /* import key */ - if (wc_ed448_init(&key) != MP_OKAY) { - WOLFSSL_MSG("wc_curve448_init failed"); - return ret; - } - if (wc_ed448_import_private_key(priv, privSz/2, priv+(privSz/2), - ED448_PUB_KEY_SIZE, &key) != MP_OKAY){ - WOLFSSL_MSG("wc_ed448_import_private failed"); - wc_ed448_free(&key); - return ret; - } - - if (wc_ed448_sign_msg(msg, msgSz, sig, sigSz, &key, NULL, 0) != MP_OKAY) - WOLFSSL_MSG("wc_curve448_shared_secret_ex failed"); - else - ret = WOLFSSL_SUCCESS; - - wc_ed448_free(&key); - - return ret; -#endif /* HAVE_ED448_SIGN && WOLFSSL_KEY_GEN && HAVE_ED448_KEY_IMPORT */ -} - -/* return 1 if success, 0 if error - * input and output keys are little endian format - * pub is a buffer containing public part of key - */ -int wolfSSL_ED448_verify(const unsigned char *msg, unsigned int msgSz, - const unsigned char *pub, unsigned int pubSz, - const unsigned char *sig, unsigned int sigSz) -{ -#if !defined(HAVE_ED448_VERIFY) || !defined(WOLFSSL_KEY_GEN) || !defined(HAVE_ED448_KEY_IMPORT) -#if !defined(HAVE_ED448_VERIFY) - WOLFSSL_MSG("No ED448 verify built in"); -#elif !defined(WOLFSSL_KEY_GEN) - WOLFSSL_MSG("No Key Gen built in"); -#elif !defined(HAVE_ED448_KEY_IMPORT) - WOLFSSL_MSG("No ED448 Key import built in"); -#endif - (void) msg; - (void) msgSz; - (void) pub; - (void) pubSz; - (void) sig; - (void) sigSz; - return WOLFSSL_FAILURE; -#else /* HAVE_ED448_VERIFY && WOLFSSL_KEY_GEN && HAVE_ED448_KEY_IMPORT */ - ed448_key key; - int ret = WOLFSSL_FAILURE, check = 0; - - WOLFSSL_ENTER("wolfSSL_ED448_verify"); - - if (pub == NULL || pubSz != ED448_PUB_KEY_SIZE || msg == NULL || - sig == NULL || sigSz != ED448_SIG_SIZE) { - WOLFSSL_MSG("Bad arguments"); - return WOLFSSL_FAILURE; - } - - /* import key */ - if (wc_ed448_init(&key) != MP_OKAY) { - WOLFSSL_MSG("wc_curve448_init failed"); - return ret; - } - if (wc_ed448_import_public(pub, pubSz, &key) != MP_OKAY){ - WOLFSSL_MSG("wc_ed448_import_public failed"); - wc_ed448_free(&key); - return ret; - } - - if ((ret = wc_ed448_verify_msg((byte*)sig, sigSz, msg, msgSz, &check, - &key, NULL, 0)) != MP_OKAY) { - WOLFSSL_MSG("wc_ed448_verify_msg failed"); - } - else if (!check) - WOLFSSL_MSG("wc_ed448_verify_msg failed (signature invalid)"); - else - ret = WOLFSSL_SUCCESS; - - wc_ed448_free(&key); - - return ret; -#endif /* HAVE_ED448_VERIFY && WOLFSSL_KEY_GEN */ -} - -#endif /* OPENSSL_EXTRA && HAVE_ED448 */ #ifdef WOLFSSL_JNI @@ -30591,8 +20486,9 @@ WOLF_STACK_OF(WOLFSSL_CIPHER) *wolfSSL_get_ciphers_compat(const WOLFSSL *ssl) } #endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ -#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ - || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || defined(HAVE_SECRET_CALLBACK) +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) || \ + defined(HAVE_LIGHTY) || defined(HAVE_SECRET_CALLBACK) long wolfSSL_SSL_CTX_get_timeout(const WOLFSSL_CTX *ctx) { WOLFSSL_ENTER("wolfSSL_SSL_CTX_get_timeout"); @@ -30631,81 +20527,6 @@ int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh) return WOLFSSL_SUCCESS; } #endif -#ifndef NO_SESSION_CACHE -int wolfSSL_SSL_CTX_remove_session(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *s) -{ -#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) - int rem_called = FALSE; -#endif - - WOLFSSL_ENTER("wolfSSL_SSL_CTX_remove_session"); - - s = ClientSessionToSession(s); - if (ctx == NULL || s == NULL) - return BAD_FUNC_ARG; - -#ifdef HAVE_EXT_CACHE - if (!ctx->internalCacheOff) -#endif - { - const byte* id; - WOLFSSL_SESSION *sess = NULL; - word32 row = 0; - int ret; - - id = s->sessionID; - if (s->haveAltSessionID) - id = s->altSessionID; - - ret = TlsSessionCacheGetAndWrLock(id, &sess, &row, ctx->method->side); - if (ret == 0 && sess != NULL) { -#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) - if (sess->rem_sess_cb != NULL) { - rem_called = TRUE; - } -#endif - /* Call this before changing ownExData so that calls to ex_data - * don't try to access the SessionCache again. */ - EvictSessionFromCache(sess); -#ifdef HAVE_EX_DATA - if (sess->ownExData) { - /* Most recent version of ex data is in cache. Copy it - * over so the user can free it. */ - XMEMCPY(&s->ex_data, &sess->ex_data, - sizeof(WOLFSSL_CRYPTO_EX_DATA)); - s->ownExData = 1; - sess->ownExData = 0; - } -#endif -#ifdef SESSION_CACHE_DYNAMIC_MEM - { - /* Find and clear entry. Row is locked so we are good to go. */ - int idx; - for (idx = 0; idx < SESSIONS_PER_ROW; idx++) { - if (sess == SessionCache[row].Sessions[idx]) { - XFREE(sess, sess->heap, DYNAMIC_TYPE_SESSION); - SessionCache[row].Sessions[idx] = NULL; - break; - } - } - } -#endif - TlsSessionCacheUnlockRow(row); - } - } - -#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) - if (ctx->rem_sess_cb != NULL && !rem_called) { - ctx->rem_sess_cb(ctx, s); - } -#endif - - /* s cannot be resumed at this point */ - s->timeout = 0; - - return 0; -} -#endif /* !NO_SESSION_CACHE */ #ifndef NO_BIO BIO *wolfSSL_SSL_get_rbio(const WOLFSSL *s) { @@ -30803,17 +20624,6 @@ int wolfSSL_SSL_in_connect_init(WOLFSSL* ssl) ssl->options.acceptState < ACCEPT_THIRD_REPLY_DONE; } -#ifndef NO_SESSION_CACHE - -WOLFSSL_SESSION *wolfSSL_SSL_get0_session(const WOLFSSL *ssl) -{ - WOLFSSL_ENTER("wolfSSL_SSL_get0_session"); - - return ssl->session; -} - -#endif /* NO_SESSION_CACHE */ - #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) /* Expected return values from implementations of OpenSSL ticket key callback. */ @@ -31097,7 +20907,8 @@ int wolfSSL_get_ocsp_producedDate( if (XSTRLEN((char *)ssl->ocspProducedDate) >= producedDate_space) return BUFFER_E; - XSTRNCPY((char *)producedDate, (const char *)ssl->ocspProducedDate, producedDate_space); + XSTRNCPY((char *)producedDate, (const char *)ssl->ocspProducedDate, + producedDate_space); *producedDateFormat = ssl->ocspProducedDateFormat; return 0; @@ -31124,7 +20935,8 @@ int wolfSSL_get_ocsp_producedDate_tm(WOLFSSL *ssl, struct tm *produced_tm) { #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) -int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, WOLF_STACK_OF(X509)** chain) +int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, + WOLF_STACK_OF(X509)** chain) { word32 idx; word32 length; @@ -31292,8 +21104,8 @@ void wolfSSL_sk_WOLFSSL_STRING_free(WOLF_STACK_OF(WOLFSSL_STRING)* sk) } } -WOLFSSL_STRING wolfSSL_sk_WOLFSSL_STRING_value(WOLF_STACK_OF(WOLFSSL_STRING)* strings, - int idx) +WOLFSSL_STRING wolfSSL_sk_WOLFSSL_STRING_value( + WOLF_STACK_OF(WOLFSSL_STRING)* strings, int idx) { for (; idx > 0 && strings != NULL; idx--) strings = strings->next; @@ -31413,8 +21225,8 @@ void wolfSSL_CTX_set_next_proto_select_cb(WOLFSSL_CTX *s, WOLFSSL_STUB("wolfSSL_CTX_set_next_proto_select_cb"); } -void wolfSSL_get0_next_proto_negotiated(const WOLFSSL *s, const unsigned char **data, - unsigned *len) +void wolfSSL_get0_next_proto_negotiated(const WOLFSSL *s, + const unsigned char **data, unsigned *len) { (void)s; (void)data; @@ -31706,7 +21518,8 @@ int wolfSSL_set_msg_callback_arg(WOLFSSL *ssl, void* arg) return WOLFSSL_SUCCESS; } -void *wolfSSL_OPENSSL_memdup(const void *data, size_t siz, const char* file, int line) +void *wolfSSL_OPENSSL_memdup(const void *data, size_t siz, const char* file, + int line) { void *ret; (void)file; @@ -32648,150 +22461,6 @@ void wolfSSL_ERR_remove_state(unsigned long id) #ifdef OPENSSL_ALL #if !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) -int wolfSSL_PEM_write_bio_PKCS8PrivateKey(WOLFSSL_BIO* bio, - WOLFSSL_EVP_PKEY* pkey, - const WOLFSSL_EVP_CIPHER* enc, - char* passwd, int passwdSz, - wc_pem_password_cb* cb, void* ctx) -{ - int ret = 0; - char password[NAME_SZ]; - byte* key = NULL; - word32 keySz; - byte* pem = NULL; - int pemSz = 0; - int type = PKCS8_PRIVATEKEY_TYPE; - const byte* curveOid; - word32 oidSz; - - if (bio == NULL || pkey == NULL) - return -1; - - keySz = pkey->pkey_sz + 128; - key = (byte*)XMALLOC(keySz, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (key == NULL) - ret = MEMORY_E; - - if (ret == 0 && enc != NULL && passwd == NULL) { - passwdSz = cb(password, sizeof(password), 1, ctx); - if (passwdSz < 0) - ret = WOLFSSL_FAILURE; - passwd = password; - } - - if (ret == 0 && enc != NULL) { - WC_RNG rng; - ret = wc_InitRng(&rng); - if (ret == 0) { - int encAlgId = 0; - #ifndef NO_DES3 - if (enc == EVP_DES_CBC) - encAlgId = DESb; - else if (enc == EVP_DES_EDE3_CBC) - encAlgId = DES3b; - else - #endif - #if !defined(NO_AES) && defined(HAVE_AES_CBC) - #ifdef WOLFSSL_AES_256 - if (enc == EVP_AES_256_CBC) - encAlgId = AES256CBCb; - else - #endif - #endif - ret = -1; - if (ret == 0) { - ret = TraditionalEnc((byte*)pkey->pkey.ptr, pkey->pkey_sz, key, - &keySz, passwd, passwdSz, PKCS5, PBES2, - encAlgId, NULL, 0, WC_PKCS12_ITT_DEFAULT, - &rng, NULL); - if (ret > 0) { - keySz = ret; - ret = 0; - } - } - wc_FreeRng(&rng); - } - type = PKCS8_ENC_PRIVATEKEY_TYPE; - } - if (ret == 0 && enc == NULL) { - int algId; - type = PKCS8_PRIVATEKEY_TYPE; - #ifdef HAVE_ECC - if (pkey->type == EVP_PKEY_EC) { - algId = ECDSAk; - ret = wc_ecc_get_oid(pkey->ecc->group->curve_oid, &curveOid, - &oidSz); - } - else - #endif - { - algId = RSAk; - curveOid = NULL; - oidSz = 0; - } - - #ifdef HAVE_ECC - if (ret >= 0) - #endif - { - ret = wc_CreatePKCS8Key(key, &keySz, (byte*)pkey->pkey.ptr, - pkey->pkey_sz, algId, curveOid, oidSz); - keySz = ret; - } - } - - if (password == passwd) - XMEMSET(password, 0, passwdSz); - - if (ret >= 0) { - pemSz = 2 * keySz + 2 * 64; - pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (pem == NULL) - ret = MEMORY_E; - } - - if (ret >= 0) - ret = wc_DerToPemEx(key, keySz, pem, pemSz, NULL, type); - - if (key != NULL) - XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - if (ret >= 0) { - if (wolfSSL_BIO_write(bio, pem, ret) != ret) - ret = -1; - } - - if (pem != NULL) - XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - return ret < 0 ? 0 : ret; - -} - -#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) -int wolfSSL_PEM_write_PKCS8PrivateKey(XFILE f, WOLFSSL_EVP_PKEY* pkey, - const WOLFSSL_EVP_CIPHER* enc, char* passwd, int passwdSz, - wc_pem_password_cb* cb, void* ctx) -{ - int ret = WOLFSSL_SUCCESS; - BIO *b; - - WOLFSSL_ENTER("wolfSSL_PEM_write_PKCS8PrivateKey"); - - b = wolfSSL_BIO_new_fp(f, BIO_NOCLOSE); - if (b == NULL) { - ret = WOLFSSL_FAILURE; - } - if (ret == WOLFSSL_SUCCESS) { - ret = wolfSSL_PEM_write_bio_PKCS8PrivateKey(b, pkey, enc, passwd, - passwdSz, cb, ctx); - } - - wolfSSL_BIO_free(b); - - return ret; -} -#endif /* !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ static int bio_get_data(WOLFSSL_BIO* bio, byte** data) { @@ -32972,7 +22641,8 @@ int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr) if (der != NULL) { ecc_key* key = (ecc_key*)keyPtr; WOLFSSL_MSG("Using static ECDH key"); - ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, der->length); + ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, + der->length); } break; #endif @@ -33106,8 +22776,8 @@ static int SetStaticEphemeralKey(WOLFSSL_CTX* ctx, curve25519_key x25519Key; ret = wc_curve25519_init_ex(&x25519Key, heap, INVALID_DEVID); if (ret == 0) { - ret = wc_Curve25519PrivateKeyDecode(keyBuf, &idx, &x25519Key, - keySz); + ret = wc_Curve25519PrivateKeyDecode(keyBuf, &idx, + &x25519Key, keySz); if (ret == 0) keyAlgo = WC_PK_TYPE_CURVE25519; wc_curve25519_free(&x25519Key); @@ -33375,36 +23045,14 @@ int wolfSSL_CTX_get_security_level(const WOLFSSL_CTX* ctx) return 0; } - -/** - * Determine whether a WOLFSSL_SESSION object can be used for resumption - * @param s a pointer to WOLFSSL_SESSION structure - * @return return 1 if session is resumable, otherwise 0. - */ -int wolfSSL_SESSION_is_resumable(const WOLFSSL_SESSION *s) -{ - s = ClientSessionToSession(s); - if (s == NULL) - return 0; - -#ifdef HAVE_SESSION_TICKET - if (s->ticketLen > 0) - return 1; -#endif - - if (s->sessionIDSz > 0) - return 1; - - return 0; -} - #if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK) /* * This API accepts a user callback which puts key-log records into * a KEY LOGFILE. The callback is stored into a CTX and propagated to * each SSL object on its creation timing. */ -void wolfSSL_CTX_set_keylog_callback(WOLFSSL_CTX* ctx, wolfSSL_CTX_keylog_cb_func cb) +void wolfSSL_CTX_set_keylog_callback(WOLFSSL_CTX* ctx, + wolfSSL_CTX_keylog_cb_func cb) { WOLFSSL_ENTER("wolfSSL_CTX_set_keylog_callback"); /* stores the callback into WOLFSSL_CTX */ @@ -33433,9 +23081,10 @@ wolfSSL_CTX_keylog_cb_func wolfSSL_CTX_get_keylog_callback( /******************************************************************************* * START OF standard C library wrapping APIs ******************************************************************************/ -#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \ - defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_OPENSSH))) +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH))) #ifndef NO_WOLFSSL_STUB int wolfSSL_CRYPTO_set_mem_ex_functions(void *(*m) (size_t, const char *, int), void *(*r) (void *, size_t, const char *, @@ -33489,9 +23138,10 @@ void *wolfSSL_CRYPTO_malloc(size_t num, const char *file, int line) /******************************************************************************* * START OF EX_DATA APIs ******************************************************************************/ -#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \ - defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_OPENSSH))) +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH))) void wolfSSL_CRYPTO_cleanup_all_ex_data(void){ WOLFSSL_ENTER("CRYPTO_cleanup_all_ex_data"); } @@ -33512,7 +23162,8 @@ void* wolfSSL_CRYPTO_get_ex_data(const WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx) return NULL; } -int wolfSSL_CRYPTO_set_ex_data(WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx, void *data) +int wolfSSL_CRYPTO_set_ex_data(WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx, + void *data) { WOLFSSL_ENTER("wolfSSL_CRYPTO_set_ex_data"); #ifdef MAX_EX_DATA @@ -33926,8 +23577,9 @@ int wolfSSL_RAND_write_file(const char* fname) #ifndef FREERTOS_TCP /* These constant values are protocol values made by egd */ -#if defined(USE_WOLFSSL_IO) && !defined(USE_WINDOWS_API) && !defined(HAVE_FIPS) && \ - defined(HAVE_HASHDRBG) && !defined(NETOS) && defined(HAVE_SYS_UN_H) +#if defined(USE_WOLFSSL_IO) && !defined(USE_WINDOWS_API) && \ + !defined(HAVE_FIPS) && defined(HAVE_HASHDRBG) && !defined(NETOS) && \ + defined(HAVE_SYS_UN_H) #define WOLFSSL_EGD_NBLOCK 0x01 #include #endif @@ -34115,7 +23767,8 @@ void wolfSSL_RAND_Cleanup(void) #endif } -/* returns WOLFSSL_SUCCESS if the bytes generated are valid otherwise WOLFSSL_FAILURE */ +/* returns WOLFSSL_SUCCESS if the bytes generated are valid otherwise + * WOLFSSL_FAILURE */ int wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num) { int ret; @@ -34165,7 +23818,8 @@ int wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num) return ret; } -/* returns WOLFSSL_SUCCESS if the bytes generated are valid otherwise WOLFSSL_FAILURE */ +/* returns WOLFSSL_SUCCESS if the bytes generated are valid otherwise + * WOLFSSL_FAILURE */ int wolfSSL_RAND_bytes(unsigned char* buf, int num) { int ret = 0; @@ -34287,7 +23941,8 @@ int wolfSSL_RAND_poll(void) int wolfSSL_RAND_set_rand_method(const WOLFSSL_RAND_METHOD *methods) { #ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { + if (wolfSSL_RAND_InitMutex() == 0 && + wc_LockMutex(&gRandMethodMutex) == 0) { gRandMethods = methods; wc_UnLockMutex(&gRandMethodMutex); return WOLFSSL_SUCCESS; @@ -34303,7 +23958,8 @@ int wolfSSL_RAND_poll(void) { int ret = WOLFSSL_SUCCESS; #ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { + if (wolfSSL_RAND_InitMutex() == 0 && + wc_LockMutex(&gRandMethodMutex) == 0) { if (gRandMethods && gRandMethods->status) ret = gRandMethods->status(); wc_UnLockMutex(&gRandMethodMutex); @@ -34320,7 +23976,8 @@ int wolfSSL_RAND_poll(void) void wolfSSL_RAND_add(const void* add, int len, double entropy) { #ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { + if (wolfSSL_RAND_InitMutex() == 0 && + wc_LockMutex(&gRandMethodMutex) == 0) { if (gRandMethods && gRandMethods->add) { /* callback has return code, but RAND_add does not */ (void)gRandMethods->add(add, len, entropy); @@ -34336,6 +23993,24 @@ int wolfSSL_RAND_poll(void) #endif } + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_RAND_screen(void) +{ + WOLFSSL_STUB("RAND_screen"); +} +#endif + +int wolfSSL_RAND_load_file(const char* fname, long len) +{ + (void)fname; + /* wolfCrypt provides enough entropy internally or will report error */ + if (len == -1) + return 1024; + else + return (int)len; +} + #endif /* OPENSSL_EXTRA */ /******************************************************************************* @@ -34704,2082 +24379,8 @@ void wolfSSL_aes_ctr_iv(WOLFSSL_EVP_CIPHER_CTX* ctx, int doset, #define WOLFSSL_X509_STORE_INCLUDED #include -/******************************************************************************* - * START OF PKCS7 APIs - ******************************************************************************/ -#ifdef HAVE_PKCS7 - -#ifdef OPENSSL_ALL -PKCS7* wolfSSL_PKCS7_new(void) -{ - WOLFSSL_PKCS7* pkcs7; - int ret = 0; - - pkcs7 = (WOLFSSL_PKCS7*)XMALLOC(sizeof(WOLFSSL_PKCS7), NULL, - DYNAMIC_TYPE_PKCS7); - if (pkcs7 != NULL) { - XMEMSET(pkcs7, 0, sizeof(WOLFSSL_PKCS7)); - ret = wc_PKCS7_Init(&pkcs7->pkcs7, NULL, INVALID_DEVID); - } - - if (ret != 0 && pkcs7 != NULL) { - XFREE(pkcs7, NULL, DYNAMIC_TYPE_PKCS7); - pkcs7 = NULL; - } - - return (PKCS7*)pkcs7; -} - -/****************************************************************************** -* wolfSSL_PKCS7_SIGNED_new - allocates PKCS7 and initialize it for a signed data -* -* RETURNS: -* returns pointer to the PKCS7 structure on success, otherwise returns NULL -*/ -PKCS7_SIGNED* wolfSSL_PKCS7_SIGNED_new(void) -{ - byte signedData[]= { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02}; - PKCS7* pkcs7 = NULL; - - if ((pkcs7 = wolfSSL_PKCS7_new()) == NULL) - return NULL; - pkcs7->contentOID = SIGNED_DATA; - if ((wc_PKCS7_SetContentType(pkcs7, signedData, sizeof(signedData))) < 0) { - if (pkcs7) { - wolfSSL_PKCS7_free(pkcs7); - return NULL; - } - } - return pkcs7; -} - -void wolfSSL_PKCS7_free(PKCS7* pkcs7) -{ - WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; - - if (p7 != NULL) { - if (p7->data != NULL) - XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7); - wc_PKCS7_Free(&p7->pkcs7); - if (p7->certs) - wolfSSL_sk_pop_free(p7->certs, NULL); - XFREE(p7, NULL, DYNAMIC_TYPE_PKCS7); - } -} - -void wolfSSL_PKCS7_SIGNED_free(PKCS7_SIGNED* p7) -{ - wolfSSL_PKCS7_free(p7); - return; -} - -/** - * Convert DER/ASN.1 encoded signedData structure to internal PKCS7 - * structure. Note, does not support detached content. - * - * p7 - pointer to set to address of newly created PKCS7 structure on return - * in - pointer to pointer of DER/ASN.1 data - * len - length of input data, bytes - * - * Returns newly allocated and populated PKCS7 structure or NULL on error. - */ -PKCS7* wolfSSL_d2i_PKCS7(PKCS7** p7, const unsigned char** in, int len) -{ - return wolfSSL_d2i_PKCS7_ex(p7, in, len, NULL, 0); -} - -/* This internal function is only decoding and setting up the PKCS7 struct. It -* does not verify the PKCS7 signature. -* -* RETURNS: -* returns pointer to a PKCS7 structure on success, otherwise returns NULL -*/ -static PKCS7* wolfSSL_d2i_PKCS7_only(PKCS7** p7, const unsigned char** in, - int len, byte* content, word32 contentSz) -{ - WOLFSSL_PKCS7* pkcs7 = NULL; - - WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_ex"); - - if (in == NULL || *in == NULL || len < 0) - return NULL; - - if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL) - return NULL; - - pkcs7->len = len; - pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7); - if (pkcs7->data == NULL) { - wolfSSL_PKCS7_free((PKCS7*)pkcs7); - return NULL; - } - XMEMCPY(pkcs7->data, *in, pkcs7->len); - - if (content != NULL) { - pkcs7->pkcs7.content = content; - pkcs7->pkcs7.contentSz = contentSz; - } - - if (p7 != NULL) - *p7 = (PKCS7*)pkcs7; - *in += pkcs7->len; - return (PKCS7*)pkcs7; -} - - -/***************************************************************************** -* wolfSSL_d2i_PKCS7_ex - Converts the given unsigned char buffer of size len -* into a PKCS7 object. Optionally, accepts a byte buffer of content which -* is stored as the PKCS7 object's content, to support detached signatures. -* @param content The content which is signed, in case the signature is -* detached. Ignored if NULL. -* @param contentSz The size of the passed in content. -* -* RETURNS: -* returns pointer to a PKCS7 structure on success, otherwise returns NULL -*/ -PKCS7* wolfSSL_d2i_PKCS7_ex(PKCS7** p7, const unsigned char** in, int len, - byte* content, word32 contentSz) -{ - WOLFSSL_PKCS7* pkcs7 = NULL; - - WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_ex"); - - if (in == NULL || *in == NULL || len < 0) - return NULL; - - pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_d2i_PKCS7_only(p7, in, len, content, - contentSz); - if (pkcs7 != NULL) { - if (wc_PKCS7_VerifySignedData(&pkcs7->pkcs7, pkcs7->data, pkcs7->len) - != 0) { - WOLFSSL_MSG("wc_PKCS7_VerifySignedData failed"); - wolfSSL_PKCS7_free((PKCS7*)pkcs7); - if (p7 != NULL) { - *p7 = NULL; - } - return NULL; - } - } - - return (PKCS7*)pkcs7; -} - - -/** - * This API was added as a helper function for libest. It - * extracts a stack of certificates from the pkcs7 object. - * @param pkcs7 PKCS7 parameter object - * @return WOLFSSL_STACK_OF(WOLFSSL_X509)* - */ -WOLFSSL_STACK* wolfSSL_PKCS7_to_stack(PKCS7* pkcs7) -{ - int i; - WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; - WOLF_STACK_OF(WOLFSSL_X509)* ret = NULL; - - WOLFSSL_ENTER("wolfSSL_PKCS7_to_stack"); - - if (!p7) { - WOLFSSL_MSG("Bad parameter"); - return NULL; - } - - if (p7->certs) - return p7->certs; - - for (i = 0; i < MAX_PKCS7_CERTS && p7->pkcs7.cert[i]; i++) { - WOLFSSL_X509* x509 = wolfSSL_X509_d2i_ex(NULL, p7->pkcs7.cert[i], - p7->pkcs7.certSz[i], pkcs7->heap); - if (!ret) - ret = wolfSSL_sk_X509_new_null(); - if (x509) { - if (wolfSSL_sk_X509_push(ret, x509) != WOLFSSL_SUCCESS) { - wolfSSL_X509_free(x509); - WOLFSSL_MSG("wolfSSL_sk_X509_push error"); - goto error; - } - } - else { - WOLFSSL_MSG("wolfSSL_X509_d2i error"); - goto error; - } - } - - /* Save stack to free later */ - if (p7->certs) - wolfSSL_sk_pop_free(p7->certs, NULL); - p7->certs = ret; - - return ret; -error: - if (ret) { - wolfSSL_sk_pop_free(ret, NULL); - } - return NULL; -} - -/** - * Return stack of signers contained in PKCS7 cert. - * Notes: - * - Currently only PKCS#7 messages with a single signer cert is supported. - * - Returned WOLFSSL_STACK must be freed by caller. - * - * pkcs7 - PKCS7 struct to retrieve signer certs from. - * certs - currently unused - * flags - flags to control function behavior. - * - * Return WOLFSSL_STACK of signers on success, NULL on error. - */ -WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs, - int flags) -{ - WOLFSSL_X509* x509 = NULL; - WOLFSSL_STACK* signers = NULL; - WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; - - if (p7 == NULL) - return NULL; - - /* Only PKCS#7 messages with a single cert that is the verifying certificate - * is supported. - */ - if (flags & PKCS7_NOINTERN) { - WOLFSSL_MSG("PKCS7_NOINTERN flag not supported"); - return NULL; - } - - signers = wolfSSL_sk_X509_new_null(); - if (signers == NULL) - return NULL; - - if (wolfSSL_d2i_X509(&x509, (const byte**)&p7->pkcs7.singleCert, - p7->pkcs7.singleCertSz) == NULL) { - wolfSSL_sk_X509_pop_free(signers, NULL); - return NULL; - } - - if (wolfSSL_sk_X509_push(signers, x509) != WOLFSSL_SUCCESS) { - wolfSSL_sk_X509_pop_free(signers, NULL); - return NULL; - } - - (void)certs; - - return signers; -} - -#ifndef NO_BIO - -PKCS7* wolfSSL_d2i_PKCS7_bio(WOLFSSL_BIO* bio, PKCS7** p7) -{ - WOLFSSL_PKCS7* pkcs7; - int ret; - - WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_bio"); - - if (bio == NULL) - return NULL; - - if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL) - return NULL; - - pkcs7->len = wolfSSL_BIO_get_len(bio); - pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7); - if (pkcs7->data == NULL) { - wolfSSL_PKCS7_free((PKCS7*)pkcs7); - return NULL; - } - - if ((ret = wolfSSL_BIO_read(bio, pkcs7->data, pkcs7->len)) <= 0) { - wolfSSL_PKCS7_free((PKCS7*)pkcs7); - return NULL; - } - /* pkcs7->len may change if using b64 for example */ - pkcs7->len = ret; - - if (wc_PKCS7_VerifySignedData(&pkcs7->pkcs7, pkcs7->data, pkcs7->len) - != 0) { - WOLFSSL_MSG("wc_PKCS7_VerifySignedData failed"); - wolfSSL_PKCS7_free((PKCS7*)pkcs7); - return NULL; - } - - if (p7 != NULL) - *p7 = (PKCS7*)pkcs7; - return (PKCS7*)pkcs7; -} - -int wolfSSL_i2d_PKCS7(PKCS7 *p7, unsigned char **out) -{ - byte* output = NULL; - int localBuf = 0; - int len; - WC_RNG rng; - int ret = WOLFSSL_FAILURE; - WOLFSSL_ENTER("wolfSSL_i2d_PKCS7"); - - if (!out || !p7) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - if (!p7->rng) { - if (wc_InitRng(&rng) != 0) { - WOLFSSL_MSG("wc_InitRng error"); - return WOLFSSL_FAILURE; - } - p7->rng = &rng; /* cppcheck-suppress autoVariables - */ - } - - if ((len = wc_PKCS7_EncodeSignedData(p7, NULL, 0)) < 0) { - WOLFSSL_MSG("wc_PKCS7_EncodeSignedData error"); - goto cleanup; - } - - if (*out == NULL) { - output = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (!output) { - WOLFSSL_MSG("malloc error"); - goto cleanup; - } - localBuf = 1; - } - else { - output = *out; - } - - if ((len = wc_PKCS7_EncodeSignedData(p7, output, len)) < 0) { - WOLFSSL_MSG("wc_PKCS7_EncodeSignedData error"); - goto cleanup; - } - - ret = len; -cleanup: - if (p7->rng == &rng) { - wc_FreeRng(&rng); - p7->rng = NULL; - } - if (ret == WOLFSSL_FAILURE && localBuf && output) - XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (ret != WOLFSSL_FAILURE) - *out = output; - return ret; -} - -int wolfSSL_i2d_PKCS7_bio(WOLFSSL_BIO *bio, PKCS7 *p7) -{ - byte* output = NULL; - int len; - int ret = WOLFSSL_FAILURE; - WOLFSSL_ENTER("wolfSSL_i2d_PKCS7_bio"); - - if (!bio || !p7) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - if ((len = wolfSSL_i2d_PKCS7(p7, &output)) == WOLFSSL_FAILURE) { - WOLFSSL_MSG("wolfSSL_i2d_PKCS7 error"); - goto cleanup; - } - - if (wolfSSL_BIO_write(bio, output, len) <= 0) { - WOLFSSL_MSG("wolfSSL_BIO_write error"); - goto cleanup; - } - - ret = WOLFSSL_SUCCESS; -cleanup: - if (output) - XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return ret; -} - -/** - * Creates and returns a PKCS7 signedData structure. - * - * Inner content type is set to DATA to match OpenSSL behavior. - * - * signer - certificate to sign bundle with - * pkey - private key matching signer - * certs - optional additional set of certificates to include - * in - input data to be signed - * flags - optional set of flags to control sign behavior - * - * PKCS7_BINARY - Do not translate input data to MIME canonical - * format (\r\n line endings), thus preventing corruption of - * binary content. - * PKCS7_TEXT - Prepend MIME headers for text/plain to content. - * PKCS7_DETACHED - Set signature detached, omit content from output bundle. - * PKCS7_STREAM - initialize PKCS7 struct for signing, do not read data. - * - * Flags not currently supported: - * PKCS7_NOCERTS - Do not include the signer cert in the output bundle. - * PKCS7_PARTIAL - Allow for PKCS7_sign() to be only partially set up, - * then signers etc to be added separately before - * calling PKCS7_final(). - * - * Returns valid PKCS7 structure pointer, or NULL if an error occurred. - */ -PKCS7* wolfSSL_PKCS7_sign(WOLFSSL_X509* signer, WOLFSSL_EVP_PKEY* pkey, - WOLFSSL_STACK* certs, WOLFSSL_BIO* in, int flags) -{ - int err = 0; - WOLFSSL_PKCS7* p7 = NULL; - WOLFSSL_STACK* cert = certs; - - WOLFSSL_ENTER("wolfSSL_PKCS7_sign"); - - if (flags & PKCS7_NOCERTS) { - WOLFSSL_MSG("PKCS7_NOCERTS flag not yet supported"); - err = 1; - } - - if (flags & PKCS7_PARTIAL) { - WOLFSSL_MSG("PKCS7_PARTIAL flag not yet supported"); - err = 1; - } - - if ((err == 0) && (signer == NULL || signer->derCert == NULL || - signer->derCert->length == 0)) { - WOLFSSL_MSG("Bad function arg, signer is NULL or incomplete"); - err = 1; - } - - if ((err == 0) && (pkey == NULL || pkey->pkey.ptr == NULL || - pkey->pkey_sz <= 0)) { - WOLFSSL_MSG("Bad function arg, pkey is NULL or incomplete"); - err = 1; - } - - if ((err == 0) && (in == NULL) && !(flags & PKCS7_STREAM)) { - WOLFSSL_MSG("input data required unless PKCS7_STREAM used"); - err = 1; - } - - if ((err == 0) && ((p7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL)) { - WOLFSSL_MSG("Error allocating new WOLFSSL_PKCS7"); - err = 1; - } - - /* load signer certificate */ - if (err == 0) { - if (wc_PKCS7_InitWithCert(&p7->pkcs7, signer->derCert->buffer, - signer->derCert->length) != 0) { - WOLFSSL_MSG("Failed to load signer certificate"); - err = 1; - } - } - - /* set signer private key, data types, defaults */ - if (err == 0) { - p7->pkcs7.privateKey = (byte*)pkey->pkey.ptr; - p7->pkcs7.privateKeySz = pkey->pkey_sz; - p7->pkcs7.contentOID = DATA; /* inner content default is DATA */ - p7->pkcs7.hashOID = SHA256h; /* default to SHA-256 hash type */ - p7->type = SIGNED_DATA; /* PKCS7_final switches on type */ - } - - /* add additional chain certs if provided */ - while (cert && (err == 0)) { - if (cert->data.x509 != NULL && cert->data.x509->derCert != NULL) { - if (wc_PKCS7_AddCertificate(&p7->pkcs7, - cert->data.x509->derCert->buffer, - cert->data.x509->derCert->length) != 0) { - WOLFSSL_MSG("Error in wc_PKCS7_AddCertificate"); - err = 1; - } - } - cert = cert->next; - } - - if ((err == 0) && (flags & PKCS7_DETACHED)) { - if (wc_PKCS7_SetDetached(&p7->pkcs7, 1) != 0) { - WOLFSSL_MSG("Failed to set signature detached"); - err = 1; - } - } - - if ((err == 0) && (flags & PKCS7_STREAM)) { - /* if streaming, return before finalizing */ - return (PKCS7*)p7; - } - - if ((err == 0) && (wolfSSL_PKCS7_final((PKCS7*)p7, in, flags) != 1)) { - WOLFSSL_MSG("Error calling wolfSSL_PKCS7_final"); - err = 1; - } - - if ((err != 0) && (p7 != NULL)) { - wolfSSL_PKCS7_free((PKCS7*)p7); - p7 = NULL; - } - - return (PKCS7*)p7; -} - -#ifdef HAVE_SMIME - -#ifndef MAX_MIME_LINE_LEN - #define MAX_MIME_LINE_LEN 1024 -#endif - -/** - * Copy input BIO to output BIO, but convert all line endings to CRLF (\r\n), - * used by PKCS7_final(). - * - * in - input WOLFSSL_BIO to be converted - * out - output WOLFSSL_BIO to hold copy of in, with line endings adjusted - * - * Return 0 on success, negative on error - */ -static int wolfSSL_BIO_to_MIME_crlf(WOLFSSL_BIO* in, WOLFSSL_BIO* out) -{ - int ret = 0; - int lineLen = 0; - word32 canonLineLen = 0; - char* canonLine = NULL; -#ifdef WOLFSSL_SMALL_STACK - char* line = NULL; -#else - char line[MAX_MIME_LINE_LEN]; -#endif - - if (in == NULL || out == NULL) { - return BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - line = (char*)XMALLOC(MAX_MIME_LINE_LEN, in->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (line == NULL) { - return MEMORY_E; - } -#endif - XMEMSET(line, 0, MAX_MIME_LINE_LEN); - - while ((lineLen = wolfSSL_BIO_gets(in, line, MAX_MIME_LINE_LEN)) > 0) { - - if (line[lineLen - 1] == '\r' || line[lineLen - 1] == '\n') { - canonLineLen = (word32)lineLen; - if ((canonLine = wc_MIME_single_canonicalize( - line, &canonLineLen)) == NULL) { - ret = -1; - break; - } - - /* remove trailing null */ - if (canonLineLen >= 1 && canonLine[canonLineLen-1] == '\0') { - canonLineLen--; - } - - if (wolfSSL_BIO_write(out, canonLine, (int)canonLineLen) < 0) { - ret = -1; - break; - } - XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); - canonLine = NULL; - } - else { - /* no line ending in current line, write direct to out */ - if (wolfSSL_BIO_write(out, line, lineLen) < 0) { - ret = -1; - break; - } - } - } - - if (canonLine != NULL) { - XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); - } -#ifdef WOLFSSL_SMALL_STACK - XFREE(line, in->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return ret; -} - -#endif /* HAVE_SMIME */ - -/* Used by both PKCS7_final() and PKCS7_verify() */ -static const char contTypeText[] = "Content-Type: text/plain\r\n\r\n"; - -/** - * Finalize PKCS7 structure, currently supports signedData only. - * - * Does not generate final bundle (ie: signedData), but finalizes - * the PKCS7 structure in preparation for a output function to be called next. - * - * pkcs7 - initialized PKCS7 structure, populated with signer, etc - * in - input data - * flags - flags to control PKCS7 behavior. Other flags except those noted - * below are ignored: - * - * PKCS7_BINARY - Do not translate input data to MIME canonical - * format (\r\n line endings), thus preventing corruption of - * binary content. - * PKCS7_TEXT - Prepend MIME headers for text/plain to content. - * - * Returns 1 on success, 0 on error - */ -int wolfSSL_PKCS7_final(PKCS7* pkcs7, WOLFSSL_BIO* in, int flags) -{ - int ret = 1; - int memSz = 0; - unsigned char* mem = NULL; - WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; - WOLFSSL_BIO* data = NULL; - - WOLFSSL_ENTER("wolfSSL_PKCS7_final"); - - if (p7 == NULL || in == NULL) { - WOLFSSL_MSG("Bad input args to PKCS7_final"); - ret = 0; - } - - if (ret == 1) { - if ((data = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())) == NULL) { - WOLFSSL_MSG("Error in wolfSSL_BIO_new"); - ret = 0; - } - } - - /* prepend Content-Type header if PKCS7_TEXT */ - if ((ret == 1) && (flags & PKCS7_TEXT)) { - if (wolfSSL_BIO_write(data, contTypeText, - (int)XSTR_SIZEOF(contTypeText)) < 0) { - WOLFSSL_MSG("Error prepending Content-Type header"); - ret = 0; - } - } - - /* convert line endings to CRLF if !PKCS7_BINARY */ - if (ret == 1) { - if (flags & PKCS7_BINARY) { - - /* no CRLF conversion, direct copy content */ - if ((memSz = wolfSSL_BIO_get_len(in)) <= 0) { - ret = 0; - } - if (ret == 1) { - mem = (unsigned char*)XMALLOC(memSz, in->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (mem == NULL) { - WOLFSSL_MSG("Failed to allocate memory for input data"); - ret = 0; - } - } - - if (ret == 1) { - if (wolfSSL_BIO_read(in, mem, memSz) != memSz) { - WOLFSSL_MSG("Error reading from input BIO"); - ret = 0; - } - else if (wolfSSL_BIO_write(data, mem, memSz) < 0) { - ret = 0; - } - } - - if (mem != NULL) { - XFREE(mem, in->heap, DYNAMIC_TYPE_TMP_BUFFER); - } - } - else { - #ifdef HAVE_SMIME - /* convert content line endings to CRLF */ - if (wolfSSL_BIO_to_MIME_crlf(in, data) != 0) { - WOLFSSL_MSG("Error converting line endings to CRLF"); - ret = 0; - } - else { - p7->pkcs7.contentCRLF = 1; - } - #else - WOLFSSL_MSG("Without PKCS7_BINARY requires wolfSSL to be built " - "with HAVE_SMIME"); - ret = 0; - #endif - } - } - - if ((ret == 1) && ((memSz = wolfSSL_BIO_get_mem_data(data, &mem)) < 0)) { - WOLFSSL_MSG("Error in wolfSSL_BIO_get_mem_data"); - ret = 0; - } - - if (ret == 1) { - if (p7->data != NULL) { - XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7); - } - p7->data = (byte*)XMALLOC(memSz, NULL, DYNAMIC_TYPE_PKCS7); - if (p7->data == NULL) { - ret = 0; - } - else { - XMEMCPY(p7->data, mem, memSz); - p7->len = memSz; - } - } - - if (ret == 1) { - p7->pkcs7.content = p7->data; - p7->pkcs7.contentSz = p7->len; - } - - if (data != NULL) { - wolfSSL_BIO_free(data); - } - - return ret; -} - -int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs, - WOLFSSL_X509_STORE* store, WOLFSSL_BIO* in, WOLFSSL_BIO* out, int flags) -{ - int i, ret = 0; - unsigned char* mem = NULL; - int memSz = 0; - WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; - int contTypeLen; - WOLFSSL_X509* signer = NULL; - WOLFSSL_STACK* signers = NULL; - - WOLFSSL_ENTER("wolfSSL_PKCS7_verify"); - - if (pkcs7 == NULL) - return WOLFSSL_FAILURE; - - if (in != NULL) { - if ((memSz = wolfSSL_BIO_get_mem_data(in, &mem)) < 0) - return WOLFSSL_FAILURE; - - p7->pkcs7.content = mem; - p7->pkcs7.contentSz = memSz; - } - - /* certs is the list of certificates to find the cert with issuer/serial. */ - (void)certs; - /* store is the certificate store to use to verify signer certificate - * associated with the signers. - */ - (void)store; - - ret = wc_PKCS7_VerifySignedData(&p7->pkcs7, p7->data, p7->len); - if (ret != 0) - return WOLFSSL_FAILURE; - - if ((flags & PKCS7_NOVERIFY) != PKCS7_NOVERIFY) { - /* Verify signer certificates */ - if (store == NULL || store->cm == NULL) { - WOLFSSL_MSG("No store or store certs, but PKCS7_NOVERIFY not set"); - return WOLFSSL_FAILURE; - } - - signers = wolfSSL_PKCS7_get0_signers(pkcs7, certs, flags); - if (signers == NULL) { - WOLFSSL_MSG("No signers found to verify"); - return WOLFSSL_FAILURE; - } - for (i = 0; i < wolfSSL_sk_X509_num(signers); i++) { - signer = wolfSSL_sk_X509_value(signers, i); - - if (wolfSSL_CertManagerVerifyBuffer(store->cm, - signer->derCert->buffer, - signer->derCert->length, - WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Failed to verify signer certificate"); - wolfSSL_sk_X509_pop_free(signers, NULL); - return WOLFSSL_FAILURE; - } - } - wolfSSL_sk_X509_pop_free(signers, NULL); - } - - if (flags & PKCS7_TEXT) { - /* strip MIME header for text/plain, otherwise error */ - contTypeLen = XSTR_SIZEOF(contTypeText); - if ((p7->pkcs7.contentSz < (word32)contTypeLen) || - (XMEMCMP(p7->pkcs7.content, contTypeText, contTypeLen) != 0)) { - WOLFSSL_MSG("Error PKCS7 Content-Type not found with PKCS7_TEXT"); - return WOLFSSL_FAILURE; - } - p7->pkcs7.content += contTypeLen; - p7->pkcs7.contentSz -= contTypeLen; - } - - if (out != NULL) { - wolfSSL_BIO_write(out, p7->pkcs7.content, p7->pkcs7.contentSz); - } - - WOLFSSL_LEAVE("wolfSSL_PKCS7_verify", WOLFSSL_SUCCESS); - - return WOLFSSL_SUCCESS; -} - -/** - * This API was added as a helper function for libest. It - * encodes a stack of certificates to pkcs7 format. - * @param pkcs7 PKCS7 parameter object - * @param certs WOLFSSL_STACK_OF(WOLFSSL_X509)* - * @param out Output bio - * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure - */ -int wolfSSL_PKCS7_encode_certs(PKCS7* pkcs7, WOLFSSL_STACK* certs, - WOLFSSL_BIO* out) -{ - int ret; - WOLFSSL_PKCS7* p7; - WOLFSSL_ENTER("wolfSSL_PKCS7_encode_certs"); - - if (!pkcs7 || !certs || !out) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - p7 = (WOLFSSL_PKCS7*)pkcs7; - - /* take ownership of certs */ - p7->certs = certs; - /* TODO: takes ownership even on failure below but not on above failure. */ - - if (pkcs7->certList) { - WOLFSSL_MSG("wolfSSL_PKCS7_encode_certs called multiple times on same " - "struct"); - return WOLFSSL_FAILURE; - } - - if (certs) { - /* Save some of the values */ - int hashOID = pkcs7->hashOID; - byte version = pkcs7->version; - - if (!certs->data.x509 || !certs->data.x509->derCert) { - WOLFSSL_MSG("Missing cert"); - return WOLFSSL_FAILURE; - } - - if (wc_PKCS7_InitWithCert(pkcs7, certs->data.x509->derCert->buffer, - certs->data.x509->derCert->length) != 0) { - WOLFSSL_MSG("wc_PKCS7_InitWithCert error"); - return WOLFSSL_FAILURE; - } - certs = certs->next; - - pkcs7->hashOID = hashOID; - pkcs7->version = version; - } - - /* Add the certs to the PKCS7 struct */ - while (certs) { - if (!certs->data.x509 || !certs->data.x509->derCert) { - WOLFSSL_MSG("Missing cert"); - return WOLFSSL_FAILURE; - } - if (wc_PKCS7_AddCertificate(pkcs7, certs->data.x509->derCert->buffer, - certs->data.x509->derCert->length) != 0) { - WOLFSSL_MSG("wc_PKCS7_AddCertificate error"); - return WOLFSSL_FAILURE; - } - certs = certs->next; - } - - if (wc_PKCS7_SetSignerIdentifierType(pkcs7, DEGENERATE_SID) != 0) { - WOLFSSL_MSG("wc_PKCS7_SetSignerIdentifierType error"); - return WOLFSSL_FAILURE; - } - - ret = wolfSSL_i2d_PKCS7_bio(out, pkcs7); - - return ret; -} - -/****************************************************************************** -* wolfSSL_PEM_write_bio_PKCS7 - writes the PKCS7 data to BIO -* -* RETURNS: -* returns WOLFSSL_SUCCESS on success, otherwise returns WOLFSSL_FAILURE -*/ -int wolfSSL_PEM_write_bio_PKCS7(WOLFSSL_BIO* bio, PKCS7* p7) -{ -#ifdef WOLFSSL_SMALL_STACK - byte* outputHead; - byte* outputFoot; -#else - byte outputHead[2048]; - byte outputFoot[2048]; -#endif - word32 outputHeadSz = 2048; - word32 outputFootSz = 2048; - word32 outputSz = 0; - byte* output = NULL; - byte* pem = NULL; - int pemSz = -1; - enum wc_HashType hashType; - byte hashBuf[WC_MAX_DIGEST_SIZE]; - word32 hashSz = -1; - - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PKCS7"); - - if (bio == NULL || p7 == NULL) - return WOLFSSL_FAILURE; - -#ifdef WOLFSSL_SMALL_STACK - outputHead = (byte*)XMALLOC(outputHeadSz, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (outputHead == NULL) - return MEMORY_E; - - outputFoot = (byte*)XMALLOC(outputFootSz, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (outputFoot == NULL) - goto error; - -#endif - - XMEMSET(hashBuf, 0, WC_MAX_DIGEST_SIZE); - XMEMSET(outputHead, 0, outputHeadSz); - XMEMSET(outputFoot, 0, outputFootSz); - - hashType = wc_OidGetHash(p7->hashOID); - hashSz = wc_HashGetDigestSize(hashType); - if (hashSz > WC_MAX_DIGEST_SIZE) - goto error; - - /* only SIGNED_DATA is supported */ - switch (p7->contentOID) { - case SIGNED_DATA: - break; - default: - WOLFSSL_MSG("Unknown PKCS#7 Type"); - goto error; - }; - - if ((wc_PKCS7_EncodeSignedData_ex(p7, hashBuf, hashSz, - outputHead, &outputHeadSz, outputFoot, &outputFootSz)) != 0) - goto error; - - outputSz = outputHeadSz + p7->contentSz + outputFootSz; - output = (byte*)XMALLOC(outputSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - - if (!output) - goto error; - - XMEMSET(output, 0, outputSz); - outputSz = 0; - XMEMCPY(&output[outputSz], outputHead, outputHeadSz); - outputSz += outputHeadSz; - XMEMCPY(&output[outputSz], p7->content, p7->contentSz); - outputSz += p7->contentSz; - XMEMCPY(&output[outputSz], outputFoot, outputFootSz); - outputSz += outputFootSz; - - /* get PEM size */ - pemSz = wc_DerToPemEx(output, outputSz, NULL, 0, NULL, CERT_TYPE); - if (pemSz < 0) - goto error; - - pemSz++; /* for '\0'*/ - - /* create PEM buffer and convert from DER to PEM*/ - if ((pem = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER)) - == NULL) - goto error; - - XMEMSET(pem, 0, pemSz); - - if (wc_DerToPemEx(output, outputSz, pem, pemSz, NULL, CERT_TYPE) < 0) { - goto error; - } - if ((wolfSSL_BIO_write(bio, pem, pemSz) == pemSz)) { - XFREE(output, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(pem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); -#ifdef WOLFSSL_SMALL_STACK - XFREE(outputHead, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(outputFoot, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return WOLFSSL_SUCCESS; - } - -error: -#ifdef WOLFSSL_SMALL_STACK - if (outputHead) { - XFREE(outputHead, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - } - if (outputFoot) { - XFREE(outputFoot, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - } -#endif - if (output) { - XFREE(output, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - } - if (pem) { - XFREE(pem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - } - return WOLFSSL_FAILURE; -} - -#ifdef HAVE_SMIME -/***************************************************************************** -* wolfSSL_SMIME_read_PKCS7 - Reads the given S/MIME message and parses it into -* a PKCS7 object. In case of a multipart message, stores the signed data in -* bcont. -* -* RETURNS: -* returns pointer to a PKCS7 structure on success, otherwise returns NULL -*/ -PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, - WOLFSSL_BIO** bcont) -{ - MimeHdr* allHdrs = NULL; - MimeHdr* curHdr = NULL; - MimeParam* curParam = NULL; - int inLen = 0; - byte* bcontMem = NULL; - int bcontMemSz = 0; - int sectionLen = 0; - int ret = -1; - char* section = NULL; - char* canonLine = NULL; - char* canonSection = NULL; - PKCS7* pkcs7 = NULL; - word32 outLen = 0; - word32 canonLineLen = 0; - byte* out = NULL; - byte* outHead = NULL; - - int canonPos = 0; - int lineLen = 0; - int remainLen = 0; - byte isEnd = 0; - size_t canonSize = 0; - size_t boundLen = 0; - char* boundary = NULL; - - static const char kContType[] = "Content-Type"; - static const char kCTE[] = "Content-Transfer-Encoding"; - static const char kMultSigned[] = "multipart/signed"; - static const char kAppPkcsSign[] = "application/pkcs7-signature"; - static const char kAppXPkcsSign[] = "application/x-pkcs7-signature"; - static const char kAppPkcs7Mime[] = "application/pkcs7-mime"; - static const char kAppXPkcs7Mime[] = "application/x-pkcs7-mime"; - - WOLFSSL_ENTER("wolfSSL_SMIME_read_PKCS7"); - - if (in == NULL || bcont == NULL) { - goto error; - } - inLen = wolfSSL_BIO_get_len(in); - if (inLen <= 0) { - goto error; - } - remainLen = wolfSSL_BIO_get_len(in); - if (remainLen <= 0) { - goto error; - } - - section = (char*)XMALLOC(remainLen+1, NULL, DYNAMIC_TYPE_PKCS7); - if (section == NULL) { - goto error; - } - lineLen = wolfSSL_BIO_gets(in, section, remainLen); - if (lineLen <= 0) { - goto error; - } - while (isEnd == 0 && remainLen > 0) { - sectionLen += lineLen; - remainLen -= lineLen; - lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], remainLen); - if (lineLen <= 0) { - goto error; - } - /* Line with just newline signals end of headers. */ - if ((lineLen==2 && !XSTRNCMP(§ion[sectionLen], - "\r\n", 2)) || - (lineLen==1 && (section[sectionLen] == '\r' || - section[sectionLen] == '\n'))) { - isEnd = 1; - } - } - section[sectionLen] = '\0'; - ret = wc_MIME_parse_headers(section, sectionLen, &allHdrs); - if (ret < 0) { - WOLFSSL_MSG("Parsing MIME headers failed."); - goto error; - } - isEnd = 0; - section[0] = '\0'; - sectionLen = 0; - - curHdr = wc_MIME_find_header_name(kContType, allHdrs); - if (curHdr && !XSTRNCMP(curHdr->body, kMultSigned, - XSTR_SIZEOF(kMultSigned))) { - curParam = wc_MIME_find_param_attr("protocol", curHdr->params); - if (curParam && (!XSTRNCMP(curParam->value, kAppPkcsSign, - XSTR_SIZEOF(kAppPkcsSign)) || - !XSTRNCMP(curParam->value, kAppXPkcsSign, - XSTR_SIZEOF(kAppXPkcsSign)))) { - curParam = wc_MIME_find_param_attr("boundary", curHdr->params); - if (curParam == NULL) { - goto error; - } - - boundLen = XSTRLEN(curParam->value) + 2; - boundary = (char*)XMALLOC(boundLen+1, NULL, DYNAMIC_TYPE_PKCS7); - if (boundary == NULL) { - goto error; - } - XMEMSET(boundary, 0, (word32)(boundLen+1)); - boundary[0] = boundary[1] = '-'; - XSTRNCPY(&boundary[2], curParam->value, boundLen-2); - - /* Parse up to first boundary, ignore everything here. */ - lineLen = wolfSSL_BIO_gets(in, section, remainLen); - if (lineLen <= 0) { - goto error; - } - while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && - remainLen > 0) { - sectionLen += lineLen; - remainLen -= lineLen; - lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], - remainLen); - if (lineLen <= 0) { - goto error; - } - } - - section[0] = '\0'; - sectionLen = 0; - canonSize = remainLen + 1; - canonSection = (char*)XMALLOC(canonSize, NULL, - DYNAMIC_TYPE_PKCS7); - if (canonSection == NULL) { - goto error; - } - - lineLen = wolfSSL_BIO_gets(in, section, remainLen); - if (lineLen < 0) { - goto error; - } - while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && - remainLen > 0) { - canonLineLen = lineLen; - canonLine = wc_MIME_single_canonicalize(§ion[sectionLen], - &canonLineLen); - if (canonLine == NULL) { - goto error; - } - /* If line endings were added, the initial length may be - * exceeded. */ - if ((canonPos + canonLineLen) >= canonSize) { - canonSize = canonPos + canonLineLen; - canonSection = (char*)XREALLOC(canonSection, canonSize, - NULL, DYNAMIC_TYPE_PKCS7); - if (canonSection == NULL) { - goto error; - } - } - XMEMCPY(&canonSection[canonPos], canonLine, - (int)canonLineLen - 1); - canonPos += canonLineLen - 1; - XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); - canonLine = NULL; - - sectionLen += lineLen; - remainLen -= lineLen; - - lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], - remainLen); - if (lineLen <= 0) { - goto error; - } - } - - if (canonPos > 0) { - canonPos--; - } - - /* Strip the final trailing newline. Support \r, \n or \r\n. */ - if (canonSection[canonPos] == '\n') { - if (canonPos > 0) { - canonPos--; - } - } - - if (canonSection[canonPos] == '\r') { - if (canonPos > 0) { - canonPos--; - } - } - - canonSection[canonPos+1] = '\0'; - - *bcont = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); - ret = wolfSSL_BIO_write(*bcont, canonSection, - canonPos + 1); - if (ret != (canonPos+1)) { - goto error; - } - if ((bcontMemSz = wolfSSL_BIO_get_mem_data(*bcont, &bcontMem)) - < 0) { - goto error; - } - XFREE(canonSection, NULL, DYNAMIC_TYPE_PKCS7); - canonSection = NULL; - - wc_MIME_free_hdrs(allHdrs); - allHdrs = NULL; - section[0] = '\0'; - sectionLen = 0; - lineLen = wolfSSL_BIO_gets(in, section, remainLen); - if (lineLen <= 0) { - goto error; - } - while (isEnd == 0 && remainLen > 0) { - sectionLen += lineLen; - remainLen -= lineLen; - lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], - remainLen); - if (lineLen <= 0) { - goto error; - } - /* Line with just newline signals end of headers. */ - if ((lineLen==2 && !XSTRNCMP(§ion[sectionLen], - "\r\n", 2)) || - (lineLen==1 && (section[sectionLen] == '\r' || - section[sectionLen] == '\n'))) { - isEnd = 1; - } - } - section[sectionLen] = '\0'; - ret = wc_MIME_parse_headers(section, sectionLen, &allHdrs); - if (ret < 0) { - WOLFSSL_MSG("Parsing MIME headers failed."); - goto error; - } - curHdr = wc_MIME_find_header_name(kContType, allHdrs); - if (curHdr == NULL || (XSTRNCMP(curHdr->body, kAppPkcsSign, - XSTR_SIZEOF(kAppPkcsSign)) && - XSTRNCMP(curHdr->body, kAppXPkcsSign, - XSTR_SIZEOF(kAppXPkcsSign)))) { - WOLFSSL_MSG("S/MIME headers not found inside " - "multipart message.\n"); - goto error; - } - - section[0] = '\0'; - sectionLen = 0; - lineLen = wolfSSL_BIO_gets(in, section, remainLen); - while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && - remainLen > 0) { - sectionLen += lineLen; - remainLen -= lineLen; - lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], - remainLen); - if (lineLen <= 0) { - goto error; - } - } - - XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7); - boundary = NULL; - } - } - else if (curHdr && (!XSTRNCMP(curHdr->body, kAppPkcs7Mime, - XSTR_SIZEOF(kAppPkcs7Mime)) || - !XSTRNCMP(curHdr->body, kAppXPkcs7Mime, - XSTR_SIZEOF(kAppXPkcs7Mime)))) { - sectionLen = wolfSSL_BIO_get_len(in); - if (sectionLen <= 0) { - goto error; - } - ret = wolfSSL_BIO_read(in, section, sectionLen); - if (ret < 0 || ret != sectionLen) { - WOLFSSL_MSG("Error reading input BIO."); - goto error; - } - } - else { - WOLFSSL_MSG("S/MIME headers not found."); - goto error; - } - - curHdr = wc_MIME_find_header_name(kCTE, allHdrs); - if (curHdr == NULL) { - WOLFSSL_MSG("Content-Transfer-Encoding header not found, " - "assuming base64 encoding."); - } - else if (XSTRNCMP(curHdr->body, "base64", XSTRLEN("base64"))) { - WOLFSSL_MSG("S/MIME encodings other than base64 are not " - "currently supported.\n"); - goto error; - } - - if (section == NULL || sectionLen <= 0) { - goto error; - } - outLen = ((sectionLen*3+3)/4)+1; - out = (byte*)XMALLOC(outLen*sizeof(byte), NULL, DYNAMIC_TYPE_PKCS7); - outHead = out; - if (outHead == NULL) { - goto error; - } - /* Strip trailing newlines. */ - while ((sectionLen > 0) && - (section[sectionLen-1] == '\r' || section[sectionLen-1] == '\n')) { - sectionLen--; - } - section[sectionLen] = '\0'; - ret = Base64_Decode((const byte*)section, sectionLen, out, &outLen); - if (ret < 0) { - WOLFSSL_MSG("Error base64 decoding S/MIME message."); - goto error; - } - pkcs7 = wolfSSL_d2i_PKCS7_only(NULL, (const unsigned char**)&out, outLen, - bcontMem, bcontMemSz); - - wc_MIME_free_hdrs(allHdrs); - XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7); - XFREE(section, NULL, DYNAMIC_TYPE_PKCS7); - - return pkcs7; - -error: - wc_MIME_free_hdrs(allHdrs); - XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7); - XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7); - XFREE(section, NULL, DYNAMIC_TYPE_PKCS7); - if (canonSection != NULL) - XFREE(canonSection, NULL, DYNAMIC_TYPE_PKCS7); - if (canonLine != NULL) - XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); - if (bcont) { - wolfSSL_BIO_free(*bcont); - *bcont = NULL; /* reset 'bcount' pointer to NULL on failure */ - } - - return NULL; -} - -/* Convert hash algo OID (from Hash_Sum in asn.h) to SMIME string equivalent. - * Returns hash algorithm string or "unknown" if not found */ -static const char* wolfSSL_SMIME_HashOIDToString(int hashOID) -{ - switch (hashOID) { - case MD5h: - return "md5"; - case SHAh: - return "sha1"; - case SHA224h: - return "sha-224"; - case SHA256h: - return "sha-256"; - case SHA384h: - return "sha-384"; - case SHA512h: - return "sha-512"; - case SHA3_224h: - return "sha3-224"; - case SHA3_384h: - return "sha3-384"; - case SHA3_512h: - return "sha3-512"; - default: - break; - } - - return "unknown"; -} - -/* Convert PKCS#7 type (from PKCS7_TYPES in pkcs7.h) to SMIME string. - * RFC2633 only defines signed-data, enveloped-data, certs-only. - * Returns string on success, NULL on unknown type. */ -static const char* wolfSSL_SMIME_PKCS7TypeToString(int type) -{ - switch (type) { - case SIGNED_DATA: - return "signed-data"; - case ENVELOPED_DATA: - return "enveloped-data"; - default: - break; - } - - return NULL; -} - -/** - * Convert PKCS7 structure to SMIME format, adding necessary headers. - * - * Handles generation of PKCS7 bundle (ie: signedData). PKCS7 structure - * should be set up beforehand with PKCS7_sign/final/etc. Output is always - * Base64 encoded. - * - * out - output BIO for SMIME formatted data to be placed - * pkcs7 - input PKCS7 structure, initialized and set up - * in - input content to be encoded into PKCS7 - * flags - flags to control behavior of PKCS7 generation - * - * Returns 1 on success, 0 or negative on failure - */ -int wolfSSL_SMIME_write_PKCS7(WOLFSSL_BIO* out, PKCS7* pkcs7, WOLFSSL_BIO* in, - int flags) -{ - int i; - int ret = 1; - WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; - byte* p7out = NULL; - int len = 0; - - char boundary[33]; /* 32 chars + \0 */ - byte* sigBase64 = NULL; - word32 sigBase64Len = 0; - const char* p7TypeString = NULL; - - static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - if (out == NULL || p7 == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return 0; - } - - if (in != NULL && (p7->pkcs7.content == NULL || p7->pkcs7.contentSz == 0 || - p7->pkcs7.contentCRLF == 0)) { - /* store and adjust content line endings for CRLF if needed */ - if (wolfSSL_PKCS7_final((PKCS7*)p7, in, flags) != 1) { - ret = 0; - } - } - - if (ret > 0) { - /* Generate signedData bundle, DER in output (dynamic) */ - if ((len = wolfSSL_i2d_PKCS7((PKCS7*)p7, &p7out)) == WOLFSSL_FAILURE) { - WOLFSSL_MSG("Error in wolfSSL_i2d_PKCS7"); - ret = 0; - } - } - - /* Base64 encode signedData bundle */ - if (ret > 0) { - if (Base64_Encode(p7out, len, NULL, &sigBase64Len) != LENGTH_ONLY_E) { - ret = 0; - } - else { - sigBase64 = (byte*)XMALLOC(sigBase64Len, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sigBase64 == NULL) { - ret = 0; - } - } - } - - if (ret > 0) { - XMEMSET(sigBase64, 0, sigBase64Len); - if (Base64_Encode(p7out, len, sigBase64, &sigBase64Len) < 0) { - WOLFSSL_MSG("Error in Base64_Encode of signature"); - ret = 0; - } - } - - /* build up SMIME message */ - if (ret > 0) { - if (flags & PKCS7_DETACHED) { - - /* generate random boundary */ - if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("No RNG to use"); - ret = 0; - } - - /* no need to generate random byte for null terminator (size-1) */ - if ((ret > 0) && (wc_RNG_GenerateBlock(&globalRNG, (byte*)boundary, - sizeof(boundary) - 1 ) != 0)) { - WOLFSSL_MSG("Error in wc_RNG_GenerateBlock"); - ret = 0; - } - - if (ret > 0) { - for (i = 0; i < (int)sizeof(boundary) - 1; i++) { - boundary[i] = - alphanum[boundary[i] % XSTR_SIZEOF(alphanum)]; - } - boundary[sizeof(boundary)-1] = 0; - } - - if (ret > 0) { - /* S/MIME header beginning */ - ret = wolfSSL_BIO_printf(out, - "MIME-Version: 1.0\n" - "Content-Type: multipart/signed; " - "protocol=\"application/x-pkcs7-signature\"; " - "micalg=\"%s\"; " - "boundary=\"----%s\"\n\n" - "This is an S/MIME signed message\n\n" - "------%s\n", - wolfSSL_SMIME_HashOIDToString(p7->pkcs7.hashOID), - boundary, boundary); - } - - if (ret > 0) { - /* S/MIME content */ - ret = wolfSSL_BIO_write(out, - p7->pkcs7.content, p7->pkcs7.contentSz); - } - - if (ret > 0) { - /* S/SMIME header end boundary */ - ret = wolfSSL_BIO_printf(out, - "\n------%s\n", boundary); - } - - if (ret > 0) { - /* Signature and header */ - ret = wolfSSL_BIO_printf(out, - "Content-Type: application/x-pkcs7-signature; " - "name=\"smime.p7s\"\n" - "Content-Transfer-Encoding: base64\n" - "Content-Disposition: attachment; " - "filename=\"smime.p7s\"\n\n" - "%.*s\n" /* Base64 encoded signature */ - "------%s--\n\n", - sigBase64Len, sigBase64, - boundary); - } - } - else { - p7TypeString = wolfSSL_SMIME_PKCS7TypeToString(p7->type); - if (p7TypeString == NULL) { - WOLFSSL_MSG("Unsupported PKCS7 SMIME type"); - ret = 0; - } - - if (ret > 0) { - /* not detached */ - ret = wolfSSL_BIO_printf(out, - "MIME-Version: 1.0\n" - "Content-Disposition: attachment; " - "filename=\"smime.p7m\"\n" - "Content-Type: application/x-pkcs7-mime; " - "smime-type=%s; name=\"smime.p7m\"\n" - "Content-Transfer-Encoding: base64\n\n" - "%.*s\n" /* signature */, - p7TypeString, sigBase64Len, sigBase64); - } - } - } - - if (p7out != NULL) { - XFREE(p7out, NULL, DYNAMIC_TYPE_TMP_BUFFER); - } - if (sigBase64 != NULL) { - XFREE(sigBase64, NULL, DYNAMIC_TYPE_TMP_BUFFER); - } - - if (ret > 0) { - return WOLFSSL_SUCCESS; - } - - return WOLFSSL_FAILURE; -} - -#endif /* HAVE_SMIME */ -#endif /* !NO_BIO */ -#endif /* OPENSSL_ALL */ - -#endif /* HAVE_PKCS7 */ -/******************************************************************************* - * END OF PKCS7 APIs - ******************************************************************************/ - -/******************************************************************************* - * START OF PKCS12 APIs - ******************************************************************************/ -#ifdef OPENSSL_EXTRA - -/* no-op function. Was initially used for adding encryption algorithms available - * for PKCS12 */ -void wolfSSL_PKCS12_PBE_add(void) -{ - WOLFSSL_ENTER("wolfSSL_PKCS12_PBE_add"); -} - -#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) -WOLFSSL_X509_PKCS12 *wolfSSL_d2i_PKCS12_fp(XFILE fp, - WOLFSSL_X509_PKCS12 **pkcs12) -{ - WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_fp"); - return (WOLFSSL_X509_PKCS12 *)wolfSSL_d2i_X509_fp_ex(fp, (void **)pkcs12, - PKCS12_TYPE); -} -#endif /* !NO_FILESYSTEM */ - -#endif /* OPENSSL_EXTRA */ - -#if defined(HAVE_PKCS12) - -#ifdef OPENSSL_EXTRA - -#if !defined(NO_ASN) && !defined(NO_PWDBASED) - -#ifndef NO_BIO -WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio, WC_PKCS12** pkcs12) -{ - WC_PKCS12* localPkcs12 = NULL; - unsigned char* mem = NULL; - long memSz; - int ret = -1; - - WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_bio"); - - if (bio == NULL) { - WOLFSSL_MSG("Bad Function Argument bio is NULL"); - return NULL; - } - - memSz = wolfSSL_BIO_get_len(bio); - if (memSz <= 0) { - return NULL; - } - mem = (unsigned char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (mem == NULL) { - return NULL; - } - - if (mem != NULL) { - localPkcs12 = wc_PKCS12_new(); - if (localPkcs12 == NULL) { - WOLFSSL_MSG("Memory error"); - } - } - - if (mem != NULL && localPkcs12 != NULL) { - if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) { - ret = wc_d2i_PKCS12(mem, (word32)memSz, localPkcs12); - if (ret < 0) { - WOLFSSL_MSG("Failed to get PKCS12 sequence"); - } - } - else { - WOLFSSL_MSG("Failed to get data from bio struct"); - } - } - - /* cleanup */ - if (mem != NULL) - XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (ret < 0 && localPkcs12 != NULL) { - wc_PKCS12_free(localPkcs12); - localPkcs12 = NULL; - } - if (pkcs12 != NULL) - *pkcs12 = localPkcs12; - - return localPkcs12; -} - -/* Converts the PKCS12 to DER format and outputs it into bio. - * - * bio is the structure to hold output DER - * pkcs12 structure to create DER from - * - * return 1 for success or 0 if an error occurs - */ -int wolfSSL_i2d_PKCS12_bio(WOLFSSL_BIO *bio, WC_PKCS12 *pkcs12) -{ - int ret = WOLFSSL_FAILURE; - - WOLFSSL_ENTER("wolfSSL_i2d_PKCS12_bio"); - - if ((bio != NULL) && (pkcs12 != NULL)) { - word32 certSz = 0; - byte *certDer = NULL; - - certSz = wc_i2d_PKCS12(pkcs12, &certDer, NULL); - if ((certSz > 0) && (certDer != NULL)) { - if (wolfSSL_BIO_write(bio, certDer, certSz) == (int)certSz) { - ret = WOLFSSL_SUCCESS; - } - } - - if (certDer != NULL) { - XFREE(certDer, NULL, DYNAMIC_TYPE_PKCS); - } - } - - return ret; -} -#endif /* !NO_BIO */ - -/* Creates a new WC_PKCS12 structure - * - * pass password to use - * name friendlyName to use - * pkey private key to go into PKCS12 bundle - * cert certificate to go into PKCS12 bundle - * ca extra certificates that can be added to bundle. Can be NULL - * keyNID type of encryption to use on the key (-1 means no encryption) - * certNID type of encryption to use on the certificate - * itt number of iterations with encryption - * macItt number of iterations with mac creation - * keyType flag for signature and/or encryption key - * - * returns a pointer to a new WC_PKCS12 structure on success and NULL on fail - */ -WC_PKCS12* wolfSSL_PKCS12_create(char* pass, char* name, WOLFSSL_EVP_PKEY* pkey, - WOLFSSL_X509* cert, WOLF_STACK_OF(WOLFSSL_X509)* ca, int keyNID, - int certNID, int itt, int macItt, int keyType) -{ - WC_PKCS12* pkcs12; - WC_DerCertList* list = NULL; - word32 passSz; - byte* keyDer = NULL; - word32 keyDerSz; - byte* certDer; - int certDerSz; - - WOLFSSL_ENTER("wolfSSL_PKCS12_create"); - - if (pass == NULL || pkey == NULL || cert == NULL) { - WOLFSSL_LEAVE("wolfSSL_PKCS12_create", BAD_FUNC_ARG); - return NULL; - } - passSz = (word32)XSTRLEN(pass); - - keyDer = (byte*)pkey->pkey.ptr; - keyDerSz = pkey->pkey_sz; - - certDer = (byte*)wolfSSL_X509_get_der(cert, &certDerSz); - if (certDer == NULL) { - return NULL; - } - - if (ca != NULL) { - unsigned long numCerts = ca->num; - WOLFSSL_STACK* sk = ca; - - while (numCerts > 0 && sk != NULL) { - byte* curDer; - WC_DerCertList* cur; - int curDerSz = 0; - - cur = (WC_DerCertList*)XMALLOC(sizeof(WC_DerCertList), NULL, - DYNAMIC_TYPE_PKCS); - if (cur == NULL) { - wc_FreeCertList(list, NULL); - return NULL; - } - - curDer = (byte*)wolfSSL_X509_get_der(sk->data.x509, &curDerSz); - if (curDer == NULL || curDerSz < 0) { - XFREE(cur, NULL, DYNAMIC_TYPE_PKCS); - wc_FreeCertList(list, NULL); - return NULL; - } - - cur->buffer = (byte*)XMALLOC(curDerSz, NULL, DYNAMIC_TYPE_PKCS); - if (cur->buffer == NULL) { - XFREE(cur, NULL, DYNAMIC_TYPE_PKCS); - wc_FreeCertList(list, NULL); - return NULL; - } - XMEMCPY(cur->buffer, curDer, curDerSz); - cur->bufferSz = curDerSz; - cur->next = list; - list = cur; - - sk = sk->next; - numCerts--; - } - } - - pkcs12 = wc_PKCS12_create(pass, passSz, name, keyDer, keyDerSz, - certDer, certDerSz, list, keyNID, certNID, itt, macItt, - keyType, NULL); - - if (ca != NULL) { - wc_FreeCertList(list, NULL); - } - - return pkcs12; -} - - -/* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure */ -int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw, - WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, - WOLF_STACK_OF(WOLFSSL_X509)** ca) -{ - void* heap = NULL; - int ret; - byte* certData = NULL; - word32 certDataSz; - byte* pk = NULL; - word32 pkSz; - WC_DerCertList* certList = NULL; -#ifdef WOLFSSL_SMALL_STACK - DecodedCert *DeCert; -#else - DecodedCert DeCert[1]; -#endif - - WOLFSSL_ENTER("wolfSSL_PKCS12_parse"); - - /* make sure we init return args */ - if (pkey) *pkey = NULL; - if (cert) *cert = NULL; - if (ca) *ca = NULL; - - if (pkcs12 == NULL || psw == NULL || pkey == NULL || cert == NULL) { - WOLFSSL_MSG("Bad argument value"); - return WOLFSSL_FAILURE; - } - - heap = wc_PKCS12_GetHeap(pkcs12); - - if (ca == NULL) { - ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz, - NULL); - } - else { - ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz, - &certList); - } - if (ret < 0) { - WOLFSSL_LEAVE("wolfSSL_PKCS12_parse", ret); - return WOLFSSL_FAILURE; - } - -#ifdef WOLFSSL_SMALL_STACK - DeCert = (DecodedCert *)XMALLOC(sizeof(*DeCert), heap, - DYNAMIC_TYPE_DCERT); - if (DeCert == NULL) { - WOLFSSL_MSG("out of memory"); - return WOLFSSL_FAILURE; - } -#endif - - /* Decode cert and place in X509 stack struct */ - if (certList != NULL) { - WC_DerCertList* current = certList; - - *ca = (WOLF_STACK_OF(WOLFSSL_X509)*)XMALLOC( - sizeof(WOLF_STACK_OF(WOLFSSL_X509)), heap, DYNAMIC_TYPE_X509); - if (*ca == NULL) { - if (pk != NULL) { - XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); - } - if (certData != NULL) { - XFREE(certData, heap, DYNAMIC_TYPE_PKCS); - } - /* Free up WC_DerCertList and move on */ - while (current != NULL) { - WC_DerCertList* next = current->next; - - XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); - XFREE(current, heap, DYNAMIC_TYPE_PKCS); - current = next; - } - ret = WOLFSSL_FAILURE; - goto out; - } - XMEMSET(*ca, 0, sizeof(WOLF_STACK_OF(WOLFSSL_X509))); - - /* add list of DER certs as X509's to stack */ - while (current != NULL) { - WC_DerCertList* toFree = current; - WOLFSSL_X509* x509; - - x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, - DYNAMIC_TYPE_X509); - InitX509(x509, 1, heap); - InitDecodedCert(DeCert, current->buffer, current->bufferSz, heap); - if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL) != 0) { - WOLFSSL_MSG("Issue with parsing certificate"); - FreeDecodedCert(DeCert); - wolfSSL_X509_free(x509); - } - else { - if (CopyDecodedToX509(x509, DeCert) != 0) { - WOLFSSL_MSG("Failed to copy decoded cert"); - FreeDecodedCert(DeCert); - wolfSSL_X509_free(x509); - wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; - if (pk != NULL) { - XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); - } - if (certData != NULL) { - XFREE(certData, heap, DYNAMIC_TYPE_PKCS); - } - /* Free up WC_DerCertList */ - while (current != NULL) { - WC_DerCertList* next = current->next; - - XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); - XFREE(current, heap, DYNAMIC_TYPE_PKCS); - current = next; - } - ret = WOLFSSL_FAILURE; - goto out; - } - FreeDecodedCert(DeCert); - - if (wolfSSL_sk_X509_push(*ca, x509) != 1) { - WOLFSSL_MSG("Failed to push x509 onto stack"); - wolfSSL_X509_free(x509); - wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; - if (pk != NULL) { - XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); - } - if (certData != NULL) { - XFREE(certData, heap, DYNAMIC_TYPE_PKCS); - } - - /* Free up WC_DerCertList */ - while (current != NULL) { - WC_DerCertList* next = current->next; - - XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); - XFREE(current, heap, DYNAMIC_TYPE_PKCS); - current = next; - } - ret = WOLFSSL_FAILURE; - goto out; - } - } - current = current->next; - XFREE(toFree->buffer, heap, DYNAMIC_TYPE_PKCS); - XFREE(toFree, heap, DYNAMIC_TYPE_PKCS); - } - } - - - /* Decode cert and place in X509 struct */ - if (certData != NULL) { - *cert = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, - DYNAMIC_TYPE_X509); - if (*cert == NULL) { - if (pk != NULL) { - XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); - } - if (ca != NULL) { - wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; - } - XFREE(certData, heap, DYNAMIC_TYPE_PKCS); - ret = WOLFSSL_FAILURE; - goto out; - } - InitX509(*cert, 1, heap); - InitDecodedCert(DeCert, certData, certDataSz, heap); - if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL) != 0) { - WOLFSSL_MSG("Issue with parsing certificate"); - } - if (CopyDecodedToX509(*cert, DeCert) != 0) { - WOLFSSL_MSG("Failed to copy decoded cert"); - FreeDecodedCert(DeCert); - if (pk != NULL) { - XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); - } - if (ca != NULL) { - wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; - } - wolfSSL_X509_free(*cert); *cert = NULL; - XFREE(certData, heap, DYNAMIC_TYPE_PKCS); - ret = WOLFSSL_FAILURE; - goto out; - } - FreeDecodedCert(DeCert); - XFREE(certData, heap, DYNAMIC_TYPE_PKCS); - } - - - /* get key type */ - ret = BAD_STATE_E; - if (pk != NULL) { /* decode key if present */ - *pkey = wolfSSL_EVP_PKEY_new_ex(heap); - if (*pkey == NULL) { - wolfSSL_X509_free(*cert); *cert = NULL; - if (ca != NULL) { - wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; - } - XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); - ret = WOLFSSL_FAILURE; - goto out; - } - - #ifndef NO_RSA - { - const unsigned char* pt = pk; - if (wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, pkey, &pt, pkSz) != - NULL) { - ret = 0; - } - } - #endif /* NO_RSA */ - - #ifdef HAVE_ECC - if (ret != 0) { /* if is in fail state check if ECC key */ - const unsigned char* pt = pk; - if (wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, pkey, &pt, pkSz) != - NULL) { - ret = 0; - } - } - #endif /* HAVE_ECC */ - if (pk != NULL) - XFREE(pk, heap, DYNAMIC_TYPE_PKCS); - if (ret != 0) { /* if is in fail state and no PKEY then fail */ - wolfSSL_X509_free(*cert); *cert = NULL; - if (ca != NULL) { - wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; - } - wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL; - WOLFSSL_MSG("Bad PKCS12 key format"); - ret = WOLFSSL_FAILURE; - goto out; - } - - if (pkey != NULL && *pkey != NULL) { - (*pkey)->save_type = 0; - } - } - - (void)ret; - (void)ca; - - ret = WOLFSSL_SUCCESS; - -out: - -#ifdef WOLFSSL_SMALL_STACK - XFREE(DeCert, heap, DYNAMIC_TYPE_DCERT); -#endif - - return ret; -} - -int wolfSSL_PKCS12_verify_mac(WC_PKCS12 *pkcs12, const char *psw, - int pswLen) -{ - WOLFSSL_ENTER("wolfSSL_PKCS12_verify_mac"); - - if (!pkcs12) { - return WOLFSSL_FAILURE; - } - - return wc_PKCS12_verify_ex(pkcs12, (const byte*)psw, pswLen) == 0 ? - WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} - -#endif /* !NO_ASN && !NO_PWDBASED */ - -#endif /* OPENSSL_EXTRA */ - -#endif /* HAVE_PKCS12 */ -/******************************************************************************* - * END OF PKCS12 APIs - ******************************************************************************/ +#define WOLFSSL_SSL_P7P12_INCLUDED +#include #endif /* !NO_CERTS */ diff --git a/src/ssl_bn.c b/src/ssl_bn.c index cbb4a92fa..c025755f9 100644 --- a/src/ssl_bn.c +++ b/src/ssl_bn.c @@ -25,7 +25,7 @@ #include - #include +#include #ifndef WC_NO_RNG #include #endif diff --git a/src/ssl_load.c b/src/ssl_load.c new file mode 100644 index 000000000..43982c4dc --- /dev/null +++ b/src/ssl_load.c @@ -0,0 +1,5783 @@ +/* ssl_load.c + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +/* + * WOLFSSL_SYS_CA_CERTS + * Enables ability to load system CA certs from the OS via + * wolfSSL_CTX_load_system_CA_certs. + */ + +#ifdef WOLFSSL_SYS_CA_CERTS + +#ifdef _WIN32 + #include + #include + + /* mingw gcc does not support pragma comment, and the + * linking with crypt32 is handled in configure.ac */ + #if !defined(__MINGW32__) && !defined(__MINGW64__) + #pragma comment(lib, "crypt32") + #endif +#endif + +#if defined(__APPLE__) && defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) +#include +#endif + +#endif /* WOLFSSL_SYS_CA_CERTS */ + +#if !defined(WOLFSSL_SSL_LOAD_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_bn.c does not need to be compiled separately from ssl.c + #endif +#else + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* PSK field of context when it exists. */ + #define CTX_HAVE_PSK(ctx) (ctx)->havePSK + /* PSK field of ssl when it exists. */ + #define SSL_HAVE_PSK(ssl) (ssl)->options.havePSK +#else + /* Have PSK value when no field. */ + #define CTX_HAVE_PSK(ctx) 0 + /* Have PSK value when no field. */ + #define SSL_HAVE_PSK(ssl) 0 +#endif +#ifdef NO_RSA + /* Boolean for RSA available. */ + #define WOLFSSL_HAVE_RSA 0 +#else + /* Boolean for RSA available. */ + #define WOLFSSL_HAVE_RSA 1 +#endif +#ifndef NO_CERTS + /* Private key size from ssl. */ + #define SSL_KEY_SZ(ssl) (ssl)->buffers.keySz +#else + /* Private key size not available. */ + #define SSL_KEY_SZ(ssl) 0 +#endif +#ifdef HAVE_ANON + /* Anonymous ciphersuite allowed field in context. */ + #define CTX_USE_ANON(ctx) (ctx)->useAnon +#else + /* Anonymous ciphersuite allowed field not in context. */ + #define CTX_USE_ANON(ctx) 0 +#endif + +#ifdef HAVE_PK_CALLBACKS + #define WOLFSSL_IS_PRIV_PK_SET(ctx, ssl) \ + wolfSSL_CTX_IsPrivatePkSet(((ssl) == NULL) ? (ctx) : (ssl)->ctx) +#else + #define WOLFSSL_IS_PRIV_PK_SET(ctx, ssl) 0 +#endif + +/* Get the heap from the context or the ssl depending on which is available. */ +#define WOLFSSL_HEAP(ctx, ssl) \ + (((ctx) != NULL) ? (ctx)->heap : (((ssl) != NULL) ? (ssl)->heap : NULL)) + + +#ifndef NO_CERTS + +/* Get DER encoding from data in a buffer as a DerBuffer. + * + * @param [in] buff Buffer containing data. + * @param [in] len Length of data in buffer. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @param [in] type Type of data: + * CERT_TYPE, CA_TYPE, TRUSTED_PEER_TYPE, + * PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE. + * @param [in, out] info Info for encryption. + * @param [in] heap Dynamic memory allocation hint. + * @param [out] der Holds DER encoded data. + * @return 0 on success. + * @return NOT_COMPILED_IN when format is PEM and PEM not supported. + * @return ASN_PARSE_E when format is ASN.1 and invalid DER encoding. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int DataToDerBuffer(const unsigned char* buff, word32 len, int format, + int type, EncryptedInfo* info, void* heap, DerBuffer** der) +{ + int ret; + + info->consumed = 0; + + /* Data in buffer has PEM format - extract DER data. */ + if (format == WOLFSSL_FILETYPE_PEM) { + #ifdef WOLFSSL_PEM_TO_DER + ret = PemToDer(buff, len, type, der, heap, info, NULL); + if (ret != 0) { + FreeDer(der); + } + #else + ret = NOT_COMPILED_IN; + #endif + } + /* Data in buffer is ASN.1 format - get first SEQ or OCT into der. */ + else { + int length; + word32 inOutIdx = 0; + + /* Get length of SEQ including header. */ + if ((info->consumed = wolfssl_der_length(buff, len)) > 0) { + ret = 0; + } + /* Private keys may be wrapped in OCT when PKCS#8 wrapper removed. + * TODO: is this really needed? */ + else if ((type == PRIVATEKEY_TYPE) && + (GetOctetString(buff, &inOutIdx, &length, len) >= 0)) { + /* Include octet string DER header. */ + info->consumed = length + inOutIdx; + ret = 0; + } + else { + ret = ASN_PARSE_E; + } + if (ret == 0) { + ret = AllocCopyDer(der, buff, (word32)info->consumed, type, heap); + } + } + + return ret; +} + +/* Process a user's certificate. + * + * Puts the 3-byte length before certificate data as required for TLS. + * CA certificates are added to the certificate manager. + * + * @param [in] cm Certificate manager. + * @param [in, out] pDer DER encoded data. + * @param [in] type Type of data. Valid values: + * CERT_TYPE, CA_TYPE or TRUSTED_PEER_TYPE. + * @param [in] verify How to verify certificate. + * @param [out] chainBuffer Buffer to hold chain of certificates. + * @param [in, out] pIdx On in, current index into chainBuffer. + * On out, index after certificate added. + * @param [in] bufferSz Size of buffer in bytes. + * @return 0 on success. + * @return BUFFER_E if chain buffer not big enough to hold certificate. + */ +static int ProcessUserCert(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, + int type, int verify, byte* chainBuffer, word32* pIdx, word32 bufferSz) +{ + int ret = 0; + word32 idx = *pIdx; + DerBuffer* der = *pDer; + + /* Check there is space for certificate in chainBuffer. */ + if ((ret == 0) && ((idx + der->length + CERT_HEADER_SZ) > bufferSz)) { + WOLFSSL_MSG(" Cert Chain bigger than buffer. " + "Consider increasing MAX_CHAIN_DEPTH"); + ret = BUFFER_E; + } + if (ret == 0) { + /* 3-byte length. */ + c32to24(der->length, &chainBuffer[idx]); + idx += CERT_HEADER_SZ; + /* Add complete DER encoded certificate. */ + XMEMCPY(&chainBuffer[idx], der->buffer, der->length); + idx += der->length; + + if (type == CA_TYPE) { + /* Add CA to certificate manager */ + ret = AddCA(cm, pDer, WOLFSSL_USER_CA, verify); + if (ret == 1) { + ret = 0; + } + } + } + + /* Update the index into chainBuffer. */ + *pIdx = idx; + return ret; +} + +/* Store the certificate chain buffer aganst WOLFSSL_CTX or WOLFSSL object. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] chainBuffer Buffer containing chain of certificates. + * @param [in] len Length, in bytes, of data in buffer. + * @param [in] cnt Number of certificates in chain. + * @param [in] type Type of data. Valid values: + * CERT_TYPE, CA_TYPE or CHAIN_CERT_TYPE. + * @param [in] heap Dynamic memory allocation hint. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int ProcessUserChainRetain(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + const byte* chainBuffer, word32 len, int cnt, int type, void* heap) +{ + int ret = 0; + + (void)cnt; + + /* Store in SSL object if available. */ + if (ssl != NULL) { + /* Dispose of old chain if not reference to context's. */ + if (ssl->buffers.weOwnCertChain) { + FreeDer(&ssl->buffers.certChain); + } + /* Allocate and copy the buffer into SSL object. */ + ret = AllocCopyDer(&ssl->buffers.certChain, chainBuffer, len, type, + heap); + ssl->buffers.weOwnCertChain = (ret == 0); + #ifdef WOLFSSL_TLS13 + /* Update count of certificates in chain. */ + ssl->buffers.certChainCnt = cnt; + #endif + } + /* Store in SSL context object if available. */ + else if (ctx != NULL) { + /* Dispose of old chain and allocate and copy in new chain. */ + FreeDer(&ctx->certChain); + /* Allocate and copy the buffer into SSL context object. */ + ret = AllocCopyDer(&ctx->certChain, chainBuffer, len, type, heap); + #ifdef WOLFSSL_TLS13 + /* Update count of certificates in chain. */ + ctx->certChainCnt = cnt; + #endif + } + + return ret; +} + +/* Process user cert chain to pass during the TLS handshake. + * + * If not a certificate type then data is ignored. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] buff Buffer holding certificates. + * @param [in] sz Length of data in buffer. + * @param [in] format Format of the certificate: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1 + * @param [in] type Type of certificate: + * CA_TYPE, CERT_TYPE or CHAIN_CERT_TYPE + * @param [out] used Number of bytes from buff used. + * @param [in, out] info Encryption information. + * @param [in] verify How to verify certificate. + * @return 0 on success. + * @return BAD_FUNC_ARG when type is CA_TYPE and ctx is NULL. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int ProcessUserChain(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + const unsigned char* buff, long sz, int format, int type, long* used, + EncryptedInfo* info, int verify) +{ + int ret = 0; + void* heap = WOLFSSL_HEAP(ctx, ssl); + + WOLFSSL_ENTER("ProcessUserChain"); + + /* Validate parameters. */ + if ((type == CA_TYPE) && (ctx == NULL)) { + WOLFSSL_MSG("Need context for CA load"); + ret = BAD_FUNC_ARG; + } + + /* Ignore non-certificate types. */ + if ((ret == 0) && (type != CERT_TYPE) && (type != CHAIN_CERT_TYPE) && + (type != CA_TYPE)) { + WOLFSSL_MSG("File type not a certificate"); + } + /* Check we haven't consumed all the data. */ + else if ((ret == 0) && (info->consumed >= sz)) { + WOLFSSL_MSG("Already consumed data"); + } + else if (ret == 0) { + #ifndef WOLFSSL_SMALL_STACK + byte stackBuffer[FILE_BUFFER_SIZE]; + #endif + StaticBuffer chain; + long consumed = info->consumed; + word32 idx = 0; + int gotOne = 0; + int cnt = 0; + /* Calculate max possible size, including max headers */ + long maxSz = (sz - consumed) + (CERT_HEADER_SZ * MAX_CHAIN_DEPTH); + + /* Setup buffer to hold chain. */ + #ifdef WOLFSSL_SMALL_STACK + static_buffer_init(&chain); + #else + static_buffer_init(&chain, stackBuffer, FILE_BUFFER_SIZE); + #endif + /* Make buffer big enough to support maximum size. */ + ret = static_buffer_set_size(&chain, (word32)maxSz, heap, + DYNAMIC_TYPE_FILE); + + WOLFSSL_MSG("Processing Cert Chain"); + /* Keep parsing certificates will data available. */ + while ((ret == 0) && (consumed < sz)) { + DerBuffer* part = NULL; + + /* Get a certificate as DER. */ + ret = DataToDerBuffer(buff + consumed, (word32)(sz - consumed), + format, type, info, heap, &part); + if (ret == 0) { + /* Process the user certificate. */ + ret = ProcessUserCert(ctx->cm, &part, type, verify, + chain.buffer, &idx, (word32)maxSz); + } + /* PEM may have trailing data that can be ignored. */ + if ((ret == ASN_NO_PEM_HEADER) && gotOne) { + WOLFSSL_MSG("We got one good cert, so stuff at end ok"); + ret = 0; + break; + } + /* Certificate data handled. */ + FreeDer(&part); + + if (ret == 0) { + /* Update consumed length. */ + consumed += info->consumed; + WOLFSSL_MSG(" Consumed another Cert in Chain"); + /* Update whether we got a user certificate. */ + gotOne |= (type != CA_TYPE); + /* Update count of certificates added to chain. */ + cnt++; + } + } + if (used != NULL) { + /* Return the total consumed length. */ + *used = consumed; + } + + /* Check whether there is data in the chain buffer. */ + if ((ret == 0) && (idx > 0)) { + /* Put the chain buffer against the SSL or SSL context object. */ + ret = ProcessUserChainRetain(ctx, ssl, chain.buffer, idx, cnt, type, + heap); + } + + /* Dispose of chain buffer. */ + static_buffer_free(&chain, heap, DYNAMIC_TYPE_FILE); + } + + WOLFSSL_LEAVE("ProcessUserChain", ret); + return ret; +} + +#ifndef NO_RSA +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION > 2)) +/* See if DER data is an RSA private key. + * + * Checks size meets minimum RSA key size. + * This implementation uses less dynamic memory. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoding. + * @param [in, out] keyFormat On in, expected format. 0 means unknown. + * @param [in] devId Device identifier. + * @param [out] keyType Type of key. + * @param [out] keySize Size of key. + * @return 0 on success or not an RSA key and format unknown. + * @return RSA_KEY_SIZE_E when key size doesn't meet minimum required. + */ +static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer* der, int* keyFormat, int devId, byte* keyType, int* keySize) +{ + int ret; + word32 idx; + int keySz = 0; + + (void)devId; + + /* Validate we have an RSA private key and get key size. */ + idx = 0; + ret = wc_RsaPrivateKeyValidate(der->buffer, &idx, &keySz, der->length); +#ifdef WOLF_PRIVATE_KEY_ID + /* If that didn't work then maybe a public key if device ID or callback. */ + if ((ret != 0) && ((devId != INVALID_DEVID) || + WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) { + word32 nSz; + + /* Decode as an RSA public key. */ + idx = 0; + ret = wc_RsaPublicKeyDecode_ex(der->buffer, &idx, der->length, NULL, + &nSz, NULL, NULL); + if (ret == 0) { + keySz = (int)nSz; + } + } +#endif + if (ret == 0) { + /* Get the minimum RSA key size from SSL or SSL context object. */ + int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz; + + /* Format, type and size are known. */ + *keyFormat = RSAk; + *keyType = rsa_sa_algo; + *keySize = keySz; + + /* Check that the size of the RSA key is enough. */ + if (keySz < minRsaSz) { + WOLFSSL_MSG("Private Key size too small"); + ret = RSA_KEY_SIZE_E; + } + /* No static ECC key possible. */ + if ((ssl != NULL) && (ssl->options.side == WOLFSSL_SERVER_END)) { + ssl->options.haveStaticECC = 0; + } + } + /* Not an RSA key but check whether we know what it is. */ + else if (*keyFormat == 0) { + WOLFSSL_MSG("Not an RSA key"); + /* Format unknown so keep trying. */ + ret = 0; + } + + return ret; +} +#else +/* See if DER data is an RSA private key. + * + * Checks size meets minimum RSA key size. + * This implementation uses more dynamic memory but supports older FIPS. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoding. + * @param [in, out] keyFormat On in, expected format. 0 means unknown. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] devId Device identifier. + * @param [out] keyType Type of key. + * @param [out] keySize Size of key. + * @return 0 on success or not an RSA key and format unknown. + * @return RSA_KEY_SIZE_E when key size doesn't meet minimum required. + */ +static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType, + int* keySize) +{ + int ret; + word32 idx; + /* make sure RSA key can be used */ +#ifdef WOLFSSL_SMALL_STACK + RsaKey* key; +#else + RsaKey key[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + /* Allocate an RSA key to parse into so we can get size. */ + key = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA); + if (key == NULL) + return MEMORY_E; +#endif + + /* Initialize the RSA key. */ + ret = wc_InitRsaKey_ex(key, heap, devId); + if (ret == 0) { + /* Check we have an RSA private key. */ + idx = 0; + ret = wc_RsaPrivateKeyDecode(der->buffer, &idx, key, der->length); + #ifdef WOLF_PRIVATE_KEY_ID + /* If that didn't work then maybe a public key if device ID or callback. + */ + if ((ret != 0) && ((devId != INVALID_DEVID) || + WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) { + /* If that didn't work then maybe a public key if device ID or + * callback. */ + idx = 0; + ret = wc_RsaPublicKeyDecode(der->buffer, &idx, key, der->length); + } + #endif + if (ret == 0) { + /* Get the minimum RSA key size from SSL or SSL context object. */ + int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz; + int keySz = wc_RsaEncryptSize((RsaKey*)key); + + /* Format is known. */ + *keyFormat = RSAk; + *keyType = rsa_sa_algo; + *keySize = keySz; + + /* Check that the size of the RSA key is enough. */ + if (keySz < minRsaSz) { + WOLFSSL_MSG("Private Key size too small"); + ret = RSA_KEY_SIZE_E; + } + /* No static ECC key possible. */ + if ((ssl != NULL) && (ssl->options.side == WOLFSSL_SERVER_END)) { + ssl->options.haveStaticECC = 0; + } + } + /* Not an RSA key but check whether we know what it is. */ + else if (*keyFormat == 0) { + WOLFSSL_MSG("Not an RSA key"); + /* Format unknown so keep trying. */ + ret = 0; + } + + /* Free dynamically allocated data in key. */ + wc_FreeRsaKey(key); + } + +#ifdef WOLFSSL_SMALL_STACK + /* Dispose of allocated key. */ + XFREE(key, heap, DYNAMIC_TYPE_RSA); +#endif + + return ret; +} +#endif +#endif /* !NO_RSA */ + +#ifdef HAVE_ECC +/* See if DER data is an ECC private key. + * + * Checks size meets minimum ECC key size. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoding. + * @param [in, out] keyFormat On in, expected format. 0 means unknown. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] devId Device identifier. + * @param [out] keyType Type of key. + * @param [out] keySize Size of key. + * @return 0 on success or not an ECC key and format unknown. + * @return ECC_KEY_SIZE_E when ECC key size doesn't meet minimum required. + */ +static int ProcessBufferTryDecodeEcc(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType, + int* keySize) +{ + int ret = 0; + word32 idx; + /* make sure ECC key can be used */ +#ifdef WOLFSSL_SMALL_STACK + ecc_key* key; +#else + ecc_key key[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + /* Allocate an ECC key to parse into. */ + key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC); + if (key == NULL) + return MEMORY_E; +#endif + + /* Initialize ECC key. */ + if (wc_ecc_init_ex(key, heap, devId) == 0) { + /* Decode as an ECC private key. */ + idx = 0; + ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, der->length); + #ifdef WOLF_PRIVATE_KEY_ID + /* If that didn't work then maybe a public key if device ID or callback. + */ + if ((ret != 0) && ((devId != INVALID_DEVID) || + WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) { + /* Decode as an ECC public key. */ + idx = 0; + ret = wc_EccPublicKeyDecode(der->buffer, &idx, key, der->length); + } + #endif + if (ret == 0) { + /* Get the minimum ECC key size from SSL or SSL context object. */ + int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz; + int keySz = wc_ecc_size(key); + + /* Format is known. */ + *keyFormat = ECDSAk; + #ifdef WOLFSSL_SM2 + if (key->dp->id == ECC_SM2P256V1) { + *keyType = sm2_sa_algo; + } + else + #endif + { + *keyType = ecc_dsa_sa_algo; + } + *keySize = keySz; + + /* Check that the size of the ECC key is enough. */ + if (keySz < minKeySz) { + WOLFSSL_MSG("ECC private key too small"); + ret = ECC_KEY_SIZE_E; + } + /* Static ECC key possible. */ + if (ssl) { + ssl->options.haveStaticECC = 1; + } + else { + ctx->haveStaticECC = 1; + } + } + /* Not an ECC key but check whether we know what it is. */ + else if (*keyFormat == 0) { + WOLFSSL_MSG("Not an ECC key"); + /* Format unknown so keep trying. */ + ret = 0; + } + + /* Free dynamically allocated data in key. */ + wc_ecc_free(key); + } + +#ifdef WOLFSSL_SMALL_STACK + /* Dispose of allocated key. */ + XFREE(key, heap, DYNAMIC_TYPE_ECC); +#endif + return ret; +} +#endif /* HAVE_ECC */ + +#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) +/* See if DER data is an Ed25519 private key. + * + * Checks size meets minimum ECC key size. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoding. + * @param [in, out] keyFormat On in, expected format. 0 means unknown. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] devId Device identifier. + * @param [out] keyType Type of key. + * @param [out] keySize Size of key. + * @return 0 on success or not an Ed25519 key and format unknown. + * @return ECC_KEY_SIZE_E when key size doesn't meet minimum required. + */ +static int ProcessBufferTryDecodeEd25519(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType, + int* keySize) +{ + int ret; + word32 idx; + /* make sure Ed25519 key can be used */ +#ifdef WOLFSSL_SMALL_STACK + ed25519_key* key; +#else + ed25519_key key[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + /* Allocate an Ed25519 key to parse into. */ + key = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap, + DYNAMIC_TYPE_ED25519); + if (key == NULL) + return MEMORY_E; +#endif + + /* Initialize Ed25519 key. */ + ret = wc_ed25519_init_ex(key, heap, devId); + if (ret == 0) { + /* Decode as an Ed25519 private key. */ + idx = 0; + ret = wc_Ed25519PrivateKeyDecode(der->buffer, &idx, key, der->length); + #ifdef WOLF_PRIVATE_KEY_ID + /* If that didn't work then maybe a public key if device ID or callback. + */ + if ((ret != 0) && ((devId != INVALID_DEVID) || + WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) { + /* Decode as an Ed25519 public key. */ + idx = 0; + ret = wc_Ed25519PublicKeyDecode(der->buffer, &idx, key, + der->length); + } + #endif + if (ret == 0) { + /* Get the minimum ECC key size from SSL or SSL context object. */ + int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz; + + /* Format is known. */ + *keyFormat = ED25519k; + *keyType = ed25519_sa_algo; + *keySize = ED25519_KEY_SIZE; + + /* Check that the size of the ECC key is enough. */ + if (ED25519_KEY_SIZE < minKeySz) { + WOLFSSL_MSG("ED25519 private key too small"); + ret = ECC_KEY_SIZE_E; + } + if (ssl != NULL) { +#if !defined(WOLFSSL_NO_CLIENT_AUTH) && !defined(NO_ED25519_CLIENT_AUTH) + /* Ed25519 requires caching enabled for tracking message + * hash used in EdDSA_Update for signing */ + ssl->options.cacheMessages = 1; +#endif + } + } + /* Not an Ed25519 key but check whether we know what it is. */ + else if (*keyFormat == 0) { + WOLFSSL_MSG("Not an Ed25519 key"); + /* Format unknown so keep trying. */ + ret = 0; + } + + /* Free dynamically allocated data in key. */ + wc_ed25519_free(key); + } + +#ifdef WOLFSSL_SMALL_STACK + /* Dispose of allocated key. */ + XFREE(key, heap, DYNAMIC_TYPE_ED25519); +#endif + return ret; +} +#endif /* HAVE_ED25519 && HAVE_ED25519_KEY_IMPORT */ + +#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) +/* See if DER data is an Ed448 private key. + * + * Checks size meets minimum ECC key size. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoding. + * @param [in, out] keyFormat On in, expected format. 0 means unknown. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] devId Device identifier. + * @param [out] keyType Type of key. + * @param [out] keySize Size of key. + * @return 0 on success or not an Ed448 key and format unknown. + * @return ECC_KEY_SIZE_E when key size doesn't meet minimum required. + */ +static int ProcessBufferTryDecodeEd448(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType, + int* keySize) +{ + int ret; + word32 idx; + /* make sure Ed448 key can be used */ +#ifdef WOLFSSL_SMALL_STACK + ed448_key* key = NULL; +#else + ed448_key key[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + /* Allocate an Ed448 key to parse into. */ + key = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, DYNAMIC_TYPE_ED448); + if (key == NULL) + return MEMORY_E; +#endif + + /* Initialize Ed448 key. */ + ret = wc_ed448_init_ex(key, heap, devId); + if (ret == 0) { + /* Decode as an Ed448 private key. */ + idx = 0; + ret = wc_Ed448PrivateKeyDecode(der->buffer, &idx, key, der->length); + #ifdef WOLF_PRIVATE_KEY_ID + /* If that didn't work then maybe a public key if device ID or callback. + */ + if ((ret != 0) && ((devId != INVALID_DEVID) || + WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) { + /* Decode as an Ed448 public key. */ + idx = 0; + ret = wc_Ed448PublicKeyDecode(der->buffer, &idx, key, der->length); + } + #endif + if (ret == 0) { + /* Get the minimum ECC key size from SSL or SSL context object. */ + int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz; + + /* Format is known. */ + *keyFormat = ED448k; + *keyType = ed448_sa_algo; + *keySize = ED448_KEY_SIZE; + + /* Check that the size of the ECC key is enough. */ + if (ED448_KEY_SIZE < minKeySz) { + WOLFSSL_MSG("ED448 private key too small"); + ret = ECC_KEY_SIZE_E; + } + if (ssl != NULL) { + /* Ed448 requires caching enabled for tracking message + * hash used in EdDSA_Update for signing */ + ssl->options.cacheMessages = 1; + } + } + /* Not an Ed448 key but check whether we know what it is. */ + else if (*keyFormat == 0) { + WOLFSSL_MSG("Not an Ed448 key"); + /* Format unknown so keep trying. */ + ret = 0; + } + + /* Free dynamically allocated data in key. */ + wc_ed448_free(key); + } + +#ifdef WOLFSSL_SMALL_STACK + /* Dispose of allocated key. */ + XFREE(key, heap, DYNAMIC_TYPE_ED448); +#endif + return ret; +} +#endif /* HAVE_ED448 && HAVE_ED448_KEY_IMPORT */ + +#if defined(HAVE_PQC) +#if defined(HAVE_FALCON) +/* See if DER data is an Falcon private key. + * + * Checks size meets minimum Falcon key size. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoding. + * @param [in, out] keyFormat On in, expected format. 0 means unknown. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] devId Device identifier. + * @param [out] keyType Type of key. + * @param [out] keySize Size of key. + * @return 0 on success or not an Falcon key and format unknown. + * @return FALCON_KEY_SIZE_E when key size doesn't meet minimum required. + */ +static int ProcessBufferTryDecodeFalcon(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer* der, int* keyFormat, void* heap, byte* keyType, int* keySize) +{ + int ret; + falcon_key* key; + + /* Allocate a Falcon key to parse into. */ + key = (falcon_key*)XMALLOC(sizeof(falcon_key), heap, DYNAMIC_TYPE_FALCON); + if (key == NULL) { + return MEMORY_E; + } + + /* Initialize Falcon key. */ + ret = wc_falcon_init(key); + if (ret == 0) { + /* Set up key to parse the format specified. */ + if (*keyFormat == FALCON_LEVEL1k) { + ret = wc_falcon_set_level(key, 1); + } + else if (*keyFormat == FALCON_LEVEL5k) { + ret = wc_falcon_set_level(key, 5); + } + else { + /* What if *keyformat is 0? We might want to do something more + * graceful here. */ + /* TODO: get the size of the private key for different formats and + * compare with DER length. */ + wc_falcon_free(key); + ret = ALGO_ID_E; + } + } + + if (ret == 0) { + /* Decode as a Falcon private key. */ + ret = wc_falcon_import_private_only(der->buffer, der->length, key); + if (ret == 0) { + /* Get the minimum Falcon key size from SSL or SSL context object. + */ + int minKeySz = ssl ? ssl->options.minFalconKeySz : + ctx->minFalconKeySz; + + /* Format is known. */ + if (*keyFormat == FALCON_LEVEL1k) { + *keyType = falcon_level1_sa_algo; + *keySize = FALCON_LEVEL1_KEY_SIZE; + } + else { + *keyType = falcon_level5_sa_algo; + *keySize = FALCON_LEVEL5_KEY_SIZE; + } + + /* Check that the size of the Falcon key is enough. */ + if (*keySize < minKeySz) { + WOLFSSL_MSG("Falcon private key too small"); + ret = FALCON_KEY_SIZE_E; + } + } + /* Not a Falcon key but check whether we know what it is. */ + else if (*keyFormat == 0) { + WOLFSSL_MSG("Not a Falcon key"); + /* Format unknown so keep trying. */ + ret = 0; + } + + /* Free dynamically allocated data in key. */ + wc_falcon_free(key); + } + + /* Dispose of allocated key. */ + XFREE(key, heap, DYNAMIC_TYPE_FALCON); + return ret; +} +#endif + +#if defined(HAVE_DILITHIUM) +/* See if DER data is an Dilithium private key. + * + * Checks size meets minimum Falcon key size. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoding. + * @param [in, out] keyFormat On in, expected format. 0 means unknown. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] devId Device identifier. + * @param [out] keyType Type of key. + * @param [out] keySize Size of key. + * @return 0 on success or not a Dilithium key and format unknown. + * @return DILITHIUM_KEY_SIZE_E when key size doesn't meet minimum required. + */ +static int ProcessBufferTryDecodeDilithium(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer* der, int* keyFormat, void* heap, byte* keyType, int* keySize) +{ + int ret; + dilithium_key* key; + + /* Allocate a Dilithium key to parse into. */ + key = (dilithium_key*)XMALLOC(sizeof(dilithium_key), heap, + DYNAMIC_TYPE_DILITHIUM); + if (key == NULL) { + return MEMORY_E; + } + + /* Initialize Dilithium key. */ + ret = wc_dilithium_init(key); + if (ret == 0) { + /* Set up key to parse the format specified. */ + if (*keyFormat == DILITHIUM_LEVEL2k) { + ret = wc_dilithium_set_level(key, 2); + } + else if (*keyFormat == DILITHIUM_LEVEL3k) { + ret = wc_dilithium_set_level(key, 3); + } + else if (*keyFormat == DILITHIUM_LEVEL5k) { + ret = wc_dilithium_set_level(key, 5); + } + else { + /* What if *keyformat is 0? We might want to do something more + * graceful here. */ + /* TODO: get the size of the private key for different formats and + * compare with DER length. */ + wc_dilithium_free(key); + ret = ALGO_ID_E; + } + } + + if (ret == 0) { + /* Decode as a Dilithium private key. */ + ret = wc_dilithium_import_private_only(der->buffer, der->length, key); + if (ret == 0) { + /* Get the minimum Dilithium key size from SSL or SSL context + * object. */ + int minKeySz = ssl ? ssl->options.minDilithiumKeySz : + ctx->minDilithiumKeySz; + + /* Format is known. */ + if (*keyFormat == DILITHIUM_LEVEL2k) { + *keyType = dilithium_level2_sa_algo; + *keySize = DILITHIUM_LEVEL2_KEY_SIZE; + } + else if (*keyFormat == DILITHIUM_LEVEL3k) { + *keyType = dilithium_level3_sa_algo; + *keySize = DILITHIUM_LEVEL3_KEY_SIZE; + } + else if (*keyFormat == DILITHIUM_LEVEL5k) { + *keyType = dilithium_level5_sa_algo; + *keySize = DILITHIUM_LEVEL5_KEY_SIZE; + } + + /* Check that the size of the Dilithium key is enough. */ + if (*keySize < minKeySz) { + WOLFSSL_MSG("Dilithium private key too small"); + ret = DILITHIUM_KEY_SIZE_E; + } + } + /* Not a Dilithium key but check whether we know what it is. */ + else if (*keyFormat == 0) { + WOLFSSL_MSG("Not a Dilithium key"); + /* Format unknown so keep trying. */ + ret = 0; + } + + /* Free dynamically allocated data in key. */ + wc_dilithium_free(key); + } + + /* Dispose of allocated key. */ + XFREE(key, heap, DYNAMIC_TYPE_DILITHIUM); + return ret; +} +#endif /* HAVE_DILITHIUM */ +#endif /* HAVE_PQC */ + +/* Try to decode DER data is a known private key. + * + * Checks size meets minimum for key type. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoding. + * @param [in, out] keyFormat On in, expected format. 0 means unknown. + * @param [in] heap Dynamic memory allocation hint. + * @param [out] type Type of key: + * PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE. + * @return 0 on success. + * @return BAD_FUNC_ARG when der or keyFormat is NULL. + * @return BAD_FUNC_ARG when ctx and ssl are NULL. + * @return WOLFSSL_BAD_FILE when unable to identify the key format. + */ +static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer* der, int* keyFormat, void* heap, int type) +{ + int ret = 0; + int devId = wolfSSL_CTX_GetDevId(ctx, ssl); + byte* keyType = NULL; + int* keySz = NULL; + + (void)heap; + (void)devId; + (void)type; + + /* Validate parameters. */ + if ((der == NULL) || (keyFormat == NULL)) { + ret = BAD_FUNC_ARG; + } + /* Must have an SSL context or SSL object to use. */ + if ((ret == 0) && (ctx == NULL) && (ssl == NULL)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + /* Determine where to put key type and size in SSL or context object. */ + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (type == ALT_PRIVATEKEY_TYPE) { + if (ssl != NULL) { + keyType = &ssl->buffers.altKeyType; + keySz = &ssl->buffers.altKeySz; + } + else { + keyType = &ctx->altPrivateKeyType; + keySz = &ctx->altPrivateKeySz; + } + } + else + #endif + /* Type is PRIVATEKEY_TYPE. */ + if (ssl != NULL) { + keyType = &ssl->buffers.keyType; + keySz = &ssl->buffers.keySz; + } + else { + keyType = &ctx->privateKeyType; + keySz = &ctx->privateKeySz; + } + } + +#ifndef NO_RSA + /* Try RSA if key format is RSA or yet unknown. */ + if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == RSAk))) { +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION > 2)) + ret = ProcessBufferTryDecodeRsa(ctx, ssl, der, keyFormat, devId, + keyType, keySz); +#else + ret = ProcessBufferTryDecodeRsa(ctx, ssl, der, keyFormat, heap, devId, + keyType, keySz); +#endif + } +#endif +#ifdef HAVE_ECC + /* Try ECC if key format is ECDSA or SM2, or yet unknown. */ + if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == ECDSAk) + #ifdef WOLFSSL_SM2 + || (*keyFormat == SM2k) + #endif + )) { + ret = ProcessBufferTryDecodeEcc(ctx, ssl, der, keyFormat, heap, devId, + keyType, keySz); + } +#endif /* HAVE_ECC */ +#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) + /* Try Ed25519 if key format is Ed25519 or yet unknown. */ + if ((ret == 0) && ((*keyFormat == 0 || *keyFormat == ED25519k))) { + ret = ProcessBufferTryDecodeEd25519(ctx, ssl, der, keyFormat, heap, + devId, keyType, keySz); + } +#endif /* HAVE_ED25519 && HAVE_ED25519_KEY_IMPORT */ +#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) + /* Try Ed448 if key format is Ed448 or yet unknown. */ + if ((ret == 0) && ((*keyFormat == 0 || *keyFormat == ED448k))) { + ret = ProcessBufferTryDecodeEd448(ctx, ssl, der, keyFormat, heap, devId, + keyType, keySz); + } +#endif /* HAVE_ED448 && HAVE_ED448_KEY_IMPORT */ +#if defined(HAVE_PQC) +#if defined(HAVE_FALCON) + /* Try Falcon if key format is Falcon level 1k or 5k or yet unknown. */ + if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == FALCON_LEVEL1k) || + (*keyFormat == FALCON_LEVEL5k))) { + ret = ProcessBufferTryDecodeFalcon(ctx, ssl, der, keyFormat, heap, + keyType, keySz); + } +#endif /* HAVE_FALCON */ +#if defined(HAVE_DILITHIUM) + /* Try Falcon if key format is Dilithium level 2k, 3k or 5k or yet unknown. + */ + if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == DILITHIUM_LEVEL2k) || + (*keyFormat == DILITHIUM_LEVEL3k) || + (*keyFormat == DILITHIUM_LEVEL5k))) { + ret = ProcessBufferTryDecodeDilithium(ctx, ssl, der, keyFormat, heap, + keyType, keySz); + } +#endif /* HAVE_DILITHIUM */ +#endif /* HAVE_PQC */ + + /* Check we know the format. */ + if ((ret == 0) && (*keyFormat == 0)) { + WOLFSSL_MSG("Not a supported key type"); + /* Not supported key format. */ + ret = WOLFSSL_BAD_FILE; + } + + return ret; +} + +#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED) +/* Decrypt PKCS#8 private key. + * + * @param [in] info Encryption information. + * @param [in] der DER encoded data. + * @param [in] heap Dynamic memory allocation hint. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int ProcessBufferPrivPkcs8Dec(EncryptedInfo* info, DerBuffer* der, + void* heap) +{ + int ret = 0; + word32 algId; + int passwordSz = NAME_SZ; +#ifndef WOLFSSL_SMALL_STACK + char password[NAME_SZ]; +#else + char* password; +#endif + + (void)heap; +#ifdef WOLFSSL_SMALL_STACK + /* Allocate memory for password. */ + password = (char*)XMALLOC(passwordSz, heap, DYNAMIC_TYPE_STRING); + if (password == NULL) { + ret = MEMORY_E; + } +#endif + + if (ret == 0) { + /* Get password. */ + ret = info->passwd_cb(password, passwordSz, PEM_PASS_READ, + info->passwd_userdata); + } + if (ret >= 0) { + /* Returned value is password size. */ + passwordSz = ret; + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("ProcessBuffer password", password, passwordSz); + #endif + + /* Decrypt PKCS#8 private key inline and get algorithm id. */ + ret = ToTraditionalEnc(der->buffer, der->length, password, passwordSz, + &algId); + } + if (ret >= 0) { + /* Zero out encrypted data not overwritten. */ + ForceZero(der->buffer + ret, der->length - ret); + /* Set decrypted data length. */ + der->length = ret; + } + + /* Ensure password is zeroized. */ + ForceZero(password, passwordSz); +#ifdef WOLFSSL_SMALL_STACK + /* Dispose of password memory. */ + XFREE(password, heap, DYNAMIC_TYPE_STRING); +#elif defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(password, NAME_SZ); +#endif + return ret; +} +#endif /* WOLFSSL_ENCRYPTED_KEYS && !NO_PWDBASED */ + +/* Put the DER into the SSL or SSL context object. + * + * Precondition: ctx or ssl is not NULL. + * Precondition: Must be a private key type. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoding. + */ +static void ProcessBufferPrivKeyHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer** der, int type) +{ + (void)type; + +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (type == ALT_PRIVATEKEY_TYPE) { + /* Put in alternate private key fields of objects. */ + if (ssl != NULL) { + /* Dispose of previous key if not context's. */ + if (ssl->buffers.weOwnAltKey) { + FreeDer(&ssl->buffers.altKey); + } + ssl->buffers.altKeyId = 0; + ssl->buffers.altKeyLabel = 0; + ssl->buffers.altKeyDevId = INVALID_DEVID; + /* Store key by reference and own it. */ + ssl->buffers.altKey = *der; + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("SSL Buffers key", (*der)->buffer, (*der)->length); + #endif + ssl->buffers.weOwnAltKey = 1; + } + else if (ctx != NULL) { + /* Dispose of previous key. */ + FreeDer(&ctx->altPrivateKey); + ctx->altPrivateKeyId = 0; + ctx->altPrivateKeyLabel = 0; + ctx->altPrivateKeyDevId = INVALID_DEVID; + /* Store key by reference. */ + ctx->altPrivateKey = *der; + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("CTX private key", (*der)->buffer, (*der)->length); + #endif + } + } + else +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + if (ssl != NULL) { + /* Dispose of previous key if not context's. */ + if (ssl->buffers.weOwnKey) { + FreeDer(&ssl->buffers.key); + } + ssl->buffers.keyId = 0; + ssl->buffers.keyLabel = 0; + ssl->buffers.keyDevId = INVALID_DEVID; + /* Store key by reference and own it. */ + ssl->buffers.key = *der; + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("SSL Buffers key", (*der)->buffer, (*der)->length); + #endif + ssl->buffers.weOwnKey = 1; + } + else if (ctx != NULL) { + /* Dispose of previous key. */ + FreeDer(&ctx->privateKey); + ctx->privateKeyId = 0; + ctx->privateKeyLabel = 0; + ctx->privateKeyDevId = INVALID_DEVID; + /* Store key by reference. */ + ctx->privateKey = *der; + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("CTX private key", (*der)->buffer, (*der)->length); + #endif + } +} + +/* Decode private key. + * + * Precondition: ctx or ssl is not NULL. + * Precondition: Must be a private key type. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoding. + * @param [in] format Original format of data. + * @param [in] info Encryption information. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] type Type of data: + * PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE. + * @return 0 on success. + * @return WOLFSSL_BAD_FILE when not able to decode. + */ +static int ProcessBufferPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer* der, int format, EncryptedInfo* info, void* heap, int type) +{ + int ret; + int keyFormat = 0; +#if (defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)) || \ + defined(HAVE_PKCS8) + word32 algId = 0; +#endif + + (void)info; + (void)format; + +#ifdef HAVE_PKCS8 + /* Try and remove PKCS8 header and get algorithm id. */ + ret = ToTraditional_ex(der->buffer, der->length, &algId); + if (ret > 0) { + /* Header stripped inline. */ + der->length = ret; + keyFormat = algId; + } +#endif + + /* Put the data into the SSL or SSL context object. */ + ProcessBufferPrivKeyHandleDer(ctx, ssl, &der, type); + /* Try to decode the DER data. */ + ret = ProcessBufferTryDecode(ctx, ssl, der, &keyFormat, heap, type); + +#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED) + /* If private key type PKCS8 header wasn't already removed (algId == 0). */ + if (((ret != 0) || (keyFormat == 0)) && (format != WOLFSSL_FILETYPE_PEM) && + (info->passwd_cb != NULL) && (algId == 0)) { + /* Try to decrypt DER data as a PKCS#8 private key. */ + ret = ProcessBufferPrivPkcs8Dec(info, der, heap); + if (ret >= 0) { + /* Try to decode decrypted data. */ + ret = ProcessBufferTryDecode(ctx, ssl, der, &keyFormat, heap, type); + } + } +#endif /* WOLFSSL_ENCRYPTED_KEYS && !NO_PWDBASED */ + + /* Check if we were able to determine key format. */ + if ((ret == 0) && (keyFormat == 0)) { + #ifdef OPENSSL_EXTRA + /* Decryption password is probably wrong. */ + if (info->passwd_cb) { + EVPerr(0, EVP_R_BAD_DECRYPT); + } + #endif + WOLFSSL_ERROR(WOLFSSL_BAD_FILE); + /* Unable to decode DER data. */ + ret = WOLFSSL_BAD_FILE; + } + + return ret; +} + +/* Use the key OID to determine have options. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] keyOID OID for public/private key. + */ +static void wolfssl_set_have_from_key_oid(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + int keyOID) +{ + /* Set which private key algorithm available based on key OID. */ + switch (keyOID) { + case ECDSAk: + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) + case SM2k: + #endif + #ifdef HAVE_ED25519 + case ED25519k: + #endif + #ifdef HAVE_ED448 + case ED448k: + #endif + if (ssl != NULL) { + ssl->options.haveECC = 1; + } + else { + ctx->haveECC = 1; + } + break; + #ifndef NO_RSA + case RSAk: + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + if (ssl != NULL) { + ssl->options.haveRSA = 1; + } + else { + ctx->haveRSA = 1; + } + break; + #endif + #ifdef HAVE_PQC + #ifdef HAVE_FALCON + case FALCON_LEVEL1k: + case FALCON_LEVEL5k: + if (ssl != NULL) { + ssl->options.haveFalconSig = 1; + } + else { + ctx->haveFalconSig = 1; + } + break; + #endif /* HAVE_FALCON */ + #ifdef HAVE_DILITHIUM + case DILITHIUM_LEVEL2k: + case DILITHIUM_LEVEL3k: + case DILITHIUM_LEVEL5k: + if (ssl != NULL) { + ssl->options.haveDilithiumSig = 1; + } + else { + ctx->haveDilithiumSig = 1; + } + break; + #endif /* HAVE_DILITHIUM */ + #endif /* HAVE_PQC */ + default: + WOLFSSL_MSG("Cert key not supported"); + break; + } +} + +/* Set which private key algorithm we have against SSL or SSL context object. + * + * Precondition: ctx or ssl is not NULL. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] cert Decode certificate. + */ +static void ProcessBufferCertSetHave(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DecodedCert* cert) +{ + if (ssl != NULL) { + /* Reset signatures we have in SSL. */ + ssl->options.haveECDSAsig = 0; + ssl->options.haveFalconSig = 0; + ssl->options.haveDilithiumSig = 0; + } + + /* Set which signature we have based on the type in the cert. */ + switch (cert->signatureOID) { + case CTC_SHAwECDSA: + case CTC_SHA256wECDSA: + case CTC_SHA384wECDSA: + case CTC_SHA512wECDSA: + #ifdef HAVE_ED25519 + case CTC_ED25519: + #endif + #ifdef HAVE_ED448 + case CTC_ED448: + #endif + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) + case CTC_SM3wSM2: + #endif + WOLFSSL_MSG("ECDSA/ED25519/ED448 cert signature"); + if (ssl) { + ssl->options.haveECDSAsig = 1; + } + else if (ctx) { + ctx->haveECDSAsig = 1; + } + break; +#ifdef HAVE_PQC + #ifdef HAVE_FALCON + case CTC_FALCON_LEVEL1: + case CTC_FALCON_LEVEL5: + WOLFSSL_MSG("Falcon cert signature"); + if (ssl) { + ssl->options.haveFalconSig = 1; + } + else if (ctx) { + ctx->haveFalconSig = 1; + } + break; + #endif + #ifdef HAVE_DILITHIUM + case CTC_DILITHIUM_LEVEL2: + case CTC_DILITHIUM_LEVEL3: + case CTC_DILITHIUM_LEVEL5: + WOLFSSL_MSG("Dilithium cert signature"); + if (ssl) { + ssl->options.haveDilithiumSig = 1; + } + else if (ctx) { + ctx->haveDilithiumSig = 1; + } + break; + #endif +#endif + default: + WOLFSSL_MSG("Cert signature not supported"); + break; + } + +#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ + (defined(HAVE_PQC) && defined(HAVE_LIBOQS)) || !defined(NO_RSA) + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) + /* Set the private key curve OID. */ + if (ssl != NULL) { + ssl->pkCurveOID = cert->pkCurveOID; + } + else { + ctx->pkCurveOID = cert->pkCurveOID; + } + #endif +#ifndef WC_STRICT_SIG + wolfssl_set_have_from_key_oid(ctx, ssl, cert->keyOID); +#else + /* Set whether ECC is available baed on signature available. */ + if (ssl != NULL) { + ssl->options.haveECC = ssl->options.haveECDSAsig; + } + else { + ctx->haveECC = ctx->haveECDSAsig; + } +#endif /* !WC_STRICT_SIG */ +#endif +} + +/* Check key size is valid. + * + * Precondition: ctx or ssl is not NULL. + * + * @param [in] min Minimum key size. + * @param [in] max Maximum key size. + * @param [in] keySz Key size. + * @param [in] err Error value to return when key size is invalid. + * @return 0 on success. + * @return err when verifying and min is less than 0 or key size is invalid. + */ +#define CHECK_KEY_SZ(min, max, keySz, err) \ + (((min) < 0) || ((keySz) < (min)) || ((keySz) > (max))) ? (err) : 0 + +/* Check public key in certificate. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] cert Certificate object. + * @return 0 on success. + * @return Non-zero when an error occurred. + */ +static int ProcessBufferCertPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DecodedCert* cert, int checkKeySz) +{ + int ret = 0; +#ifdef WOLF_PRIVATE_KEY_ID + byte keyType = 0; +#endif + int keySz = 0; +#ifndef NO_RSA + word32 idx; +#endif + + /* Get key size and check unless not verifying. */ + switch (cert->keyOID) { +#ifndef NO_RSA + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + case RSAk: + #ifdef WOLF_PRIVATE_KEY_ID + keyType = rsa_sa_algo; + #endif + /* Determine RSA key size by parsing public key */ + idx = 0; + ret = wc_RsaPublicKeyDecode_ex(cert->publicKey, &idx, + cert->pubKeySize, NULL, (word32*)&keySz, NULL, NULL); + if ((ret == 0) && checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minRsaKeySz : + ctx->minRsaKeySz, RSA_MAX_SIZE / 8, keySz, RSA_KEY_SIZE_E); + } + break; +#endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + #ifdef WOLF_PRIVATE_KEY_ID + keyType = ecc_dsa_sa_algo; + #endif + /* Determine ECC key size based on curve */ + #ifdef WOLFSSL_CUSTOM_CURVES + if ((cert->pkCurveOID == 0) && (cert->pkCurveSize != 0)) { + keySz = cert->pkCurveSize; + } + else + #endif + { + keySz = wc_ecc_get_curve_size_from_id(wc_ecc_get_oid( + cert->pkCurveOID, NULL, NULL)); + } + + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz, + ECC_KEY_SIZE_E); + } + break; + #endif /* HAVE_ECC */ + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) + case SM2k: + #ifdef WOLF_PRIVATE_KEY_ID + keyType = sm2_sa_algo; + #endif + /* Determine ECC key size based on curve */ + keySz = WOLFSSL_SM2_KEY_BITS / 8; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz, + ECC_KEY_SIZE_E); + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED25519 + case ED25519k: + #ifdef WOLF_PRIVATE_KEY_ID + keyType = ed25519_sa_algo; + #endif + /* ED25519 is fixed key size */ + keySz = ED25519_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz, ED25519_KEY_SIZE, keySz, ECC_KEY_SIZE_E); + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + #ifdef WOLF_PRIVATE_KEY_ID + keyType = ed448_sa_algo; + #endif + /* ED448 is fixed key size */ + keySz = ED448_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz, ED448_KEY_SIZE, keySz, ECC_KEY_SIZE_E); + } + break; + #endif /* HAVE_ED448 */ + #if defined(HAVE_PQC) + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + #ifdef WOLF_PRIVATE_KEY_ID + keyType = falcon_level1_sa_algo; + #endif + /* Falcon is fixed key size */ + keySz = FALCON_LEVEL1_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz : + ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz, + FALCON_KEY_SIZE_E); + } + break; + case FALCON_LEVEL5k: + #ifdef WOLF_PRIVATE_KEY_ID + keyType = falcon_level5_sa_algo; + #endif + /* Falcon is fixed key size */ + keySz = FALCON_MAX_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz : + ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz, + FALCON_KEY_SIZE_E); + } + break; + #endif /* HAVE_FALCON */ + #if defined(HAVE_DILITHIUM) + case DILITHIUM_LEVEL2k: + #ifdef WOLF_PRIVATE_KEY_ID + keyType = dilithium_level2_sa_algo; + #endif + /* Dilithium is fixed key size */ + keySz = DILITHIUM_MAX_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz : + ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz, + DILITHIUM_KEY_SIZE_E); + } + break; + case DILITHIUM_LEVEL3k: + #ifdef WOLF_PRIVATE_KEY_ID + keyType = dilithium_level3_sa_algo; + #endif + /* Dilithium is fixed key size */ + keySz = DILITHIUM_MAX_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz : + ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz, + DILITHIUM_KEY_SIZE_E); + } + break; + case DILITHIUM_LEVEL5k: + #ifdef WOLF_PRIVATE_KEY_ID + keyType = dilithium_level5_sa_algo; + #endif + /* Dilithium is fixed key size */ + keySz = DILITHIUM_MAX_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz : + ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz, + DILITHIUM_KEY_SIZE_E); + } + break; + #endif /* HAVE_DILITHIUM */ + #endif /* HAVE_PQC */ + + default: + WOLFSSL_MSG("No key size check done on public key in certificate"); + break; + } + +#ifdef WOLF_PRIVATE_KEY_ID + /* Store the type and key size as there may not be a private key set. */ + if (ssl != NULL) { + ssl->buffers.keyType = keyType; + ssl->buffers.keySz = keySz; + } + else { + ctx->privateKeyType = keyType; + ctx->privateKeySz = keySz; + } +#endif + + return ret; +} + +#ifdef WOLFSSL_DUAL_ALG_CERTS +static int ProcessBufferCertAltPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DecodedCert* cert, int checkKeySz) +{ + int ret = 0; + byte keyType = 0; + int keySz = 0; +#ifndef NO_RSA + word32 idx; +#endif + + /* Check alternative key size of cert. */ + switch (cert->sapkiOID) { + /* No OID set. */ + case 0: + if (cert->sapkiLen != 0) { + /* Have the alternative key data but no OID. */ + ret = NOT_COMPILED_IN; + } + break; + +#ifndef NO_RSA + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + case RSAk: + keyType = rsa_sa_algo; + /* Determine RSA key size by parsing public key */ + idx = 0; + ret = wc_RsaPublicKeyDecode_ex(cert->sapkiDer, &idx, + cert->sapkiLen, NULL, (word32*)&keySz, NULL, NULL); + if ((ret == 0) && checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minRsaKeySz : + ctx->minRsaKeySz, RSA_MAX_SIZE / 8, keySz, RSA_KEY_SIZE_E); + } + break; +#endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + { + #ifdef WOLFSSL_SMALL_STACK + ecc_key* temp_key = NULL; + #else + ecc_key temp_key[1]; + #endif + keyType = ecc_dsa_sa_algo; + + #ifdef WOLFSSL_SMALL_STACK + temp_key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, + DYNAMIC_TYPE_ECC); + if (temp_key == NULL) { + ret = MEMORY_E; + } + #endif + + /* Determine ECC key size. We have to decode the sapki for + * that. */ + if (ret == 0) { + ret = wc_ecc_init_ex(temp_key, heap, INVALID_DEVID); + if (ret == 0) { + idx = 0; + ret = wc_EccPublicKeyDecode(cert->sapkiDer, &idx, temp_key, + cert->sapkiLen); + if (ret == 0) { + keySz = wc_ecc_size(temp_key); + } + wc_ecc_free(temp_key); + } + } + #ifdef WOLFSSL_SMALL_STACK + XFREE(temp_key, heap, DYNAMIC_TYPE_ECC); + #endif + + if ((ret == 0) && checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz, + ECC_KEY_SIZE_E); + } + break; + } + #endif /* HAVE_ECC */ + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) + case SM2k: + keyType = sm2_sa_algo; + /* Determine ECC key size based on curve */ + keySz = WOLFSSL_SM2_KEY_BITS / 8; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz, + ECC_KEY_SIZE_E); + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED25519 + case ED25519k: + keyType = ed25519_sa_algo; + /* ED25519 is fixed key size */ + keySz = ED25519_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz, ED25519_KEY_SIZE, keySz, ECC_KEY_SIZE_E); + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + keyType = ed448_sa_algo; + /* ED448 is fixed key size */ + keySz = ED448_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz, ED448_KEY_SIZE, keySz, ECC_KEY_SIZE_E); + } + break; + #endif /* HAVE_ED448 */ + #if defined(HAVE_PQC) + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + keyType = falcon_level1_sa_algo; + /* Falcon is fixed key size */ + keySz = FALCON_LEVEL1_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz : + ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz, + FALCON_KEY_SIZE_E); + } + break; + case FALCON_LEVEL5k: + keyType = falcon_level5_sa_algo; + /* Falcon is fixed key size */ + keySz = FALCON_LEVEL5_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz : + ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz, + FALCON_KEY_SIZE_E); + } + break; + #endif /* HAVE_FALCON */ + #if defined(HAVE_DILITHIUM) + case DILITHIUM_LEVEL2k: + keyType = dilithium_level2_sa_algo; + /* Dilithium is fixed key size */ + keySz = DILITHIUM_LEVEL2_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz : + ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz, + DILITHIUM_KEY_SIZE_E); + } + break; + case DILITHIUM_LEVEL3k: + keyType = dilithium_level3_sa_algo; + /* Dilithium is fixed key size */ + keySz = DILITHIUM_LEVEL3_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz : + ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz, + DILITHIUM_KEY_SIZE_E); + } + break; + case DILITHIUM_LEVEL5k: + keyType = dilithium_level5_sa_algo; + /* Dilithium is fixed key size */ + keySz = DILITHIUM_LEVEL5_KEY_SIZE; + if (checkKeySz) { + ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz : + ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz, + DILITHIUM_KEY_SIZE_E); + } + break; + #endif /* HAVE_DILITHIUM */ + #endif /* HAVE_PQC */ + + default: + /* In this case, there was an OID that we didn't recognize. + * This is an error. Use not compiled in because likely the + * given algorithm was not enabled. */ + ret = NOT_COMPILED_IN; + WOLFSSL_MSG("No alt key size check done on certificate"); + break; + } + + if (ssl != NULL) { + ssl->buffers.altKeyType = (byte)keyType; + ssl->buffers.altKeySz = keySz; + } + else if (ctx != NULL) { + ctx->altPrivateKeyType = (byte)keyType; + ctx->altPrivateKeySz = keySz; + } + + return ret; +} +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + +/* Parse the certificate and pull out information for TLS handshake. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoded X509 certificate. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + * @return WOLFSSL_BAD_FILE when decoding certificate fails. + */ +static int ProcessBufferCert(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der) +{ + int ret = 0; + void* heap = WOLFSSL_HEAP(ctx, ssl); +#if defined(HAVE_RPK) + RpkState* rpkState = ssl ? &ssl->options.rpkState : &ctx->rpkState; +#endif +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert; +#else + DecodedCert cert[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + /* Allocate memory for certificate to be decoded into. */ + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), heap, DYNAMIC_TYPE_DCERT); + if (cert == NULL) { + ret = MEMORY_E; + } + + if (ret == 0) +#endif + { + /* Get device id from SSL context or SSL object. */ + int devId = wolfSSL_CTX_GetDevId(ctx, ssl); + + WOLFSSL_MSG("Checking cert signature type"); + /* Initialize certificate object. */ + InitDecodedCert_ex(cert, der->buffer, der->length, heap, devId); + + /* Decode up to and including public key. */ + if (DecodeToKey(cert, 0) < 0) { + WOLFSSL_MSG("Decode to key failed"); + ret = WOLFSSL_BAD_FILE; + } + if (ret == 0) { + int checkKeySz = 1; + + #if defined(HAVE_RPK) + /* Store whether the crtificate is a raw public key. */ + rpkState->isRPKLoaded = cert->isRPK; + #endif /* HAVE_RPK */ + + /* Set which private key algorithm we have. */ + ProcessBufferCertSetHave(ctx, ssl, cert); + + /* Don't check if verification is disabled for SSL. */ + if ((ssl != NULL) && ssl->options.verifyNone) { + checkKeySz = 0; + } + /* Don't check if no SSL object verification is disabled for SSL + * context. */ + else if ((ssl == NULL) && ctx->verifyNone) { + checkKeySz = 0; + } + + /* Check public key size. */ + ret = ProcessBufferCertPublicKey(ctx, ssl, cert, checkKeySz); + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ret == 0) { + ret = ProcessBufferCertAltPublicKey(ctx, ssl, cert, checkKeySz); + } + #endif + } + } + + /* Dispose of dynamic memory in certificate object. */ + FreeDecodedCert(cert); +#ifdef WOLFSSL_SMALL_STACK + /* Dispose of certificate object. */ + XFREE(cert, heap, DYNAMIC_TYPE_DCERT); +#endif + return ret; +} + +/* Handle storing the DER encoding of the certificate. + * + * Do not free der outside of this function. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] der DER encoded certificate. + * @param [in] type Type of data: + * CERT_TYPE, CA_TYPE or TRUSTED_PEER_TYPE. + * @param [in] verify What verification to do. + * @return 0 on success. + * @return BAD_FUNC_ARG when type is CA_TYPE and ctx is NULL. + * @return WOLFSSL_BAD_CERTTYPE when data type is not supported. + */ +static int ProcessBufferCertHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + DerBuffer* der, int type, int verify) +{ + int ret = 0; + + /* CA certificate to verify with. */ + if (type == CA_TYPE) { + /* verify CA unless user set to no verify */ + ret = AddCA(ctx->cm, &der, WOLFSSL_USER_CA, verify); + if (ret == 1) { + ret = 0; + } + } +#ifdef WOLFSSL_TRUST_PEER_CERT + /* Trusted certificate to verify peer with. */ + else if (type == TRUSTED_PEER_TYPE) { + WOLFSSL_CERT_MANAGER* cm; + + /* Get certificate manager to add certificate to. */ + if (ctx != NULL) { + cm = ctx->cm; + } + else { + SSL_CM_WARNING(ssl); + cm = SSL_CM(ssl); + } + /* Add certificate as a trusted peer. */ + ret = AddTrustedPeer(cm, &der, verify); + if (ret != 1) { + WOLFSSL_MSG("Error adding trusted peer"); + } + } +#endif /* WOLFSSL_TRUST_PEER_CERT */ + /* Leaf certificate - our certificate. */ + else if (type == CERT_TYPE) { + if (ssl != NULL) { + /* Free previous certificate if we own it. */ + if (ssl->buffers.weOwnCert) { + FreeDer(&ssl->buffers.certificate); + #ifdef KEEP_OUR_CERT + /* Dispose of X509 version of certificate. */ + wolfSSL_X509_free(ssl->ourCert); + ssl->ourCert = NULL; + #endif + } + /* Store certificate as ours. */ + ssl->buffers.certificate = der; + #ifdef KEEP_OUR_CERT + ssl->keepCert = 1; /* hold cert for ssl lifetime */ + #endif + /* We have to free the certificate buffer. */ + ssl->buffers.weOwnCert = 1; + /* ourCert is created on demand. */ + } + else if (ctx != NULL) { + /* Free previous certificate. */ + FreeDer(&ctx->certificate); /* Make sure previous is free'd */ + #ifdef KEEP_OUR_CERT + /* Dispose of X509 version of certificate if we own it. */ + if (ctx->ownOurCert) { + wolfSSL_X509_free(ctx->ourCert); + } + ctx->ourCert = NULL; + #endif + /* Store certificate as ours. */ + ctx->certificate = der; + /* ourCert is created on demand. */ + } + } + else { + /* Dispose of DER buffer. */ + FreeDer(&der); + /* Not a certificate type supported. */ + ret = WOLFSSL_BAD_CERTTYPE; + } + + return ret; +} + +/* Process certificate based on type. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] buff Buffer holding original data. + * @param [in] sz Size of data in buffer. + * @param [in] der DER encoding of certificate. + * @param [in] format Format of data. + * @param [in] type Type of data: + * CERT_TYPE, CA_TYPE or TRUSTED_PEER_TYPE. + * @param [in] verify What verification to do. + * @return 0 on success. + * @return WOLFSSL_FATAL_ERROR on failure. + */ +static int ProcessBufferCertTypes(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + const unsigned char* buff, long sz, DerBuffer* der, int format, int type, + int verify) +{ + int ret; + + (void)buff; + (void)sz; + (void)format; + + ret = ProcessBufferCertHandleDer(ctx, ssl, der, type, verify); + if ((ret == 0) && (type == CERT_TYPE)) { + /* Process leaf certificate. */ + ret = ProcessBufferCert(ctx, ssl, der); + } +#if !defined(NO_WOLFSSL_CM_VERIFY) && (!defined(NO_WOLFSSL_CLIENT) || \ + !defined(WOLFSSL_NO_CLIENT_AUTH)) + /* Hand bad CA or user certificate to callback. */ + if ((ret < 0) && ((type == CA_TYPE) || (type == CERT_TYPE))) { + /* Check for verification callback that may override error. */ + if ((ctx != NULL) && (ctx->cm != NULL) && + (ctx->cm->verifyCallback != NULL)) { + /* Verify and use callback. */ + ret = CM_VerifyBuffer_ex(ctx->cm, buff, sz, format, ret); + /* Convert error. */ + if (ret == 0) { + ret = WOLFSSL_FATAL_ERROR; + } + if (ret == 1) { + ret = 0; + } + } + } +#endif /* NO_WOLFSSL_CM_VERIFY */ + + return ret; +} + +/* Reset the cipher suites based on updated private key or certificate. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] type Type of certificate. + * @return 0 on success. + * @return WOLFSSL_FATAL_ERROR when allocation fails. + */ +static int ProcessBufferResetSuites(WOLFSSL_CTX* ctx, WOLFSSL* ssl, int type) +{ + int ret = 0; + + /* Reset suites of SSL object. */ + if (ssl != NULL) { + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* Allocate memory for suites. */ + if (AllocateSuites(ssl) != 0) { + ret = WOLFSSL_FATAL_ERROR; + } + else { + /* Determine cipher suites based on what we have. */ + InitSuites(ssl->suites, ssl->version, ssl->buffers.keySz, + WOLFSSL_HAVE_RSA, SSL_HAVE_PSK(ssl), ssl->options.haveDH, + ssl->options.haveECDSAsig, ssl->options.haveECC, TRUE, + ssl->options.haveStaticECC, ssl->options.haveFalconSig, + ssl->options.haveDilithiumSig, ssl->options.useAnon, TRUE, + ssl->options.side); + } + } + } + /* Reset suites of SSL context object. */ + else if ((type == CERT_TYPE) && (ctx->method->side == WOLFSSL_SERVER_END)) { + /* Allocate memory for suites. */ + if (AllocateCtxSuites(ctx) != 0) { + ret = WOLFSSL_FATAL_ERROR; + } + else { + /* Determine cipher suites based on what we have. */ + InitSuites(ctx->suites, ctx->method->version, ctx->privateKeySz, + WOLFSSL_HAVE_RSA, CTX_HAVE_PSK(ctx), ctx->haveDH, + ctx->haveECDSAsig, ctx->haveECC, TRUE, ctx->haveStaticECC, + ctx->haveFalconSig, ctx->haveDilithiumSig, CTX_USE_ANON(ctx), + TRUE, ctx->method->side); + } + } + + return ret; +} + +#ifndef WOLFSSL_DUAL_ALG_CERTS + /* Determine whether the type is for a private key. */ + #define IS_PRIVKEY_TYPE(type) ((type) == PRIVATEKEY_TYPE) +#else + /* Determine whether the type is for a private key. */ + #define IS_PRIVKEY_TYPE(type) (((type) == PRIVATEKEY_TYPE) || \ + ((type) == ALT_PRIVATEKEY_TYPE)) +#endif + +/* Process a buffer of data. + * + * Data type is a private key or a certificate. + * The format can be ASN.1 (DER) or PEM. + * + * @param [in, out] ctx SSL context object. + * @param [in] buff Buffer holding data. + * @param [in] sz Size of data in buffer. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @param [in] type Type of data: + * CERT_TYPE, CA_TYPE, TRUSTED_PEER_TYPE, + * PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE. + * @param [in, out] ssl SSL object. + * @param [out] used Number of bytes consumed. + * @param [in[ userChain Whether this certificate is for user's chain. + * @param [in] verify How to verify certificate. + * @return 1 on success. + * @return Less than 1 on failure. + */ +int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, long sz, + int format, int type, WOLFSSL* ssl, long* used, int userChain, int verify) +{ + DerBuffer* der = NULL; + int ret = 0; + void* heap = WOLFSSL_HEAP(ctx, ssl); +#ifdef WOLFSSL_SMALL_STACK + EncryptedInfo* info = NULL; +#else + EncryptedInfo info[1]; +#endif + + WOLFSSL_ENTER("ProcessBuffer"); + + /* Check data format is supported. */ + if ((format != WOLFSSL_FILETYPE_ASN1) && (format != WOLFSSL_FILETYPE_PEM)) { + ret = WOLFSSL_BAD_FILETYPE; + } + /* Need an object to store certificate into. */ + if ((ret == 0) && (ctx == NULL) && (ssl == NULL)) { + ret = BAD_FUNC_ARG; + } + /* CA certificates go into the SSL context object. */ + if ((ret == 0) && (ctx == NULL) && (type == CA_TYPE)) { + ret = BAD_FUNC_ARG; + } + /* This API does not handle CHAIN_CERT_TYPE */ + if ((ret == 0) && (type == CHAIN_CERT_TYPE)) { + ret = BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 0) { + /* Allocate memory for encryption information. */ + info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), heap, + DYNAMIC_TYPE_ENCRYPTEDINFO); + if (info == NULL) { + ret = MEMORY_E; + } + } +#endif + if (ret == 0) { + /* Initialize encryption information. */ + XMEMSET(info, 0, sizeof(EncryptedInfo)); + #if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED) + if (ctx != NULL) { + info->passwd_cb = ctx->passwd_cb; + info->passwd_userdata = ctx->passwd_userdata; + } + #endif + + /* Get the DER data for a private key or certificate. */ + ret = DataToDerBuffer(buff, (word32)sz, format, type, info, heap, &der); + if (used != NULL) { + /* Update to amount used/consumed. */ + *used = info->consumed; + } + #ifdef WOLFSSL_SMALL_STACK + if (ret != 0) { + /* Info no longer needed as loading failed. */ + XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); + } + #endif + } + + if ((ret == 0) && IS_PRIVKEY_TYPE(type)) { + /* Process the private key. */ + ret = ProcessBufferPrivateKey(ctx, ssl, der, format, info, heap, type); + #ifdef WOLFSSL_SMALL_STACK + /* Info no longer needed - keep max memory usage down. */ + XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); + #endif + } + else if (ret == 0) { + /* Processing a cerificate. */ + if (userChain) { + /* Take original buffer and add to user chain to send in TLS + * handshake. */ + ret = ProcessUserChain(ctx, ssl, buff, sz, format, type, used, info, + verify); + /* Additional chain is optional */ + if (ret == ASN_NO_PEM_HEADER) { + unsigned long pemErr = 0; + CLEAR_ASN_NO_PEM_HEADER_ERROR(pemErr); + ret = 0; + } + } + + #ifdef WOLFSSL_SMALL_STACK + /* Info no longer needed - keep max memory usage down. */ + XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); + #endif + + if (ret == 0) { + /* Process the different types of certificates. */ + ret = ProcessBufferCertTypes(ctx, ssl, buff, sz, der, format, type, + verify); + } + } + + /* Reset suites if this is a private key or user certificate. */ + if ((ret == 0) && ((type == PRIVATEKEY_TYPE) || (type == CERT_TYPE))) { + ret = ProcessBufferResetSuites(ctx, ssl, type); + } + + /* Convert return code. */ + if (ret == 0) { + ret = 1; + } + else if (ret == WOLFSSL_FATAL_ERROR) { + ret = 0; + } + WOLFSSL_LEAVE("ProcessBuffer", ret); + return ret; +} + +#if defined(WOLFSSL_WPAS) && defined(HAVE_CRL) +/* Try to parse data as a PEM CRL. + * + * @param [in] ctx SSL context object. + * @param [in] buff Buffer containing potential CRL in PEM format. + * @param [in] sz Amount of data in buffer remaining. + * @param [out] consumed Number of bytes in buffer was the CRL. + * @return 0 on success. + */ +static int ProcessChainBufferCRL(WOLFSSL_CTX* ctx, const unsigned char* buff, + long sz, long* consumed) +{ + int ret; + DerBuffer* der = NULL; + EncryptedInfo info; + + WOLFSSL_MSG("Trying a CRL"); + ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, &info, NULL); + if (ret == 0) { + WOLFSSL_MSG(" Processed a CRL"); + wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, der->buffer, der->length, + WOLFSSL_FILETYPE_ASN1); + FreeDer(&der); + *consumed = info.consumed; + } + + return ret; +} +#endif + +/* Process all chain certificates (and CRLs) in the PEM data. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] buff Buffer containing PEM data. + * @param [in] sz Size of data in buffer. + * @param [in] type Type of data. + * @param [in] verify How to verify certificate. + * @return 1 on success. + * @return 0 on failure. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int ProcessChainBuffer(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + const unsigned char* buff, long sz, int type, int verify) +{ + int ret = 0; + long used = 0; + int gotOne = 0; + + WOLFSSL_MSG("Processing CA PEM file"); + /* Keep processing file while no errors and data to parse. */ + while ((ret >= 0) && (used < sz)) { + long consumed = 0; + + /* Process the buffer. */ + ret = ProcessBuffer(ctx, buff + used, sz - used, WOLFSSL_FILETYPE_PEM, + type, ssl, &consumed, 0, verify); + /* Memory allocation failure is fatal. */ + if (ret == MEMORY_E) { + gotOne = 0; + } + /* Other error parsing. */ + else if (ret < 0) { +#if defined(WOLFSSL_WPAS) && defined(HAVE_CRL) + /* Try parsing a CRL. */ + if (ProcessChainBufferCRL(ctx, buff + used, sz - used, + &consumed) == 0) { + ret = 0; + } + else +#endif + /* Check whether we made progress. */ + if (consumed > 0) { + WOLFSSL_ERROR(ret); + WOLFSSL_MSG("CA Parse failed, with progress in file."); + WOLFSSL_MSG("Search for other certs in file"); + /* Check if we have more data to parse to recover. */ + if (used + consumed < sz) { + ret = 0; + } + } + else { + /* No progress in parsing being made - stop here. */ + WOLFSSL_MSG("CA Parse failed, no progress in file."); + WOLFSSL_MSG("Do not continue search for other certs in file"); + } + } + else { + /* Got a certificate out. */ + WOLFSSL_MSG(" Processed a CA"); + gotOne = 1; + } + /* Update used count. */ + used += consumed; + } + + /* May have other unparsable data but did we get a certificate? */ + if (gotOne) { + WOLFSSL_MSG("Processed at least one valid CA. Other stuff OK"); + ret = 1; + } + return ret; +} + + +/* Get verify settings for AddCA from SSL context. */ +#define GET_VERIFY_SETTING_CTX(ctx) \ + ((ctx) && (ctx)->verifyNone ? NO_VERIFY : VERIFY) +/* Get verify settings for AddCA from SSL. */ +#define GET_VERIFY_SETTING_SSL(ssl) \ + ((ssl)->options.verifyNone ? NO_VERIFY : VERIFY) + +#ifndef NO_FILESYSTEM + +/* Process data from a file as private keys, CRL or certificates. + * + * @param [in, out] ctx SSL context object. + * @param [in] fname Name of file to read. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @param [in] type Type of data: + * CERT_TYPE, CA_TYPE, TRUSTED_PEER_TYPE, + * PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE. + * @param [in, out] ssl SSL object. + * @param [in] userChain Whether file contains chain of certificates. + * @param [in, out] crl CRL object to load data into. + * @param [in] verify How to verify certificates. + * @return 1 on success. + * @return WOLFSSL_BAD_FILE when reading the file fails. + * @return WOLFSSL_BAD_CERTTYPE when unable to detect certificate type. + */ +int ProcessFile(WOLFSSL_CTX* ctx, const char* fname, int format, int type, + WOLFSSL* ssl, int userChain, WOLFSSL_CRL* crl, int verify) +{ + int ret = 0; +#ifndef WOLFSSL_SMALL_STACK + byte stackBuffer[FILE_BUFFER_SIZE]; +#endif + StaticBuffer content; + long sz = 0; + void* heap = WOLFSSL_HEAP(ctx, ssl); + + (void)crl; + (void)heap; + +#ifdef WOLFSSL_SMALL_STACK + static_buffer_init(&content); +#else + static_buffer_init(&content, stackBuffer, FILE_BUFFER_SIZE); +#endif + + /* Read file into static buffer. */ + ret = wolfssl_read_file_static(fname, &content, heap, DYNAMIC_TYPE_FILE, + &sz); + if ((ret == 0) && (type == DETECT_CERT_TYPE) && + (format != WOLFSSL_FILETYPE_PEM)) { + WOLFSSL_MSG("Cannot detect certificate type when not PEM"); + ret = WOLFSSL_BAD_CERTTYPE; + } + /* Try to detect type by parsing cert header and footer. */ + if ((ret == 0) && (type == DETECT_CERT_TYPE)) { +#ifndef NO_CODING + const char* header = NULL; + const char* footer = NULL; + + /* Look for CA header and footer - same as CERT_TYPE. */ + if (wc_PemGetHeaderFooter(CA_TYPE, &header, &footer) == 0 && + (XSTRNSTR((char*)content.buffer, header, (word32)sz) != NULL)) { + type = CA_TYPE; + } +#ifdef HAVE_CRL + /* Look for CRL header and footer. */ + else if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 && + (XSTRNSTR((char*)content.buffer, header, (word32)sz) != NULL)) { + type = CRL_TYPE; + } +#endif + /* Look for cert header and footer - same as CA_TYPE. */ + else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 && + (XSTRNSTR((char*)content.buffer, header, (word32)sz) != + NULL)) { + type = CERT_TYPE; + } + else +#endif + { + /* Not a header that we support. */ + WOLFSSL_MSG("Failed to detect certificate type"); + ret = WOLFSSL_BAD_CERTTYPE; + } + } + if (ret == 0) { + /* When CA or trusted peer and PEM - process as a chain buffer. */ + if (((type == CA_TYPE) || (type == TRUSTED_PEER_TYPE)) && + (format == WOLFSSL_FILETYPE_PEM)) { + ret = ProcessChainBuffer(ctx, ssl, content.buffer, sz, type, + verify); + } +#ifdef HAVE_CRL + else if (type == CRL_TYPE) { + /* Load the CRL. */ + ret = BufferLoadCRL(crl, content.buffer, sz, format, verify); + } +#endif +#ifdef WOLFSSL_DUAL_ALG_CERTS + else if (type == PRIVATEKEY_TYPE) { + /* Load all other certificate types. */ + ret = ProcessBuffer(ctx, content.buffer, sz, format, type, ssl, + NULL, userChain, verify); + if ((ret == 1) && (consumed < sz)) { + ret = ProcessBuffer(ctx, content.buffer + consumed, + sz - consumed, format, ALT_PRIVATEKEY_TYPE, ssl, NULL, 0, + verify); + } + } +#endif + else { + /* Load all other certificate types. */ + ret = ProcessBuffer(ctx, content.buffer, sz, format, type, ssl, + NULL, userChain, verify); + } + } + + /* Dispose of dynamically allocated data. */ + static_buffer_free(&content, heap, DYNAMIC_TYPE_FILE); + return ret; +} + +#ifndef NO_WOLFSSL_DIR +/* Load file when filename is in the path. + * + * @param [in, out] ctx SSL context object. + * @param [in] name Name of file. + * @param [in] verify How to verify a certificate. + * @param [in] flags Flags representing options for loading. + * @param [in, out] failCount Number of files that failed to load. + * @param [in, out] successCount Number of files successfully loaded. + * @return 1 on success. + * @return Not 1 when loading PEM certificate failed. + */ +static int wolfssl_ctx_load_path_file(WOLFSSL_CTX* ctx, const char* name, + int verify, int flags, int* failCount, int* successCount) +{ + int ret; + + /* Attempt to load file as a CA. */ + ret = ProcessFile(ctx, name, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0, NULL, + verify); + if (ret != 1) { + /* When ignoring errors or loading PEM only and no PEM. don't fail. */ + if ((flags & WOLFSSL_LOAD_FLAG_IGNORE_ERR) || + ((flags & WOLFSSL_LOAD_FLAG_PEM_CA_ONLY) && + (ret == ASN_NO_PEM_HEADER))) { + unsigned long err = 0; + CLEAR_ASN_NO_PEM_HEADER_ERROR(err); + #if defined(WOLFSSL_QT) + ret = 1; + #endif + } + else { + WOLFSSL_ERROR(ret); + WOLFSSL_MSG("Load CA file failed, continuing"); + /* Add to fail count. */ + (*failCount)++; + } + } + else { + #if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS) + /* Try loading as a trusted peer certificate. */ + ret = wolfSSL_CTX_trust_peer_cert(ctx, name, WOLFSSL_FILETYPE_PEM); + if (ret != 1) { + WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error. " + "Ignoring this error."); + } + #endif + /* Add to success count. */ + (*successCount)++; + } + + return ret; +} + +/* Load PEM formatted CA files from a path. + * + * @param [in, out] ctx SSL context object. + * @param [in] path Path to directory to read. + * @param [in] flags Flags representing options for loading. + * @param [in] verify How to verify a certificate. + * @param [in] successCount Number of files successfully loaded. + * @return 1 on success. + * @return 0 on failure. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int wolfssl_ctx_load_path(WOLFSSL_CTX* ctx, const char* path, + word32 flags, int verify, int successCount) +{ + int ret = 1; + char* name = NULL; + int fileRet; + int failCount = 0; +#ifdef WOLFSSL_SMALL_STACK + ReadDirCtx* readCtx; +#else + ReadDirCtx readCtx[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + /* Allocate memory for directory reading context. */ + readCtx = (ReadDirCtx*)XMALLOC(sizeof(ReadDirCtx), ctx->heap, + DYNAMIC_TYPE_DIRCTX); + if (readCtx == NULL) { + ret = MEMORY_E; + } +#endif + + if (ret == 1) { + /* Get name of first file in path. */ + fileRet = wc_ReadDirFirst(readCtx, path, &name); + /* While getting filename doesn't fail and name returned, process file. + */ + while ((fileRet == 0) && (name != NULL)) { + WOLFSSL_MSG(name); + /* Load file. */ + ret = wolfssl_ctx_load_path_file(ctx, name, verify, flags, + &failCount, &successCount); + /* Get next filenmae. */ + fileRet = wc_ReadDirNext(readCtx, path, &name); + } + /* Cleanup directory reading context. */ + wc_ReadDirClose(readCtx); + + /* When not WOLFSSL_QT, ret is always overwritten. */ + (void)ret; + + /* Return real directory read failure error codes. */ + if (fileRet != WC_READDIR_NOFILE) { + ret = fileRet; + #if defined(WOLFSSL_QT) || defined(WOLFSSL_IGNORE_BAD_CERT_PATH) + /* Ignore bad path error when flag set. */ + if ((ret == BAD_PATH_ERROR) && + (flags & WOLFSSL_LOAD_FLAG_IGNORE_BAD_PATH_ERR)) { + /* QSslSocket always loads certs in system folder + * when it is initialized. + * Compliant with OpenSSL when flag set. + */ + ret = 1; + } + else { + /* qssl socket wants to know errors. */ + WOLFSSL_ERROR(ret); + } + #endif + } + /* Report failure if no files successfully loaded or there were + * failures. */ + else if ((successCount == 0) || (failCount > 0)) { + /* Use existing error code if exists. */ + #if defined(WOLFSSL_QT) + /* Compliant with OpenSSL when flag set. */ + if (!(flags & WOLFSSL_LOAD_FLAG_IGNORE_ZEROFILE)) + #endif + { + /* Return 0 when no files loaded. */ + ret = 0; + } + } + else { + /* We loaded something so it is a success. */ + ret = 1; + } + + #ifdef WOLFSSL_SMALL_STACK + /* Dispose of dynamically allocated memory. */ + XFREE(readCtx, ctx->heap, DYNAMIC_TYPE_DIRCTX); + #endif + } + + return ret; +} +#endif + +/* Load a file and/or files in path + * + * No c_rehash. + * + * @param [in, out] ctx SSL context object. + * @param [in] file Name of file to load. May be NULL. + * @param [in] path Path to directory containing PEM CA files. + * May be NULL. + * @param [in] flags Flags representing options for loading. + * @return 1 on success. + * @return 0 on failure. + * @return NOT_COMPILED_IN when directory reading not supported and path is + * not NULL. + * @return Other negative on error. + */ +int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file, + const char* path, word32 flags) +{ + int ret = 1; +#ifndef NO_WOLFSSL_DIR + int successCount = 0; +#endif + int verify = WOLFSSL_VERIFY_DEFAULT; + + WOLFSSL_MSG("wolfSSL_CTX_load_verify_locations_ex"); + + /* Validate parameters. */ + if ((ctx == NULL) || ((file == NULL) && (path == NULL))) { + ret = 0; + } + + if (ret == 1) { + /* Get setting on how to verify certificates. */ + verify = GET_VERIFY_SETTING_CTX(ctx); + /* Overwrite setting when flag set. */ + if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) { + verify = VERIFY_SKIP_DATE; + } + + if (file != NULL) { + /* Load the PEM formatted CA file. */ + ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0, + NULL, verify); + #ifndef NO_WOLFSSL_DIR + if (ret == 1) { + /* Include success in overall count. */ + successCount++; + } + #endif + #if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS) + /* Load CA as a trusted peer certificate. */ + ret = wolfSSL_CTX_trust_peer_cert(ctx, file, WOLFSSL_FILETYPE_PEM); + if (ret != 1) { + WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error"); + } + #endif + } + } + + if ((ret == 1) && (path != NULL)) { +#ifndef NO_WOLFSSL_DIR + /* Load CA files form path. */ + ret = wolfssl_ctx_load_path(ctx, path, flags, verify, successCount); +#else + /* Loading a path not supported. */ + ret = NOT_COMPILED_IN; + (void)flags; +#endif + } + + return ret; +} + +/* Load a file and/or files in path + * + * No c_rehash. + * + * @param [in, out] ctx SSL context object. + * @param [in] file Name of file to load. May be NULL. + * @param [in] path Path to directory containing PEM CA files. + * May be NULL. + * @return 1 on success. + * @return 0 on failure. + */ +WOLFSSL_ABI +int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file, + const char* path) +{ + /* Load using default flags/options. */ + int ret = wolfSSL_CTX_load_verify_locations_ex(ctx, file, path, + WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); + + /* Return 1 on success or 0 on failure. */ + return WS_RETURN_CODE(ret, 0); +} + +#ifdef WOLFSSL_SYS_CA_CERTS + +#ifdef USE_WINDOWS_API + +/* Load CA certificate from Windows store. + * + * Assumes loaded is 0. + * + * @param [in, out] ctx SSL context object. + * @param [out] loaded Whether CA certificates were loaded. + * @return 1 on success. + * @return 0 on failure. + */ +static int LoadSystemCaCertsWindows(WOLFSSL_CTX* ctx, byte* loaded) +{ + int ret = 1; + word32 i; + HANDLE handle = NULL; + PCCERT_CONTEXT certCtx = NULL; + LPCSTR storeNames[2] = {"ROOT", "CA"}; + HCRYPTPROV_LEGACY hProv = (HCRYPTPROV_LEGACY)NULL; + + if ((ctx == NULL) || (loaded == NULL)) { + ret = 0; + } + + for (i = 0; (ret == 0) && (i < sizeof(storeNames)/sizeof(*storeNames)); + ++i) { + handle = CertOpenSystemStoreA(hProv, storeNames[i]); + if (handle != NULL) { + while ((certCtx = CertEnumCertificatesInStore(handle, certCtx)) + != NULL) { + if (certCtx->dwCertEncodingType == X509_ASN_ENCODING) { + if (ProcessBuffer(ctx, certCtx->pbCertEncoded, + certCtx->cbCertEncoded, WOLFSSL_FILETYPE_ASN1, + CA_TYPE, NULL, NULL, 0, + GET_VERIFY_SETTING_CTX(ctx)) == 1) { + /* + * Set "loaded" as long as we've loaded one CA + * cert. + */ + *loaded = 1; + } + } + } + } + else { + WOLFSSL_MSG_EX("Failed to open cert store %s.", storeNames[i]); + } + + if (handle != NULL && !CertCloseStore(handle, 0)) { + WOLFSSL_MSG_EX("Failed to close cert store %s.", storeNames[i]); + ret = 0; + } + } + + return ret; +} + +#elif defined(__APPLE__) + +#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) \ + && !defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION) +/* Manually obtains certificates from the system trust store and loads them + * directly into wolfSSL "the old way". + * + * As of MacOS 14.0 we are still able to use this method to access system + * certificates. Accessibility of this API is indicated by the presence of the + * Security/SecTrustSettings.h header. In the likely event that Apple removes + * access to this API on Macs, this function should be removed and the + * DoAppleNativeCertValidation() routine should be used for all devices. + * + * Assumes loaded is 0. + * + * @param [in, out] ctx SSL context object. + * @param [out] loaded Whether CA certificates were loaded. + * @return 1 on success. + * @return 0 on failure. + */ +static int LoadSystemCaCertsMac(WOLFSSL_CTX* ctx, byte* loaded) +{ + int ret = 1; + word32 i; + const unsigned int trustDomains[] = { + kSecTrustSettingsDomainUser, + kSecTrustSettingsDomainAdmin, + kSecTrustSettingsDomainSystem + }; + CFArrayRef certs; + OSStatus stat; + CFIndex numCerts; + CFDataRef der; + CFIndex j; + + if ((ctx == NULL) || (loaded == NULL)) { + ret = 0; + } + + for (i = 0; (ret == 1) && (i < sizeof(trustDomains)/sizeof(*trustDomains)); + ++i) { + stat = SecTrustSettingsCopyCertificates( + (SecTrustSettingsDomain)trustDomains[i], &certs); + if (stat == errSecSuccess) { + numCerts = CFArrayGetCount(certs); + for (j = 0; j < numCerts; ++j) { + der = SecCertificateCopyData((SecCertificateRef) + CFArrayGetValueAtIndex(certs, j)); + if (der != NULL) { + if (ProcessBuffer(ctx, CFDataGetBytePtr(der), + CFDataGetLength(der), WOLFSSL_FILETYPE_ASN1, + CA_TYPE, NULL, NULL, 0, + GET_VERIFY_SETTING_CTX(ctx)) == 1) { + /* + * Set "loaded" as long as we've loaded one CA + * cert. + */ + *loaded = 1; + } + + CFRelease(der); + } + } + + CFRelease(certs); + } + else if (stat == errSecNoTrustSettings) { + WOLFSSL_MSG_EX("No trust settings for domain %d, moving to next " + "domain.", trustDomains[i]); + } + else { + WOLFSSL_MSG_EX("SecTrustSettingsCopyCertificates failed with" + " status %d.", stat); + ret = 0; + break; + } + } + + return ret; +} +#endif /* defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) */ + +#else + +/* Potential system CA certs directories on Linux/Unix distros. */ +static const char* systemCaDirs[] = { +#if defined(__ANDROID__) || defined(ANDROID) + "/system/etc/security/cacerts" /* Android */ +#else + "/etc/ssl/certs", /* Debian, Ubuntu, Gentoo, others */ + "/etc/pki/ca-trust/source/anchors", /* Fedora, RHEL */ + "/etc/pki/tls/certs" /* Older RHEL */ +#endif +}; + +/* Get CA directory list. + * + * @param [out] num Number of CA directories. + * @return CA directory list. + * @return NULL when num is NULL. + */ +const char** wolfSSL_get_system_CA_dirs(word32* num) +{ + const char** ret; + + /* Validate parameters. */ + if (num == NULL) { + ret = NULL; + } + else { + ret = systemCaDirs; + *num = sizeof(systemCaDirs)/sizeof(*systemCaDirs); + } + + return ret; +} + +/* Load CA certificate from default system directories. + * + * Assumes loaded is 0. + * + * @param [in, out] ctx SSL context object. + * @param [out] loaded Whether CA certificates were loaded. + * @return 1 on success. + * @return 0 on failure. + */ +static int LoadSystemCaCertsNix(WOLFSSL_CTX* ctx, byte* loaded) { + int ret = 1; + word32 i; + + if ((ctx == NULL) || (loaded == NULL)) { + ret = 0; + } + + for (i = 0; (ret == 1) && (i < sizeof(systemCaDirs)/sizeof(*systemCaDirs)); + ++i) { + WOLFSSL_MSG_EX("Attempting to load system CA certs from %s.", + systemCaDirs[i]); + /* + * We want to keep trying to load more CA certs even if one cert in + * the directory is bad and can't be used (e.g. if one is expired), + * so we use WOLFSSL_LOAD_FLAG_IGNORE_ERR. + */ + if (wolfSSL_CTX_load_verify_locations_ex(ctx, NULL, systemCaDirs[i], + WOLFSSL_LOAD_FLAG_IGNORE_ERR) != 1) { + WOLFSSL_MSG_EX("Failed to load CA certs from %s, trying " + "next possible location.", systemCaDirs[i]); + } + else { + WOLFSSL_MSG_EX("Loaded CA certs from %s.", + systemCaDirs[i]); + *loaded = 1; + /* Stop searching after we've loaded one directory. */ + break; + } + } + + return ret; +} + +#endif + +/* Load CA certificates from system defined locations. + * + * @param [in, out] ctx SSL context object. + * @return 1 on success. + * @return 0 on failure. + * @return WOLFSSL_BAD_PATH when no error but no certificates loaded. + */ +int wolfSSL_CTX_load_system_CA_certs(WOLFSSL_CTX* ctx) +{ + int ret; + byte loaded = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_load_system_CA_certs"); + +#ifdef USE_WINDOWS_API + + ret = LoadSystemCaCertsWindows(ctx, &loaded); + +#elif defined(__APPLE__) + +#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) \ + && !defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION) + /* As of MacOS 14.0 we are still able to access system certificates and + * load them manually into wolfSSL "the old way". Accessibility of this API + * is indicated by the presence of the Security/SecTrustSettings.h header */ + ret = LoadSystemCaCertsMac(ctx, &loaded); +#elif defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION) + /* For other Apple devices, Apple has removed the ability to obtain + * certificates from the trust store, so we can't use wolfSSL's built-in + * certificate validation mechanisms anymore. We instead must call into the + * Security Framework APIs to authenticate peer certificates when received. + * (see src/internal.c:DoAppleNativeCertValidation()). + * Thus, there is no CA "loading" required, but to keep behavior consistent + * with the current API (not using system CA certs unless this function has + * been called), we simply set a flag indicating that the new apple trust + * verification routine should be used later */ + ctx->doAppleNativeCertValidationFlag = 1; + ret = 1; + loaded = 1; + +#if FIPS_VERSION_GE(2,0) /* Gate back to cert 3389 FIPS modules */ +#warning "Cryptographic operations may occur outside the FIPS module boundary" \ + "Please review FIPS claims for cryptography on this Apple device" +#endif /* FIPS_VERSION_GE(2,0) */ + +#else +/* HAVE_SECURITY_SECXXX_H macros are set by autotools or CMake when searching + * system for the required SDK headers. If building with user_settings.h, you + * will need to manually define WOLFSSL_APPLE_NATIVE_CERT_VALIDATION + * and ensure the appropriate Security.framework headers and libraries are + * visible to your compiler */ +#error "WOLFSSL_SYS_CA_CERTS on Apple devices requires Security.framework" \ + " header files to be detected, or a manual override with" \ + " WOLFSSL_APPLE_NATIVE_CERT_VALIDATION" +#endif + +#else + + ret = LoadSystemCaCertsNix(ctx, &loaded); + +#endif + + /* If we didn't fail but didn't load then we error out. */ + if ((ret == 1) && (!loaded)) { + ret = WOLFSSL_BAD_PATH; + } + + WOLFSSL_LEAVE("wolfSSL_CTX_load_system_CA_certs", ret); + + return ret; +} + +#endif /* WOLFSSL_SYS_CA_CERTS */ + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* Load a trusted peer certificate into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] file Name of peer certificate file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 when ctx or file is NULL. + */ +int wolfSSL_CTX_trust_peer_cert(WOLFSSL_CTX* ctx, const char* file, int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_cert"); + + /* Validate parameters. */ + if ((ctx == NULL) || (file == NULL)) { + ret = 0; + } + else { + ret = ProcessFile(ctx, file, format, TRUSTED_PEER_TYPE, NULL, 0, NULL, + GET_VERIFY_SETTING_CTX(ctx)); + } + + return ret; +} + +/* Load a trusted peer certificate into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] file Name of peer certificate file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 when ssl or file is NULL. + */ +int wolfSSL_trust_peer_cert(WOLFSSL* ssl, const char* file, int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_trust_peer_cert"); + + /* Validate parameters. */ + if ((ssl == NULL) || (file == NULL)) { + ret = 0; + } + else { + ret = ProcessFile(NULL, file, format, TRUSTED_PEER_TYPE, ssl, 0, NULL, + GET_VERIFY_SETTING_SSL(ssl)); + } + + return ret; +} +#endif /* WOLFSSL_TRUST_PEER_CERT */ + + +#ifdef WOLFSSL_DER_LOAD + +/* Load a CA certificate into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] file Name of peer certificate file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file, + int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_der_load_verify_locations"); + + /* Validate parameters. */ + if ((ctx == NULL) || (file == NULL)) { + ret = 0; + } + else { + ret = ProcessFile(ctx, file, format, CA_TYPE, NULL, 0, NULL, + GET_VERIFY_SETTING_CTX(ctx)); + } + + /* Return 1 on success or 0 on failure. */ + return WS_RC(ret); +} + +#endif /* WOLFSSL_DER_LOAD */ + + +/* Load a user certificate into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] file Name of user certificate file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + */ +WOLFSSL_ABI +int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file, + int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_file"); + + ret = ProcessFile(ctx, file, format, CERT_TYPE, NULL, 0, NULL, + GET_VERIFY_SETTING_CTX(ctx)); + + /* Return 1 on success or 0 on failure. */ + return WS_RC(ret); +} + + +/* Load a private key into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] file Name of private key file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + */ +WOLFSSL_ABI +int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX* ctx, const char* file, + int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_file"); + + ret = ProcessFile(ctx, file, format, PRIVATEKEY_TYPE, NULL, 0, NULL, + GET_VERIFY_SETTING_CTX(ctx)); + + /* Return 1 on success or 0 on failure. */ + return WS_RC(ret); +} + +#ifdef WOLFSSL_DUAL_ALG_CERTS +/* Load an alternative private key into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] file Name of private key file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_use_AltPrivateKey_file(WOLFSSL_CTX* ctx, const char* file, + int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_file"); + + ret = ProcessFile(ctx, file, format, ALT_PRIVATEKEY_TYPE, NULL, 0, NULL, + GET_VERIFY_SETTING_CTX(ctx)); + + /* Return 1 on success or 0 on failure. */ + return WS_RC(ret); +} +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + + +/* Load a PEM certificate chain into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] file Name of PEM certificate chain file. + * @return 1 on success. + * @return 0 on failure. + */ +WOLFSSL_ABI +int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file) +{ + int ret; + + /* process up to MAX_CHAIN_DEPTH plus subject cert */ + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file"); + + ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL, + GET_VERIFY_SETTING_CTX(ctx)); + + /* Return 1 on success or 0 on failure. */ + return WS_RC(ret); +} + +/* Load certificate chain into SSL context. + * + * Processes up to MAX_CHAIN_DEPTH plus subject cert. + * + * @param [in, out] ctx SSL context object. + * @param [in] file Name of private key file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_use_certificate_chain_file_format(WOLFSSL_CTX* ctx, + const char* file, int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file_format"); + + ret = ProcessFile(ctx, file, format, CERT_TYPE, NULL, 1, NULL, + GET_VERIFY_SETTING_CTX(ctx)); + + /* Return 1 on success or 0 on failure. */ + return WS_RC(ret); +} + +#endif /* NO_FILESYSTEM */ + +#ifdef OPENSSL_EXTRA + +/* Load a private key into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] pkey EVP private key. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_use_PrivateKey(WOLFSSL* ssl, WOLFSSL_EVP_PKEY* pkey) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_PrivateKey"); + + /* Validate parameters. */ + if ((ssl == NULL) || (pkey == NULL)) { + ret = 0; + } + else { + /* Get DER encoded key data from EVP private key. */ + ret = wolfSSL_use_PrivateKey_buffer(ssl, (unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz, WOLFSSL_FILETYPE_ASN1); + } + + return ret; +} + +/* Load a DER encoded private key in a buffer into SSL. + * + * @param [in] pri Indicates type of private key. Ignored. + * @param [in, out] ssl SSL object. + * @param [in] der Buffer holding DER encoded private key. + * @param [in] derSz Size of data in bytes. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_use_PrivateKey_ASN1(int pri, WOLFSSL* ssl, const unsigned char* der, + long derSz) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_PrivateKey_ASN1"); + + (void)pri; + + /* Validate parameters. */ + if ((ssl == NULL) || (der == NULL)) { + ret = 0; + } + else { + ret = wolfSSL_use_PrivateKey_buffer(ssl, der, derSz, + WOLFSSL_FILETYPE_ASN1); + } + + return ret; +} + +/* Load a DER encoded private key in a buffer into SSL context. + * + * @param [in] pri Indicates type of private key. Ignored. + * @param [in, out] ctx SSL context object. + * @param [in] der Buffer holding DER encoded private key. + * @param [in] derSz Size of data in bytes. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_use_PrivateKey_ASN1(int pri, WOLFSSL_CTX* ctx, + unsigned char* der, long derSz) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_ASN1"); + + (void)pri; + + /* Validate parameters. */ + if ((ctx == NULL) || (der == NULL)) { + ret = 0; + } + else { + ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSz, + WOLFSSL_FILETYPE_ASN1); + } + + return ret; +} + + +#ifndef NO_RSA +/* Load a DER encoded RSA private key in a buffer into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] der Buffer holding DER encoded RSA private key. + * @param [in] derSz Size of data in bytes. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_use_RSAPrivateKey_ASN1(WOLFSSL* ssl, unsigned char* der, long derSz) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_ASN1"); + + /* Validate parameters. */ + if ((ssl == NULL) || (der == NULL)) { + ret = 0; + } + else { + ret = wolfSSL_use_PrivateKey_buffer(ssl, der, derSz, + WOLFSSL_FILETYPE_ASN1); + } + + return ret; +} +#endif + +/* Load a certificate into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] x509 X509 certificate object. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_use_certificate(WOLFSSL* ssl, WOLFSSL_X509* x509) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_certificate"); + + /* Validate parameters. */ + if ((ssl == NULL) || (x509 == NULL) || (x509->derCert == NULL)) { + ret = 0; + } + else { + long idx = 0; + + /* Get DER encoded certificate data from X509 object. */ + ret = ProcessBuffer(NULL, x509->derCert->buffer, x509->derCert->length, + WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl, &idx, 0, + GET_VERIFY_SETTING_SSL(ssl)); + } + + /* Return 1 on success or 0 on failure. */ + return WS_RC(ret); +} + +#endif /* OPENSSL_EXTRA */ + +/* Load a DER encoded certificate in a buffer into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] der Buffer holding DER encoded certificate. + * @param [in] derSz Size of data in bytes. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, const unsigned char* der, + int derSz) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_certificate_ASN1"); + + /* Validate parameters. */ + if ((ssl == NULL) || (der == NULL)) { + ret = 0; + } + else { + long idx = 0; + + ret = ProcessBuffer(NULL, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, + ssl, &idx, 0, GET_VERIFY_SETTING_SSL(ssl)); + } + + /* Return 1 on success or 0 on failure. */ + return WS_RC(ret); +} + +#ifndef NO_FILESYSTEM + +/* Load a certificate from a file into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] file Name of file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +WOLFSSL_ABI +int wolfSSL_use_certificate_file(WOLFSSL* ssl, const char* file, int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_certificate_file"); + + /* Validate parameters. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 0, NULL, + GET_VERIFY_SETTING_SSL(ssl)); + /* Return 1 on success or 0 on failure. */ + ret = WS_RC(ret); + } + + return ret; +} + + +/* Load a private key from a file into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] file Name of file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +WOLFSSL_ABI +int wolfSSL_use_PrivateKey_file(WOLFSSL* ssl, const char* file, int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_PrivateKey_file"); + + /* Validate parameters. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = ProcessFile(ssl->ctx, file, format, PRIVATEKEY_TYPE, ssl, 0, NULL, + GET_VERIFY_SETTING_SSL(ssl)); + /* Return 1 on success or 0 on failure. */ + ret = WS_RC(ret); + } + + return ret; +} + + +/* Load a PEM encoded certificate chain from a file into SSL. + * + * Process up to MAX_CHAIN_DEPTH plus subject cert. + * + * @param [in, out] ssl SSL object. + * @param [in] file Name of file. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +WOLFSSL_ABI +int wolfSSL_use_certificate_chain_file(WOLFSSL* ssl, const char* file) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file"); + + /* Validate parameters. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = ProcessFile(ssl->ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, ssl, + 1, NULL, GET_VERIFY_SETTING_SSL(ssl)); + /* Return 1 on success or 0 on failure. */ + ret = WS_RC(ret); + } + + return ret; +} + +/* Load a certificate chain from a file into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] file Name of file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_use_certificate_chain_file_format(WOLFSSL* ssl, const char* file, + int format) +{ + int ret; + + /* process up to MAX_CHAIN_DEPTH plus subject cert */ + WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file_format"); + + /* Validate parameters. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 1, NULL, + GET_VERIFY_SETTING_SSL(ssl)); + /* Return 1 on success or 0 on failure. */ + ret = WS_RC(ret); + } + + return ret; +} + +#endif /* !NO_FILESYSTEM */ + +#ifdef OPENSSL_EXTRA + +#ifndef NO_FILESYSTEM +/* Load an RSA private key from a file into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] file Name of file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_use_RSAPrivateKey_file(WOLFSSL_CTX* ctx,const char* file, + int format) +{ + WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey_file"); + + return wolfSSL_CTX_use_PrivateKey_file(ctx, file, format); +} + +/* Load an RSA private key from a file into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] file Name of file. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_use_RSAPrivateKey_file(WOLFSSL* ssl, const char* file, int format) +{ + WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_file"); + + return wolfSSL_use_PrivateKey_file(ssl, file, format); +} +#endif /* NO_FILESYSTEM */ + +#endif /* OPENSSL_EXTRA */ + +/* Load a buffer of certificate/s into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] in Buffer holding certificate or private key. + * @param [in] sz Length of data in buffer in bytes. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @param [in] userChain Whether file contains chain of certificates. + * @param [in] flags Flags representing options for loading. + * @return 1 on success. + * @return 0 on failure. + * @return Negative on error. + */ +int wolfSSL_CTX_load_verify_buffer_ex(WOLFSSL_CTX* ctx, const unsigned char* in, + long sz, int format, int userChain, word32 flags) +{ + int ret; + int verify; + + WOLFSSL_ENTER("wolfSSL_CTX_load_verify_buffer_ex"); + + /* Get setting on how to verify certificates. */ + verify = GET_VERIFY_SETTING_CTX(ctx); + /* Overwrite setting when flag set. */ + if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) { + verify = VERIFY_SKIP_DATE; + } + + /* When PEM, treat as certificate chain of CA certificates. */ + if (format == WOLFSSL_FILETYPE_PEM) { + ret = ProcessChainBuffer(ctx, NULL, in, sz, CA_TYPE, verify); + } + /* When DER, load the CA certificate. */ + else { + ret = ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL, NULL, + userChain, verify); + } +#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS) + if (ret == 1) { + /* Load certificate/s as trusted peer certificate. */ + ret = wolfSSL_CTX_trust_peer_buffer(ctx, in, sz, format); + } +#endif + + WOLFSSL_LEAVE("wolfSSL_CTX_load_verify_buffer_ex", ret); + return ret; +} + +/* Load a buffer of certificate/s into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] in Buffer holding certificate or private key. + * @param [in] sz Length of data in buffer in bytes. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return Negative on error. + */ +int wolfSSL_CTX_load_verify_buffer(WOLFSSL_CTX* ctx, const unsigned char* in, + long sz, int format) +{ + return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 0, + WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); +} + +/* Load a buffer of certificate chain into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] in Buffer holding certificate chain. + * @param [in] sz Length of data in buffer in bytes. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return Negative on error. + */ +int wolfSSL_CTX_load_verify_chain_buffer_format(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz, int format) +{ + return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 1, + WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); +} + + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* Load a buffer of certificate/s into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] in Buffer holding certificate/s. + * @param [in] sz Length of data in buffer in bytes. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ctx or in is NULL, or sz is less than zero. + */ +int wolfSSL_CTX_trust_peer_buffer(WOLFSSL_CTX* ctx, const unsigned char* in, + long sz, int format) +{ + int ret; + int verify; + + WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_buffer"); + + /* Validate parameters. */ + if ((ctx == NULL) || (in == NULL) || (sz < 0)) { + ret = BAD_FUNC_ARG; + } + else { + #if WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY + verify = VERIFY_SKIP_DATE; + #else + verify = GET_VERIFY_SETTING_CTX(ctx); + #endif + + /* When PEM, treat as certificate chain of trusted peer certificates. */ + if (format == WOLFSSL_FILETYPE_PEM) { + ret = ProcessChainBuffer(ctx, NULL, in, sz, TRUSTED_PEER_TYPE, + verify); + } + /* When DER, load the trusted peer certificate. */ + else { + ret = ProcessBuffer(ctx, in, sz, format, TRUSTED_PEER_TYPE, NULL, + NULL, 0, verify); + } + } + + return ret; +} +#endif /* WOLFSSL_TRUST_PEER_CERT */ + +/* Load a certificate in a buffer into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] in Buffer holding certificate. + * @param [in] sz Size of data in bytes. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return Negative on error. + */ +int wolfSSL_CTX_use_certificate_buffer(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz, int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_buffer"); + ret = ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 0, + GET_VERIFY_SETTING_CTX(ctx)); + WOLFSSL_LEAVE("wolfSSL_CTX_use_certificate_buffer", ret); + + return ret; +} + +/* Load a private key in a buffer into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] in Buffer holding private key. + * @param [in] sz Size of data in bytes. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return Negative on error. + */ +int wolfSSL_CTX_use_PrivateKey_buffer(WOLFSSL_CTX* ctx, const unsigned char* in, + long sz, int format) +{ + int ret; + long consumed = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_buffer"); + + ret = ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL, &consumed, + 0, GET_VERIFY_SETTING_CTX(ctx)); +#ifdef WOLFSSL_DUAL_ALG_CERTS + if ((ret == 1) && (consumed < sz)) { + /* When support for dual algorithm certificates is enabled, the + * buffer may contain both the primary and the alternative + * private key. Hence, we have to parse both of them. + */ + ret = ProcessBuffer(ctx, in + consumed, sz - consumed, format, + ALT_PRIVATEKEY_TYPE, NULL, NULL, 0, GET_VERIFY_SETTING_CTX(ctx)); + } +#endif + + (void)consumed; + + WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_buffer", ret); + return ret; +} + +#ifdef WOLFSSL_DUAL_ALG_CERTS +int wolfSSL_CTX_use_AltPrivateKey_buffer(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz, int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_buffer"); + ret = ProcessBuffer(ctx, in, sz, format, ALT_PRIVATEKEY_TYPE, NULL, + NULL, 0, GET_VERIFY_SETTING_CTX(ctx)); + WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_buffer", ret); + + return ret; +} +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + +#ifdef WOLF_PRIVATE_KEY_ID +/* Load the id of a private key into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] id Buffer holding id. + * @param [in] sz Size of data in bytes. + * @param [in] devId Device identifier. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, + long sz, int devId) +{ + int ret = 1; + + /* Dispose of old private key and allocate and copy in id. */ + FreeDer(&ctx->privateKey); + if (AllocCopyDer(&ctx->privateKey, id, (word32)sz, PRIVATEKEY_TYPE, + ctx->heap) != 0) { + ret = 0; + } + if (ret == 1) { + /* Private key is an id. */ + ctx->privateKeyId = 1; + ctx->privateKeyLabel = 0; + /* Set private key device id to be one passed in or for SSL context. */ + if (devId != INVALID_DEVID) { + ctx->privateKeyDevId = devId; + } + else { + ctx->privateKeyDevId = ctx->devId; + } + + #ifdef WOLFSSL_DUAL_ALG_CERTS + /* Set the ID for the alternative key, too. User can still override that + * afterwards. */ + ret = wolfSSL_CTX_use_AltPrivateKey_id(ctx, id, sz, devId, keySz); + #endif + } + + return ret; +} + +/* Load the id of a private key into SSL context and set key size. + * + * @param [in, out] ctx SSL context object. + * @param [in] id Buffer holding id. + * @param [in] sz Size of data in bytes. + * @param [in] devId Device identifier. + * @param [in] keySz Size of key. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_use_PrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id, + long sz, int devId, long keySz) +{ + int ret = wolfSSL_CTX_use_PrivateKey_Id(ctx, id, sz, devId); + if (ret == 1) { + /* Set the key size which normally is calculated during decoding. */ + ctx->privateKeySz = (word32)keySz; + } + + return ret; +} + +/* Load the label name of a private key into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] label Buffer holding label. + * @param [in] devId Device identifier. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_use_PrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, + int devId) +{ + int ret = 1; + word32 sz = (word32)XSTRLEN(label) + 1; + + /* Dispose of old private key and allocate and copy in label. */ + FreeDer(&ctx->privateKey); + if (AllocCopyDer(&ctx->privateKey, (const byte*)label, (word32)sz, + PRIVATEKEY_TYPE, ctx->heap) != 0) { + ret = 0; + } + if (ret == 1) { + /* Private key is a label. */ + ctx->privateKeyId = 0; + ctx->privateKeyLabel = 1; + /* Set private key device id to be one passed in or for SSL context. */ + if (devId != INVALID_DEVID) { + ctx->privateKeyDevId = devId; + } + else { + ctx->privateKeyDevId = ctx->devId; + } + + #ifdef WOLFSSL_DUAL_ALG_CERTS + /* Set the ID for the alternative key, too. User can still override that + * afterwards. */ + ret = wolfSSL_CTX_use_AltPrivateKey_Label(ctx, label, devId); + #endif + } + + return ret; +} + +#ifdef WOLFSSL_DUAL_ALG_CERTS +int wolfSSL_CTX_use_AltPrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, + long sz, int devId) +{ + int ret = 1; + + if ((ctx == NULL) || (id == NULL)) { + ret = 0; + } + + if (ret == 1) { + FreeDer(&ctx->altPrivateKey); + if (AllocDer(&ctx->altPrivateKey, (word32)sz, ALT_PRIVATEKEY_TYPE, + ctx->heap) != 0) { + ret = 0; + } + } + if (ret == 1) { + XMEMCPY(ctx->altPrivateKey->buffer, id, sz); + ctx->altPrivateKeyId = 1; + if (devId != INVALID_DEVID) { + ctx->altPrivateKeyDevId = devId; + } + else { + ctx->altPrivateKeyDevId = ctx->devId; + } + } + + return ret; +} + +int wolfSSL_CTX_use_AltPrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id, + long sz, int devId, long keySz) +{ + int ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId); + if (ret == 1) { + ctx->altPrivateKeySz = (word32)keySz; + } + + return ret; +} + +int wolfSSL_CTX_use_AltPrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, + int devId) +{ + int ret = 1; + word32 sz; + + if ((ctx == NULL) || (label == NULL)) { + ret = 0; + } + + if (ret == 1) { + sz = (word32)XSTRLEN(label) + 1; + FreeDer(&ctx->altPrivateKey); + if (AllocDer(&ctx->altPrivateKey, (word32)sz, ALT_PRIVATEKEY_TYPE, + ctx->heap) != 0) { + ret = 0; + } + } + if (ret == 1) { + XMEMCPY(ctx->altPrivateKey->buffer, label, sz); + ctx->altPrivateKeyLabel = 1; + if (devId != INVALID_DEVID) { + ctx->altPrivateKeyDevId = devId; + } + else { + ctx->altPrivateKeyDevId = ctx->devId; + } + } + + return ret; +} +#endif /* WOLFSSL_DUAL_ALG_CERTS */ +#endif /* WOLF_PRIVATE_KEY_ID */ + +/* Load a certificate chain in a buffer into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] in Buffer holding DER encoded certificate chain. + * @param [in] sz Size of data in bytes. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return Negative on error. + */ +int wolfSSL_CTX_use_certificate_chain_buffer_format(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz, int format) +{ + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_buffer_format"); + return ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 1, + GET_VERIFY_SETTING_CTX(ctx)); +} + +/* Load a PEM encoded certificate chain in a buffer into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] in Buffer holding DER encoded certificate chain. + * @param [in] sz Size of data in bytes. + * @return 1 on success. + * @return 0 on failure. + * @return Negative on error. + */ +int wolfSSL_CTX_use_certificate_chain_buffer(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz) +{ + return wolfSSL_CTX_use_certificate_chain_buffer_format(ctx, in, sz, + WOLFSSL_FILETYPE_PEM); +} + +/* Load a user certificate in a buffer into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] in Buffer holding user certificate. + * @param [in] sz Size of data in bytes. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_use_certificate_buffer(WOLFSSL* ssl, const unsigned char* in, + long sz, int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_certificate_buffer"); + + /* Validate parameters. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, ssl, NULL, 0, + GET_VERIFY_SETTING_SSL(ssl)); + } + + return ret; +} + +/* Load a private key in a buffer into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] in Buffer holding private key. + * @param [in] sz Size of data in bytes. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_use_PrivateKey_buffer(WOLFSSL* ssl, const unsigned char* in, + long sz, int format) +{ + int ret; + long consumed = 0; + + WOLFSSL_ENTER("wolfSSL_use_PrivateKey_buffer"); + + /* Validate parameters. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = ProcessBuffer(ssl->ctx, in, sz, format, PRIVATEKEY_TYPE, ssl, + &consumed, 0, GET_VERIFY_SETTING_SSL(ssl)); + #ifdef WOLFSSL_DUAL_ALG_CERTS + if ((ret == 1) && (consumed < sz)) { + /* When support for dual algorithm certificates is enabled, the + * buffer may contain both the primary and the alternative + * private key. Hence, we have to parse both of them. + */ + ret = ProcessBuffer(ssl->ctx, in + consumed, sz - consumed, format, + ALT_PRIVATEKEY_TYPE, ssl, NULL, 0, GET_VERIFY_SETTING_SSL(ssl)); + } + #endif + } + + return ret; +} + +#ifdef WOLFSSL_DUAL_ALG_CERTS +int wolfSSL_use_AltPrivateKey_buffer(WOLFSSL* ssl, const unsigned char* in, + long sz, int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_AltPrivateKey_buffer"); + ret = ProcessBuffer(ssl->ctx, in, sz, format, ALT_PRIVATEKEY_TYPE, ssl, + NULL, 0, GET_VERIFY_SETTING_SSL(ssl)); + WOLFSSL_LEAVE("wolfSSL_use_AltPrivateKey_buffer", ret); + + return ret; +} +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + +#ifdef WOLF_PRIVATE_KEY_ID +/* Load the id of a private key into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] id Buffer holding id. + * @param [in] sz Size of data in bytes. + * @param [in] devId Device identifier. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_use_PrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, + long sz, int devId) +{ + int ret = 1; + + /* Dispose of old private key if owned and allocate and copy in id. */ + if (ssl->buffers.weOwnKey) { + FreeDer(&ssl->buffers.key); + } + if (AllocCopyDer(&ssl->buffers.key, id, (word32)sz, PRIVATEKEY_TYPE, + ssl->heap) != 0) { + ret = 0; + } + if (ret == 1) { + /* Buffer now ours. */ + ssl->buffers.weOwnKey = 1; + /* Private key is an id. */ + ssl->buffers.keyId = 1; + ssl->buffers.keyLabel = 0; + /* Set private key device id to be one passed in or for SSL. */ + if (devId != INVALID_DEVID) { + ssl->buffers.keyDevId = devId; + } + else { + ssl->buffers.keyDevId = ssl->devId; + } + + #ifdef WOLFSSL_DUAL_ALG_CERTS + /* Set the ID for the alternative key, too. User can still override that + * afterwards. */ + ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId); + #endif + } + + return ret; +} + +/* Load the id of a private key into SSL and set key size. + * + * @param [in, out] ssl SSL object. + * @param [in] id Buffer holding id. + * @param [in] sz Size of data in bytes. + * @param [in] devId Device identifier. + * @param [in] keySz Size of key. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_use_PrivateKey_id(WOLFSSL* ssl, const unsigned char* id, + long sz, int devId, long keySz) +{ + int ret = wolfSSL_use_PrivateKey_Id(ssl, id, sz, devId); + if (ret == 1) { + /* Set the key size which normally is calculated during decoding. */ + ssl->buffers.keySz = (word32)keySz; + } + + return ret; +} + +/* Load the label name of a private key into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] label Buffer holding label. + * @param [in] devId Device identifier. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_use_PrivateKey_Label(WOLFSSL* ssl, const char* label, int devId) +{ + int ret = 1; + word32 sz = (word32)XSTRLEN(label) + 1; + + /* Dispose of old private key if owned and allocate and copy in label. */ + if (ssl->buffers.weOwnKey) { + FreeDer(&ssl->buffers.key); + } + if (AllocCopyDer(&ssl->buffers.key, (const byte*)label, (word32)sz, + PRIVATEKEY_TYPE, ssl->heap) != 0) { + ret = 0; + } + if (ret == 1) { + /* Buffer now ours. */ + ssl->buffers.weOwnKey = 1; + /* Private key is a label. */ + ssl->buffers.keyId = 0; + ssl->buffers.keyLabel = 1; + /* Set private key device id to be one passed in or for SSL. */ + if (devId != INVALID_DEVID) { + ssl->buffers.keyDevId = devId; + } + else { + ssl->buffers.keyDevId = ssl->devId; + } + + #ifdef WOLFSSL_DUAL_ALG_CERTS + /* Set the label for the alternative key, too. User can still override + * that afterwards. */ + ret = wolfSSL_use_AltPrivateKey_Label(ssl, label, devId); + #endif + } + + return ret; +} + +#ifdef WOLFSSL_DUAL_ALG_CERTS +int wolfSSL_use_AltPrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, long sz, + int devId) +{ + int ret = 1; + + if ((ssl == NULL) || (id == NULL)) { + ret = 0; + } + + if (ret == 1) { + if (ssl->buffers.weOwnAltKey) { + FreeDer(&ssl->buffers.altKey); + } + if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE, + ssl->heap) == 0) { + ret = 0; + } + } + if (ret == 1) { + XMEMCPY(ssl->buffers.altKey->buffer, id, sz); + ssl->buffers.weOwnAltKey = 1; + ssl->buffers.altKeyId = 1; + if (devId != INVALID_DEVID) { + ssl->buffers.altKeyDevId = devId; + } + else { + ssl->buffers.altKeyDevId = ssl->devId; + } + } + + return ret; +} + +int wolfSSL_use_AltPrivateKey_id(WOLFSSL* ssl, const unsigned char* id, long sz, + int devId, long keySz) +{ + int ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId); + if (ret == 1) { + ssl->buffers.altKeySz = (word32)keySz; + } + + return ret; +} + +int wolfSSL_use_AltPrivateKey_Label(WOLFSSL* ssl, const char* label, int devId) +{ + int ret = 1; + word32 sz; + + if ((ssl == NULL) || (label == NULL)) { + ret = 0; + } + + if (ret == 1) { + sz = (word32)XSTRLEN(label) + 1; + if (ssl->buffers.weOwnAltKey) + FreeDer(&ssl->buffers.altKey); + if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE, + ssl->heap) == 0) { + ret = 0; + } + } + if (ret == 1) { + XMEMCPY(ssl->buffers.altKey->buffer, label, sz); + ssl->buffers.weOwnAltKey = 1; + ssl->buffers.altKeyLabel = 1; + if (devId != INVALID_DEVID) { + ssl->buffers.altKeyDevId = devId; + } + else { + ssl->buffers.altKeyDevId = ssl->devId; + } + } + + return ret; +} +#endif /* WOLFSSL_DUAL_ALG_CERTS */ +#endif /* WOLF_PRIVATE_KEY_ID */ + +/* Load a certificate chain in a buffer into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] in Buffer holding DER encoded certificate chain. + * @param [in] sz Size of data in bytes. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_use_certificate_chain_buffer_format(WOLFSSL* ssl, + const unsigned char* in, long sz, int format) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format"); + + /* Validate parameters. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, ssl, NULL, 1, + GET_VERIFY_SETTING_SSL(ssl)); + } + + return ret; +} + +/* Load a PEM encoded certificate chain in a buffer into SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] in Buffer holding DER encoded certificate chain. + * @param [in] sz Size of data in bytes. + * @return 1 on success. + * @return 0 on failure. + * @return Negative on error. + */ +int wolfSSL_use_certificate_chain_buffer(WOLFSSL* ssl, const unsigned char* in, + long sz) +{ + return wolfSSL_use_certificate_chain_buffer_format(ssl, in, sz, + WOLFSSL_FILETYPE_PEM); +} + +#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ + defined(WOLFSSL_HAPROXY) +/* Add certificate to chain. + * + * @param [in, out] chain Buffer holding encoded certificate for TLS. + * @param [in] weOwn Indicates we need to free chain if repleced. + * @param [in] cert Buffer holding DER encoded certificate. + * @param [in] certSz Size of DER encoded certificate in bytes. + * @param [in] heap Dynamic memory allocation hint. + * @return 1 on success. + * @return 0 on failure. + */ +static int wolfssl_add_to_chain(DerBuffer** chain, int weOwn, const byte* cert, + word32 certSz, void* heap) +{ + int res = 1; + int ret; + DerBuffer* oldChain = *chain; + DerBuffer* newChain = NULL; + word32 len = 0; + + if (oldChain != NULL) { + /* Get length of previous chain. */ + len = oldChain->length; + } + /* Allocate DER buffer bug enough to hold old and new certificates. */ + ret = AllocDer(&newChain, len + CERT_HEADER_SZ + certSz, CERT_TYPE, heap); + if (ret != 0) { + WOLFSSL_MSG("AllocDer error"); + res = 0; + } + + if (res == 1) { + if (oldChain != NULL) { + /* Place old chain in new buffer. */ + XMEMCPY(newChain->buffer, oldChain->buffer, len); + } + /* Append length and DER encoded certificate. */ + c32to24(certSz, newChain->buffer + len); + XMEMCPY(newChain->buffer + len + CERT_HEADER_SZ, cert, certSz); + + /* Dispose of old chain if we own it. */ + if (weOwn) { + FreeDer(chain); + } + /* Replace chain. */ + *chain = newChain; + } + + return res; +} +#endif + +#ifdef OPENSSL_EXTRA + +/* Add a certificate to end of chain sent in TLS handshake. + * + * @param [in, out] ctx SSL context. + * @param [in] der Buffer holding DER encoded certificate. + * @param [in] derSz Size of data in buffer. + * @return 1 on success. + * @return 0 on failure. + */ +static int wolfssl_ctx_add_to_chain(WOLFSSL_CTX* ctx, const byte* der, + int derSz) +{ + int res = 1; + int ret; + DerBuffer* derBuffer = NULL; + + /* Create a DER buffer from DER encoding. */ + ret = AllocCopyDer(&derBuffer, der, derSz, CERT_TYPE, ctx->heap); + if (ret != 0) { + WOLFSSL_MSG("Memory Error"); + res = 0; + } + if (res == 1) { + /* Add a user CA certificate to the certificate manager. */ + res = AddCA(ctx->cm, &derBuffer, WOLFSSL_USER_CA, + GET_VERIFY_SETTING_CTX(ctx)); + if (res != 1) { + res = 0; + } + } + + if (res == 1) { + /* Add chain to DER buffer. */ + res = wolfssl_add_to_chain(&ctx->certChain, 1, der, derSz, ctx->heap); + #ifdef WOLFSSL_TLS13 + /* Update count of certificates. */ + ctx->certChainCnt++; + #endif + } + + return res; +} + +/* Add a certificate to chain sent in TLS handshake. + * + * @param [in, out] ctx SSL context. + * @param [in] x509 X509 certificate object. + * @return 1 on success. + * @return 0 on failure. + */ +long wolfSSL_CTX_add_extra_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) +{ + int ret = 1; + int derSz = 0; + const byte* der = NULL; + + WOLFSSL_ENTER("wolfSSL_CTX_add_extra_chain_cert"); + + /* Validate parameters. */ + if ((ctx == NULL) || (x509 == NULL)) { + WOLFSSL_MSG("Bad Argument"); + ret = 0; + } + + if (ret == 1) { + /* Get the DER encoding of the certificate from the X509 object. */ + der = wolfSSL_X509_get_der(x509, &derSz); + /* Validate buffer. */ + if ((der == NULL) || (derSz <= 0)) { + WOLFSSL_MSG("Error getting X509 DER"); + ret = 0; + } + } + + if ((ret == 1) && (ctx->certificate == NULL)) { + WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format"); + + /* Process buffer makes first certificate the leaf. */ + ret = ProcessBuffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, + NULL, NULL, 1, GET_VERIFY_SETTING_CTX(ctx)); + if (ret != 1) { + ret = 0; + } + } + else if (ret == 1) { + /* Add certificate to existing chain. */ + ret = wolfssl_ctx_add_to_chain(ctx, der, derSz); + } + + if (ret == 1) { + /* On success WOLFSSL_X509 memory is responsibility of SSL context. */ + wolfSSL_X509_free(x509); + } + + WOLFSSL_LEAVE("wolfSSL_CTX_add_extra_chain_cert", ret); + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ + defined(WOLFSSL_HAPROXY) +/* Load a certificate into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] x509 X509 certificate object. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_use_certificate(WOLFSSL_CTX *ctx, WOLFSSL_X509 *x) +{ + int res = 1; + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate"); + + /* Validate parameters. */ + if ((ctx == NULL) || (x == NULL) || (x->derCert == NULL)) { + WOLFSSL_MSG("Bad parameter"); + res = 0; + } + + if (res == 1) { + /* Replace certificate buffer with one holding the new certificate. */ + FreeDer(&ctx->certificate); + ret = AllocCopyDer(&ctx->certificate, x->derCert->buffer, + x->derCert->length, CERT_TYPE, ctx->heap); + if (ret != 0) { + res = 0; + } + } + +#ifdef KEEP_OUR_CERT + if (res == 1) { + /* Dispose of our certificate if it is ours. */ + if ((ctx->ourCert != NULL) && ctx->ownOurCert) { + wolfSSL_X509_free(ctx->ourCert); + } + #ifndef WOLFSSL_X509_STORE_CERTS + /* Keep a reference to the new certificate. */ + ctx->ourCert = x; + if (wolfSSL_X509_up_ref(x) != 1) { + res = 0; + } + #else + /* Keep a copy of the new certificate. */ + ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, x->derCert->buffer, + x->derCert->length, ctx->heap); + if (ctx->ourCert == NULL) { + res = 0; + } + #endif + /* Now own our certificate. */ + ctx->ownOurCert = 1; + } +#endif + + if (res == 1) { + /* Set have options based on public key OID. */ + wolfssl_set_have_from_key_oid(ctx, NULL, x->pubKeyOID); + } + + return res; +} + +/* Add the certificate to the chain in the SSL context and own the X509 object. + * + * @param [in, out] ctx SSL context object. + * @param [in] x509 X509 certificate object. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_add0_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_add0_chain_cert"); + + /* Add certificate to chain and copy or up reference it. */ + ret = wolfSSL_CTX_add1_chain_cert(ctx, x509); + if (ret == 1) { + /* Down reference or free original now as we own certificate. */ + wolfSSL_X509_free(x509); + } + + return ret; +} + +/* Add the certificate to the chain in the SSL context. + * + * X509 object copied or up referenced. + * + * @param [in, out] ctx SSL context object. + * @param [in] x509 X509 certificate object. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_add1_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_CTX_add1_chain_cert"); + + /* Validate parameters. */ + if ((ctx == NULL) || (x509 == NULL) || (x509->derCert == NULL)) { + ret = 0; + } + + /* Check if we already have set a certificate. */ + if ((ret == 1) && (ctx->certificate == NULL)) { + /* Use the certificate. */ + ret = wolfSSL_CTX_use_certificate(ctx, x509); + } + /* Increate reference count as we will store it. */ + else if ((ret == 1) && ((ret = wolfSSL_X509_up_ref(x509)) == 1)) { + /* Load the DER encoding. */ + ret = wolfSSL_CTX_load_verify_buffer(ctx, x509->derCert->buffer, + x509->derCert->length, WOLFSSL_FILETYPE_ASN1); + if (ret == 1) { + /* Add DER encoding to chain. */ + ret = wolfssl_add_to_chain(&ctx->certChain, 1, + x509->derCert->buffer, x509->derCert->length, ctx->heap); + } + /* Store cert in stack to free it later. */ + if ((ret == 1) && (ctx->x509Chain == NULL)) { + /* Create a stack for certificates. */ + ctx->x509Chain = wolfSSL_sk_X509_new_null(); + if (ctx->x509Chain == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_new_null error"); + ret = 0; + } + } + if (ret == 1) { + /* Push the X509 object onto stack. */ + ret = wolfSSL_sk_X509_push(ctx->x509Chain, x509); + } + + if (ret != 1) { + /* Decrease reference count on error as we didn't store it. */ + wolfSSL_X509_free(x509); + } + } + + return WS_RC(ret); +} + +#ifdef KEEP_OUR_CERT +/* Add the certificate to the chain in the SSL and own the X509 object. + * + * @param [in, out] ssl SSL object. + * @param [in] x509 X509 certificate object. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_add0_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_add0_chain_cert"); + + /* Validate parameters. */ + if ((ssl == NULL) || (ssl->ctx == NULL) || (x509 == NULL) || + (x509->derCert == NULL)) { + ret = 0; + } + + /* Check if we already have set a certificate. */ + if ((ret == 1) && (ssl->buffers.certificate == NULL)) { + /* Use the certificate. */ + ret = wolfSSL_use_certificate(ssl, x509); + if (ret == 1) { + /* Dispose of old certificate if we own it. */ + if (ssl->buffers.weOwnCert) { + wolfSSL_X509_free(ssl->ourCert); + } + /* Store cert to free it later. */ + ssl->ourCert = x509; + ssl->buffers.weOwnCert = 1; + } + } + else if (ret == 1) { + /* Add DER encoding to chain. */ + ret = wolfssl_add_to_chain(&ssl->buffers.certChain, + ssl->buffers.weOwnCertChain, x509->derCert->buffer, + x509->derCert->length, ssl->heap); + if (ret == 1) { + /* We now own cert chain. */ + ssl->buffers.weOwnCertChain = 1; + /* Create a stack to put certificate into. */ + if (ssl->ourCertChain == NULL) { + ssl->ourCertChain = wolfSSL_sk_X509_new_null(); + if (ssl->ourCertChain == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_new_null error"); + ret = 0; + } + } + } + if (ret == 1) { + /* Push X509 object onto stack to be freed. */ + ret = wolfSSL_sk_X509_push(ssl->ourCertChain, x509); + if (ret != 1) { + /* Free it now on error. */ + wolfSSL_X509_free(x509); + } + } + } + return WS_RC(ret); +} + +/* Add the certificate to the chain in the SSL. + * + * X509 object is up referenced. + * + * @param [in, out] ssl SSL object. + * @param [in] x509 X509 certificate object. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_add1_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_add1_chain_cert"); + + /* Validate parameters. */ + if ((ssl == NULL) || (ssl->ctx == NULL) || (x509 == NULL) || + (x509->derCert == NULL)) { + ret = 0; + } + + /* Increase reference count on X509 object before adding. */ + if ((ret == 1) && ((ret == wolfSSL_X509_up_ref(x509)) == 1)) { + /* Add this to the chain. */ + if ((ret = wolfSSL_add0_chain_cert(ssl, x509)) != 1) { + /* Decrease reference count on error as not stored. */ + wolfSSL_X509_free(x509); + } + } + + return ret; +} +#endif /* KEEP_OUR_CERT */ +#endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL, + WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY */ + +#ifdef OPENSSL_EXTRA + +/* Load a private key into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] pkey EVP private key. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey"); + + /* Validate parameters. */ + if ((ctx == NULL) || (pkey == NULL) || (pkey->pkey.ptr == NULL)) { + ret = 0; + } + + if (ret == 1) { + switch (pkey->type) { + #if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) + case EVP_PKEY_RSA: + WOLFSSL_MSG("populating RSA key"); + ret = PopulateRSAEvpPkeyDer(pkey); + break; + #endif /* (WOLFSSL_KEY_GEN || OPENSSL_EXTRA) && !NO_RSA */ + #if !defined(HAVE_SELFTEST) && (defined(WOLFSSL_KEY_GEN) || \ + defined(WOLFSSL_CERT_GEN)) && !defined(NO_DSA) + case EVP_PKEY_DSA: + break; + #endif /* !HAVE_SELFTEST && (WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN) && + * !NO_DSA */ + #ifdef HAVE_ECC + case EVP_PKEY_EC: + WOLFSSL_MSG("populating ECC key"); + ret = ECC_populate_EVP_PKEY(pkey, pkey->ecc); + break; + #endif + default: + ret = 0; + } + } + + if (ret == 1) { + /* ptr for WOLFSSL_EVP_PKEY struct is expected to be DER format */ + ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, + (const unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, + SSL_FILETYPE_ASN1); + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) +/* Load a DER encoded certificate in a buffer into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] der Buffer holding DER encoded certificate. + * @param [in] derSz Size of data in bytes. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_use_certificate_ASN1(WOLFSSL_CTX *ctx, int derSz, + const unsigned char *der) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_ASN1"); + + /* Validate parameters. */ + if ((ctx == NULL) || (der == NULL)) { + ret = 0; + } + /* Load DER encoded cerificate into SSL context. */ + if ((ret == 1) && (wolfSSL_CTX_use_certificate_buffer(ctx, der, derSz, + WOLFSSL_FILETYPE_ASN1) != 1)) { + ret = 0; + } + + return ret; +} + +#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) +/* Load an RSA private key into SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] rsa RSA private key. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ctx or rsa is NULL. + * @return MEMORY_E when dynamic memory allocation fails. + */ +int wolfSSL_CTX_use_RSAPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL_RSA* rsa) +{ + int ret = 1; + int derSize; + unsigned char* der = NULL; + unsigned char* p; + + WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey"); + + /* Validate parameters. */ + if ((ctx == NULL) || (rsa == NULL)) { + WOLFSSL_MSG("one or more inputs were NULL"); + ret = BAD_FUNC_ARG; + } + + /* Get DER encoding size. */ + if ((ret == 1) && ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, NULL)) <= 0)) { + ret = 0; + } + + if (ret == 1) { + /* Allocate memory to hold DER encoding.. */ + der = (unsigned char*)XMALLOC(derSize, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (der == NULL) { + WOLFSSL_MSG("Malloc failure"); + ret = MEMORY_E; + } + } + + if (ret == 1) { + /* Pointer passed in is modified.. */ + p = der; + /* Encode the RSA key as DER into buffer and get size. */ + if ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, &p)) <= 0) { + WOLFSSL_MSG("wolfSSL_i2d_RSAPrivateKey() failure"); + ret = 0; + } + } + + if (ret == 1) { + /* Load DER encoded cerificate into SSL context. */ + ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSize, + SSL_FILETYPE_ASN1); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_CTX_USE_PrivateKey_buffer() failure"); + ret = 0; + } + } + + /* Dispos of dynamically allocated data. */ + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} +#endif /* WOLFSSL_KEY_GEN && !NO_RSA */ + +#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ + +#endif /* !NO_CERTS */ + +#ifdef OPENSSL_EXTRA + +#ifdef WOLFSSL_SYS_CA_CERTS + +/* Use the default paths to look for CA certificate. + * + * This is an OpenSSL compatibility layer function, but it doesn't mirror + * the exact functionality of its OpenSSL counterpart. We don't support the + * notion of an "OpenSSL directory". This function will attempt to load the + * environment variables SSL_CERT_DIR and SSL_CERT_FILE, if either are + * found, they will be loaded. Otherwise, it will act as a wrapper around + * our native wolfSSL_CTX_load_system_CA_certs function. This function does + * conform to OpenSSL's return value conventions. + * + * @param [in] ctx SSL context object. + * @return 1 on success. + * @return 0 on failure. + * @return WOLFSSL_FATAL_ERROR when using a filesystem is not supported. + */ +int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx) +{ + int ret; +#ifdef XGETENV + char* certDir; + char* certFile; + word32 flags; +#endif + + WOLFSSL_ENTER("wolfSSL_CTX_set_default_verify_paths"); + +#ifdef XGETENV + certDir = XGETENV("SSL_CERT_DIR"); + certFile = XGETENV("SSL_CERT_FILE"); + flags = WOLFSSL_LOAD_FLAG_PEM_CA_ONLY; + + if ((certDir != NULL) || (certFile != NULL)) { + if (certDir != NULL) { + /* We want to keep trying to load more CA certs even if one cert in + * the directory is bad and can't be used (e.g. if one is + * expired), so we use WOLFSSL_LOAD_FLAG_IGNORE_ERR. + */ + flags |= WOLFSSL_LOAD_FLAG_IGNORE_ERR; + } + + /* Load CA certificates from environment variable locations. */ + ret = wolfSSL_CTX_load_verify_locations_ex(ctx, certFile, certDir, + flags); + if (ret != 1) { + WOLFSSL_MSG_EX("Failed to load CA certs from SSL_CERT_FILE: %s" + " SSL_CERT_DIR: %s. Error: %d", certFile, + certDir, ret); + ret = 0; + } + } + else +#endif + + { + #ifdef NO_FILESYSTEM + WOLFSSL_MSG("wolfSSL_CTX_set_default_verify_paths not supported" + " with NO_FILESYSTEM enabled"); + ret = WOLFSSL_FATAL_ERROR; + #else + /* Load the system CA certificates. */ + ret = wolfSSL_CTX_load_system_CA_certs(ctx); + if (ret == WOLFSSL_BAD_PATH) { + /* OpenSSL doesn't treat the lack of a system CA cert directory as a + * failure. We do the same here. + */ + ret = 1; + } + #endif + } + + WOLFSSL_LEAVE("wolfSSL_CTX_set_default_verify_paths", ret); + + return ret; +} + +#endif /* WOLFSSL_SYS_CA_CERTS */ + +#endif /* OPENSSL_EXTRA */ + +#ifndef NO_DH + +/* Set the temporary DH parameters against the SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] p Buffer holding prime. + * @param [in] pSz Length of prime in bytes. + * @param [in] g Buffer holding generator. + * @param [in] gSz Length of generator in bytes. + * @return 1 on success. + * @return 0 on failure. + * @return DH_KEY_SIZE_E when the prime is too short or long. + * @return SIDE_ERROR when the SSL is for a client. + */ +static int wolfssl_set_tmp_dh(WOLFSSL* ssl, unsigned char* p, int pSz, + unsigned char* g, int gSz) +{ + int ret = 1; + + /* Check the size of the prime meets the requirements of the SSL. */ + if (((word16)pSz < ssl->options.minDhKeySz) || + ((word16)pSz > ssl->options.maxDhKeySz)) { + ret = DH_KEY_SIZE_E; + } + /* Only able to set DH parameters on server. */ + if ((ret == 1) && (ssl->options.side == WOLFSSL_CLIENT_END)) { + ret = SIDE_ERROR; + } + + if (ret == 1) { + #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + /* New DH parameters not tested for validity. */ + ssl->options.dhKeyTested = 0; + /* New DH parameters must be tested for validity before use. */ + ssl->options.dhDoKeyTest = 1; + #endif + + /* Dispose of old DH parameters if we own it. */ + if (ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + } + + /* Assign the buffers and lengths to SSL. */ + ssl->buffers.serverDH_P.buffer = p; + ssl->buffers.serverDH_G.buffer = g; + ssl->buffers.serverDH_P.length = pSz; + ssl->buffers.serverDH_G.length = gSz; + /* We own the buffers. */ + ssl->buffers.weOwnDH = 1; + /* We have a DH parameters to use. */ + ssl->options.haveDH = 1; + } + + /* Allocate space for cipher suites. */ + if ((ret == 1) && (AllocateSuites(ssl) != 0)) { + ret = 0; + } + if (ret == 1) { + /* Reset the cipher suites based on having a DH parameters now. */ + InitSuites(ssl->suites, ssl->version, SSL_KEY_SZ(ssl), + WOLFSSL_HAVE_RSA, SSL_HAVE_PSK(ssl), ssl->options.haveDH, + ssl->options.haveECDSAsig, ssl->options.haveECC, TRUE, + ssl->options.haveStaticECC, ssl->options.haveFalconSig, + ssl->options.haveDilithiumSig, ssl->options.useAnon, TRUE, + ssl->options.side); + } + + return ret; +} + +/* Set the temporary DH parameters against the SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] p Buffer holding prime. + * @param [in] pSz Length of prime in bytes. + * @param [in] g Buffer holding generator. + * @param [in] gSz Length of generator in bytes. + * @return 1 on success. + * @return 0 on failure. + * @return DH_KEY_SIZE_E when the prime is too short or long. + * @return SIDE_ERROR when the SSL is for a client. + * @return MEMORY_E when dynamic memory allocation fails. + */ +int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz, + const unsigned char* g, int gSz) +{ + int ret = 1; + byte* pAlloc = NULL; + byte* gAlloc = NULL; + + WOLFSSL_ENTER("wolfSSL_SetTmpDH"); + + /* Validate parameters. */ + if ((ssl == NULL) || (p == NULL) || (g == NULL)) { + ret = 0; + } + + if (ret == 1) { + /* Allocate buffers for p and g to be assigned into SSL. */ + pAlloc = (byte*)XMALLOC(pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + gAlloc = (byte*)XMALLOC(gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if ((pAlloc == NULL) || (gAlloc == NULL)) { + XFREE(pAlloc, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(gAlloc, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ret = MEMORY_E; + } + } + if (ret == 1) { + /* Copy p and g into allocated buffers. */ + XMEMCPY(pAlloc, p, pSz); + XMEMCPY(gAlloc, g, gSz); + /* Set the buffers into SSL. */ + ret = wolfssl_set_tmp_dh(ssl, pAlloc, pSz, gAlloc, gSz); + } + + if (ret != 1) { + /* Free the allocated buffers if not assigned into SSL. */ + XFREE(pAlloc, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(gAlloc, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + + WOLFSSL_LEAVE("wolfSSL_SetTmpDH", ret); + return ret; +} + +#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) +/* Check the DH parameters is valid. + * + * @param [in] p Buffer holding prime. + * @param [in] pSz Length of prime in bytes. + * @param [in] g Buffer holding generator. + * @param [in] gSz Length of generator in bytes. + * @return 1 on success. + * @return DH_CHECK_PUB_E when p is not a prime. + * @return BAD_FUNC_ARG when p or g is NULL, or pSz or gSz is 0. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int wolfssl_check_dh_key(unsigned char* p, int pSz, unsigned char* g, + int gSz) +{ + WC_RNG rng; + int ret = 0; +#ifndef WOLFSSL_SMALL_STACK + DhKey checkKey[1]; +#else + DhKey *checkKey; +#endif + +#ifdef WOLFSSL_SMALL_STACK + checkKey = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); + if (checkKey == NULL) { + ret = MEMORY_E; + } +#endif + /* Initialize a new random number generator. */ + if ((ret == 0) && ((ret = wc_InitRng(&rng)) == 0)) { + /* Initialize a DH object. */ + if ((ret = wc_InitDhKey(checkKey)) == 0) { + /* Check DH parameters. */ + ret = wc_DhSetCheckKey(checkKey, p, pSz, g, gSz, NULL, 0, 0, &rng); + /* Dispose of DH object. */ + wc_FreeDhKey(checkKey); + } + /* Dispose of random number generator. */ + wc_FreeRng(&rng); + } + +#ifdef WOLFSSL_SMALL_STACK + /* Dispose of dynamically allocated data. */ + XFREE(checkKey, NULL, DYNAMIC_TYPE_DH); +#endif + /* Convert wolfCrypt return code to 1 on success and ret on failure. */ + return WC_TO_WS_RC(ret); +} +#endif + +/* Set the temporary DH parameters against the SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] p Buffer holding prime. + * @param [in] pSz Length of prime in bytes. + * @param [in] g Buffer holding generator. + * @param [in] gSz Length of generator in bytes. + * @return 1 on success. + * @return 0 on failure. + * @return DH_KEY_SIZE_E when the prime is too short or long. + * @return SIDE_ERROR when the SSL is for a client. + * @return BAD_FUNC_ARG when ctx, p or g is NULL. + * @return DH_CHECK_PUB_E when p is not a prime. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int wolfssl_ctx_set_tmp_dh(WOLFSSL_CTX* ctx, unsigned char* p, int pSz, + unsigned char* g, int gSz) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_CTX_SetTmpDH"); + + /* Check the size of the prime meets the requirements of the SSL context. */ + if (((word16)pSz < ctx->minDhKeySz) || ((word16)pSz > ctx->maxDhKeySz)) { + ret = DH_KEY_SIZE_E; + } + +#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + if (ret == 1) { + /* Test DH parameters for validity. */ + ret = wolfssl_check_dh_key(p, pSz, g, gSz); + /* Record as whether tested based on result of validity test. */ + ctx->dhKeyTested = (ret == 1); + } +#endif + + if (ret == 1) { + /* Dispose of old DH parameters. */ + XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + /* Assign the buffers and lengths to SSL context. */ + ctx->serverDH_P.buffer = p; + ctx->serverDH_G.buffer = g; + ctx->serverDH_P.length = pSz; + ctx->serverDH_G.length = gSz; + /* We have a DH parameters to use. */ + ctx->haveDH = 1; + } + + WOLFSSL_LEAVE("wolfSSL_CTX_SetTmpDH", 0); + return ret; +} + +/* Set the temporary DH parameters against the SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] p Buffer holding prime. + * @param [in] pSz Length of prime in bytes. + * @param [in] g Buffer holding generator. + * @param [in] gSz Length of generator in bytes. + * @return 1 on success. + * @return 0 on failure. + * @return DH_KEY_SIZE_E when the prime is too short or long. + * @return SIDE_ERROR when the SSL is for a client. + * @return BAD_FUNC_ARG when ctx, p or g is NULL. + * @return DH_CHECK_PUB_E when p is not a prime. + */ +int wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX* ctx, const unsigned char* p, int pSz, + const unsigned char* g, int gSz) +{ + int ret = 1; + byte* pAlloc = NULL; + byte* gAlloc = NULL; + + /* Validate parameters. */ + if ((ctx == NULL) || (p == NULL) || (g == NULL)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 1) { + /* Allocate buffers for p and g to be assigned into SSL context. */ + pAlloc = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + gAlloc = (byte*)XMALLOC(gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if ((pAlloc == NULL) || (gAlloc == NULL)) { + XFREE(pAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(gAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ret = MEMORY_E; + } + } + + if (ret == 1) { + /* Copy p and g into allocated buffers. */ + XMEMCPY(pAlloc, p, pSz); + XMEMCPY(gAlloc, g, gSz); + /* Set the buffers into SSL context. */ + ret = wolfssl_ctx_set_tmp_dh(ctx, pAlloc, pSz, gAlloc, gSz); + } + + if (ret != 1) { + /* Free the allocated buffers if not assigned into SSL context. */ + XFREE(pAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(gAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + return ret; +} + +#ifdef OPENSSL_EXTRA +/* Set the temporary DH parameters against the SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] dh DH object. + * @return 1 on success. + * @return 0 on failure. + * @return WOLFSSL_FATAL_ERROR on failure. + * @return BAD_FUNC_ARG when ssl or dh is NULL. + * @return DH_KEY_SIZE_E when the prime is too short or long. + * @return SIDE_ERROR when the SSL is for a client. + */ +long wolfSSL_set_tmp_dh(WOLFSSL *ssl, WOLFSSL_DH *dh) +{ + int ret = 1; + byte* p = NULL; + byte* g = NULL; + int pSz = 0; + int gSz = 0; + + WOLFSSL_ENTER("wolfSSL_set_tmp_dh"); + + /* Validate parameters. */ + if ((ssl == NULL) || (dh == NULL)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 1) { + /* Get needed size for p and g. */ + pSz = wolfSSL_BN_bn2bin(dh->p, NULL); + gSz = wolfSSL_BN_bn2bin(dh->g, NULL); + /* Validate p and g size. */ + if ((pSz <= 0) || (gSz <= 0)) { + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 1) { + /* Allocate buffers for p and g to be assigned into SSL. */ + p = (byte*)XMALLOC(pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + g = (byte*)XMALLOC(gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if ((p == NULL) || (g == NULL)) { + ret = MEMORY_E; + } + } + if (ret == 1) { + /* Encode p and g and get sizes. */ + pSz = wolfSSL_BN_bn2bin(dh->p, p); + gSz = wolfSSL_BN_bn2bin(dh->g, g); + /* Check encoding worked. */ + if ((pSz <= 0) || (gSz <= 0)) { + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Set the buffers into SSL. */ + ret = wolfssl_set_tmp_dh(ssl, p, pSz, g, gSz); + } + + if (ret != 1) { + /* Free the allocated buffers if not assigned into SSL. */ + XFREE(p, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + return ret; +} + +/* Set the temporary DH parameters object against the SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] dh DH object. + * @return 1 on success. + * @return 0 on failure. + * @return DH_KEY_SIZE_E when the prime is too short or long. + * @return SIDE_ERROR when the SSL is for a client. + * @return BAD_FUNC_ARG when ctx, p or g is NULL. + * @return DH_CHECK_PUB_E when p is not a prime. + */ +long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL_DH* dh) +{ + int ret = 1; + int pSz = 0; + int gSz = 0; + byte* p = NULL; + byte* g = NULL; + + WOLFSSL_ENTER("wolfSSL_CTX_set_tmp_dh"); + + /* Validate parameters. */ + if ((ctx == NULL) || (dh == NULL)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 1) { + /* Get needed size for p and g. */ + pSz = wolfSSL_BN_bn2bin(dh->p, NULL); + gSz = wolfSSL_BN_bn2bin(dh->g, NULL); + /* Validate p and g size. */ + if ((pSz <= 0) || (gSz <= 0)) { + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 1) { + /* Allocate buffers for p and g to be assigned into SSL. */ + p = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + g = (byte*)XMALLOC(gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if ((p == NULL) || (g == NULL)) { + ret = MEMORY_E; + } + } + + if (ret == 1) { + /* Encode p and g and get sizes. */ + pSz = wolfSSL_BN_bn2bin(dh->p, p); + gSz = wolfSSL_BN_bn2bin(dh->g, g); + /* Check encoding worked. */ + if ((pSz < 0) && (gSz < 0)) { + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Set the buffers into SSL context. */ + ret = wolfssl_ctx_set_tmp_dh(ctx, p, pSz, g, gSz); + } + + if (ret != 1) { + /* Free the allocated buffers if not assigned into SSL. */ + XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +#ifndef NO_CERTS + +/* Set the temporary DH parameters against the SSL context or SSL. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @oaram [in] buf Buffer holding encoded DH parameters. + * @param [in] sz Size of encoded DH parameters. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return 0 on failure. + * @return BAD_FUNC_ARG when ctx and ssl NULL or buf is NULL. + * @return NOT_COMPLED_IN when format is PEM but PEM is not supported. + * @return WOLFSSL_BAD_FILETYPE if format is not supported. + */ +static int ws_ctx_ssl_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + const unsigned char* buf, long sz, int format) +{ + DerBuffer* der = NULL; + int res = 1; + int ret; + /* p and g size to allocate set to maximum valid size. */ + word32 pSz = MAX_DH_SIZE; + word32 gSz = MAX_DH_SIZE; + byte* p = NULL; + byte* g = NULL; + void* heap = WOLFSSL_HEAP(ctx, ssl); + + /* Validate parameters. */ + if (((ctx == NULL) && (ssl == NULL)) || (buf == NULL)) { + res = BAD_FUNC_ARG; + } + /* Check format is supported. */ + if ((res == 1) && (format != WOLFSSL_FILETYPE_ASN1)) { + if (format != WOLFSSL_FILETYPE_PEM) { + res = WOLFSSL_BAD_FILETYPE; + } + #ifndef WOLFSSL_PEM_TO_DER + else { + res = NOT_COMPILED_IN; + } + #endif + } + + /* PemToDer allocates its own DER buffer. */ + if ((res == 1) && (format != WOLFSSL_FILETYPE_PEM)) { + /* Create an empty DER buffer. */ + ret = AllocDer(&der, 0, DH_PARAM_TYPE, heap); + if (ret == 0) { + /* Assign encoded DH parameters to DER buffer. */ + der->buffer = (byte*)buf; + der->length = (word32)sz; + } + else { + res = ret; + } + } + + if (res == 1) { + /* Allocate enough memory to p and g to support valid use cases. */ + p = (byte*)XMALLOC(pSz, heap, DYNAMIC_TYPE_PUBLIC_KEY); + g = (byte*)XMALLOC(gSz, heap, DYNAMIC_TYPE_PUBLIC_KEY); + if ((p == NULL) || (g == NULL)) { + res = MEMORY_E; + } + } + +#ifdef WOLFSSL_PEM_TO_DER + if ((res == 1) && (format == WOLFSSL_FILETYPE_PEM)) { + /* Convert from PEM to DER. */ + /* Try converting DH parameters from PEM to DER. */ + ret = PemToDer(buf, sz, DH_PARAM_TYPE, &der, heap, NULL, NULL); + if (ret < 0) { + /* Otherwise, try converting X9.43 format DH parameters. */ + ret = PemToDer(buf, sz, X942_PARAM_TYPE, &der, heap, NULL, NULL); + } + #if defined(WOLFSSL_WPAS) && !defined(NO_DSA) + if (ret < 0) { + /* Otherwise, try converting DSA parameters. */ + ret = PemToDer(buf, sz, DSA_PARAM_TYPE, &der, heap, NULL, NULL); + } + #endif /* WOLFSSL_WPAS && !NO_DSA */ + if (ret < 0) { + /* Return error from conversion. */ + res = ret; + } + } +#endif /* WOLFSSL_PEM_TO_DER */ + + if (res == 1) { + /* Get the p and g from the DER encoded parameters. */ + if (wc_DhParamsLoad(der->buffer, der->length, p, &pSz, g, &gSz) < 0) { + res = WOLFSSL_BAD_FILETYPE; + } + else if (ssl != NULL) { + /* Set p and g into SSL. */ + res = wolfssl_set_tmp_dh(ssl, p, pSz, g, gSz); + } + else { + /* Set p and g into SSL context. */ + res = wolfssl_ctx_set_tmp_dh(ctx, p, pSz, g, gSz); + } + } + + /* Dispose of the DER buffer. */ + FreeDer(&der); + if (res != 1) { + /* Free the allocated buffers if not assigned into SSL or context. */ + XFREE(p, heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + return res; +} + + +/* Set the temporary DH parameters against the SSL. + * + * @param [in, out] ssl SSL object. + * @oaram [in] buf Buffer holding encoded DH parameters. + * @param [in] sz Size of encoded DH parameters. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl or buf is NULL. + * @return NOT_COMPLED_IN when format is PEM but PEM is not supported. + * @return WOLFSSL_BAD_FILETYPE if format is not supported. + */ +int wolfSSL_SetTmpDH_buffer(WOLFSSL* ssl, const unsigned char* buf, long sz, + int format) +{ + return ws_ctx_ssl_set_tmp_dh(NULL, ssl, buf, sz, format); +} + + +/* Set the temporary DH parameters against the SSL context. + * + * @param [in, out] ctx SSL context object. + * @oaram [in] buf Buffer holding encoded DH parameters. + * @param [in] sz Size of encoded DH parameters. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or buf is NULL. + * @return NOT_COMPLED_IN when format is PEM but PEM is not supported. + * @return WOLFSSL_BAD_FILETYPE if format is not supported. + */ +int wolfSSL_CTX_SetTmpDH_buffer(WOLFSSL_CTX* ctx, const unsigned char* buf, + long sz, int format) +{ + return ws_ctx_ssl_set_tmp_dh(ctx, NULL, buf, sz, format); +} + +#ifndef NO_FILESYSTEM + +/* Set the temporary DH parameters file against the SSL context or SSL. + * + * @param [in, out] ctx SSL context object. + * @param [in, out] ssl SSL object. + * @param [in] fname Name of file to load. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx and ssl NULL or fname is NULL. + * @return NOT_COMPLED_IN when format is PEM but PEM is not supported. + * @return WOLFSSL_BAD_FILETYPE if format is not supported. + */ +static int ws_ctx_ssl_set_tmp_dh_file(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + const char* fname, int format) +{ + int res = 1; + int ret; +#ifndef WOLFSSL_SMALL_STACK + byte stackBuffer[FILE_BUFFER_SIZE]; +#endif + StaticBuffer dhFile; + long sz = 0; + void* heap = WOLFSSL_HEAP(ctx, ssl); + + /* Setup buffer to hold file contents. */ +#ifdef WOLFSSL_SMALL_STACK + static_buffer_init(&dhFile); +#else + static_buffer_init(&dhFile, stackBuffer, FILE_BUFFER_SIZE); +#endif + + /* Validate parameters. */ + if (((ctx == NULL) && (ssl == NULL)) || (fname == NULL)) { + res = BAD_FUNC_ARG; + } + + if (res == 1) { + /* Read file into static buffer. */ + ret = wolfssl_read_file_static(fname, &dhFile, heap, DYNAMIC_TYPE_FILE, + &sz); + if (ret != 0) { + res = ret; + } + } + if (res == 1) { + if (ssl != NULL) { + /* Set encoded DH paramters into SSL. */ + res = wolfSSL_SetTmpDH_buffer(ssl, dhFile.buffer, sz, format); + } + else { + /* Set encoded DH paramters into SSL context. */ + res = wolfSSL_CTX_SetTmpDH_buffer(ctx, dhFile.buffer, sz, format); + } + } + + /* Dispose of any dynamically allocated data. */ + static_buffer_free(&dhFile, heap, DYNAMIC_TYPE_FILE); + return res; +} + +/* Set the temporary DH parameters file against the SSL. + * + * @param [in, out] ssl SSL object. + * @param [in] fname Name of file to load. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl or fname is NULL. + * @return NOT_COMPLED_IN when format is PEM but PEM is not supported. + * @return WOLFSSL_BAD_FILETYPE if format is not supported. + */ +int wolfSSL_SetTmpDH_file(WOLFSSL* ssl, const char* fname, int format) +{ + return ws_ctx_ssl_set_tmp_dh_file(NULL, ssl, fname, format); +} + + +/* Set the temporary DH parameters file against the SSL context. + * + * @param [in, out] ctx SSL context object. + * @param [in] fname Name of file to load. + * @param [in] format Format of data: + * WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or fname is NULL. + * @return NOT_COMPLED_IN when format is PEM but PEM is not supported. + * @return WOLFSSL_BAD_FILETYPE if format is not supported. + */ +int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format) +{ + return ws_ctx_ssl_set_tmp_dh_file(ctx, NULL, fname, format); +} + +#endif /* NO_FILESYSTEM */ + +#endif /* NO_CERTS */ + +#endif /* !NO_DH */ + +#endif /* !WOLFSSL_SSL_LOAD_INCLUDED */ + diff --git a/src/ssl_misc.c b/src/ssl_misc.c index 9bc42ddd9..9dd30b256 100644 --- a/src/ssl_misc.c +++ b/src/ssl_misc.c @@ -24,6 +24,8 @@ #endif #include +#include +#include #if !defined(WOLFSSL_SSL_MISC_INCLUDED) #ifndef WOLFSSL_IGNORE_FILE_WARN @@ -54,7 +56,7 @@ static int wolfssl_read_bio_file(WOLFSSL_BIO* bio, char** data) char* p; /* Allocate buffer to hold a chunk of data. */ - mem = (char*)XMALLOC(READ_BIO_FILE_CHUNK, bio->heap, DYNAMIC_TYPE_OPENSSL); + mem = (char*)XMALLOC(READ_BIO_FILE_CHUNK, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (mem == NULL) { WOLFSSL_ERROR_MSG("Memory allocation error"); ret = MEMORY_E; @@ -86,8 +88,8 @@ static int wolfssl_read_bio_file(WOLFSSL_BIO* bio, char** data) } else { /* No space left for more data to be read - add a chunk. */ - p = (char*)XREALLOC(mem, ret + READ_BIO_FILE_CHUNK, bio->heap, - DYNAMIC_TYPE_OPENSSL); + p = (char*)XREALLOC(mem, ret + READ_BIO_FILE_CHUNK, NULL, + DYNAMIC_TYPE_TMP_BUFFER); if (p == NULL) { sz = MEMORY_E; break; @@ -103,7 +105,7 @@ static int wolfssl_read_bio_file(WOLFSSL_BIO* bio, char** data) } if ((sz < 0) || (ret == 0)) { /* Dispose of memory on error or no data read. */ - XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + XFREE(mem, NULL, DYNAMIC_TYPE_TMP_BUFFER); mem = NULL; /* Return error. */ ret = sz; @@ -129,14 +131,14 @@ static int wolfssl_read_bio_len(WOLFSSL_BIO* bio, int sz, char** data) char* mem; /* Allocate buffer to hold data. */ - mem = (char*)XMALLOC((size_t)sz, bio->heap, DYNAMIC_TYPE_OPENSSL); + mem = (char*)XMALLOC((size_t)sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (mem == NULL) { WOLFSSL_ERROR_MSG("Memory allocation error"); ret = MEMORY_E; } else if ((ret = wolfSSL_BIO_read(bio, mem, sz)) != sz) { /* Pending data not read. */ - XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + XFREE(mem, NULL, DYNAMIC_TYPE_TMP_BUFFER); mem = NULL; ret = MEMORY_E; } @@ -299,5 +301,204 @@ static int wolfssl_read_file(XFILE fp, char** data, int* dataSz) } #endif /* (OPENSSL_EXTRA || PERSIST_CERT_CACHE) && !WOLFCRYPT_ONLY && * !NO_FILESYSTEM */ + +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) + +#ifdef WOLFSSL_SMALL_STACK + +/* Buffer and size with no stack buffer. */ +typedef struct { + /* Dynamically allocated buffer. */ + byte* buffer; + /* Size of buffer in bytes. */ + word32 sz; +} StaticBuffer; + +/* Initialize static buffer. + * + * @param [in, out] sb Static buffer. + */ +static void static_buffer_init(StaticBuffer* sb) +{ + sb->buffer = NULL; + sb->sz = 0; +} + +/* Set the size of the buffer. + * + * Can only set size once. + * + * @param [in] sb Static buffer. + * @param [in] len Length required. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] type Type of dynamic memory. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int static_buffer_set_size(StaticBuffer* sb, word32 len, void* heap, + int type) +{ + int ret = 0; + + (void)heap; + (void)type; + + sb->buffer = (byte*)XMALLOC(len, heap, type); + if (sb->buffer == NULL) { + ret = MEMORY_E; + } + else { + sb->sz = len; + } + + return ret; +} + +/* Dispose of dynamically allocated buffer. + * + * @param [in] sb Static buffer. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] type Type of dynamic memory. + */ +static void static_buffer_free(StaticBuffer* sb, void* heap, int type) +{ + (void)heap; + (void)type; + XFREE(sb->buffer, heap, type); +} + +#else + +/* Buffer and size with stack buffer set and option to dynamically allocate. */ +typedef struct { + /* Stack or heap buffer. */ + byte* buffer; + /* Size of buffer in bytes. */ + word32 sz; + /* Indicates whether the buffer was dynamically allocated. */ + int dyn; +} StaticBuffer; + +/* Initialize static buffer. + * + * @param [in, out] sb Static buffer. + * @param [in] stackBuffer Buffer allocated on the stack. + * @param [in] len Length of stack buffer. + */ +static void static_buffer_init(StaticBuffer* sb, byte* stackBuffer, word32 len) +{ + sb->buffer = stackBuffer; + sb->sz = len; + sb->dyn = 0; +} + +/* Set the size of the buffer. + * + * Pre: Buffer on the stack set with its size. + * Can only set size once. + * + * @param [in] sb Static buffer. + * @param [in] len Length required. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] type Type of dynamic memory. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + */ +static int static_buffer_set_size(StaticBuffer* sb, word32 len, void* heap, + int type) +{ + int ret = 0; + + (void)heap; + (void)type; + + if (len > sb->sz) { + byte* buff = (byte*)XMALLOC(len, heap, type); + if (buff == NULL) { + ret = MEMORY_E; + } + else { + sb->buffer = buff; + sb->sz = len; + sb->dyn = 1; + } + } + + return ret; +} + +/* Dispose of dynamically allocated buffer. + * + * @param [in] sb Static buffer. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] type Type of dynamic memory. + */ +static void static_buffer_free(StaticBuffer* sb, void* heap, int type) +{ + (void)heap; + (void)type; + + if (sb->dyn) { + XFREE(sb->buffer, heap, type); + } +} + +#endif /* WOLFSSL_SMALL_STACK */ + +#ifndef NO_FILESYSTEM + +/* Read all the data from a file into content. + * + * @param [in] fname File pointer to read with. + * @param [in, out] content Read data in an allocated buffer. + * @param [in] heap Dynamic memory allocation hint. + * @param [in] type Type of dynamic memory. + * @param [out] size Amount of data read in bytes. + * @return 0 on success. + * @return WOLFSSL_BAD_FILE when reading fails. + * @return MEMORY_E when memory allocation fails. + */ +static int wolfssl_read_file_static(const char* fname, StaticBuffer* content, + void* heap, int type, long* size) +{ + int ret = 0; + XFILE file = XBADFILE; + long sz = 0; + + /* Check filename is usable. */ + if (fname == NULL) { + ret = WOLFSSL_BAD_FILE; + } + /* Open file for reading. */ + if ((ret == 0) && ((file = XFOPEN(fname, "rb")) == XBADFILE)) { + ret = WOLFSSL_BAD_FILE; + } + if (ret == 0) { + /* Get length of file. */ + ret = wolfssl_file_len(file, &sz); + } + if (ret == 0) { + /* Set the buffer to be big enough to hold all data. */ + ret = static_buffer_set_size(content, (word32)sz, heap, type); + } + /* Read data from file. */ + if ((ret == 0) && ((size_t)XFREAD(content->buffer, 1, sz, file) != + (size_t)sz)) { + ret = WOLFSSL_BAD_FILE; + } + + /* Close file if opened. */ + if (file != XBADFILE) { + XFCLOSE(file); + } + /* Return size read. */ + *size = sz; + return ret; +} + +#endif /* !NO_FILESYSTEM */ + +#endif /* !WOLFCRYPT_ONLY && !NO_CERTS */ + #endif /* !WOLFSSL_SSL_MISC_INCLUDED */ diff --git a/src/ssl_p7p12.c b/src/ssl_p7p12.c new file mode 100644 index 000000000..5c45407b0 --- /dev/null +++ b/src/ssl_p7p12.c @@ -0,0 +1,2122 @@ +/* ssl_p7p12.c + * + * Copyright (C) 2006-2024 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#if defined(OPENSSL_EXTRA) && (defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) + #include +#endif +#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) + #include +#endif + +#if !defined(WOLFSSL_SSL_P7P12_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_p7p12.c does not need to be compiled separately from ssl.c + #endif +#else + +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) + +/******************************************************************************* + * START OF PKCS7 APIs + ******************************************************************************/ +#ifdef HAVE_PKCS7 + +#ifdef OPENSSL_ALL +PKCS7* wolfSSL_PKCS7_new(void) +{ + WOLFSSL_PKCS7* pkcs7; + int ret = 0; + + pkcs7 = (WOLFSSL_PKCS7*)XMALLOC(sizeof(WOLFSSL_PKCS7), NULL, + DYNAMIC_TYPE_PKCS7); + if (pkcs7 != NULL) { + XMEMSET(pkcs7, 0, sizeof(WOLFSSL_PKCS7)); + ret = wc_PKCS7_Init(&pkcs7->pkcs7, NULL, INVALID_DEVID); + } + + if (ret != 0 && pkcs7 != NULL) { + XFREE(pkcs7, NULL, DYNAMIC_TYPE_PKCS7); + pkcs7 = NULL; + } + + return (PKCS7*)pkcs7; +} + +/****************************************************************************** +* wolfSSL_PKCS7_SIGNED_new - allocates PKCS7 and initialize it for a signed data +* +* RETURNS: +* returns pointer to the PKCS7 structure on success, otherwise returns NULL +*/ +PKCS7_SIGNED* wolfSSL_PKCS7_SIGNED_new(void) +{ + byte signedData[]= { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02}; + PKCS7* pkcs7 = NULL; + + if ((pkcs7 = wolfSSL_PKCS7_new()) == NULL) + return NULL; + pkcs7->contentOID = SIGNED_DATA; + if ((wc_PKCS7_SetContentType(pkcs7, signedData, sizeof(signedData))) < 0) { + if (pkcs7) { + wolfSSL_PKCS7_free(pkcs7); + return NULL; + } + } + return pkcs7; +} + +void wolfSSL_PKCS7_free(PKCS7* pkcs7) +{ + WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; + + if (p7 != NULL) { + if (p7->data != NULL) + XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7); + wc_PKCS7_Free(&p7->pkcs7); + if (p7->certs) + wolfSSL_sk_pop_free(p7->certs, NULL); + XFREE(p7, NULL, DYNAMIC_TYPE_PKCS7); + } +} + +void wolfSSL_PKCS7_SIGNED_free(PKCS7_SIGNED* p7) +{ + wolfSSL_PKCS7_free(p7); + return; +} + +/** + * Convert DER/ASN.1 encoded signedData structure to internal PKCS7 + * structure. Note, does not support detached content. + * + * p7 - pointer to set to address of newly created PKCS7 structure on return + * in - pointer to pointer of DER/ASN.1 data + * len - length of input data, bytes + * + * Returns newly allocated and populated PKCS7 structure or NULL on error. + */ +PKCS7* wolfSSL_d2i_PKCS7(PKCS7** p7, const unsigned char** in, int len) +{ + return wolfSSL_d2i_PKCS7_ex(p7, in, len, NULL, 0); +} + +/* This internal function is only decoding and setting up the PKCS7 struct. It +* does not verify the PKCS7 signature. +* +* RETURNS: +* returns pointer to a PKCS7 structure on success, otherwise returns NULL +*/ +static PKCS7* wolfSSL_d2i_PKCS7_only(PKCS7** p7, const unsigned char** in, + int len, byte* content, word32 contentSz) +{ + WOLFSSL_PKCS7* pkcs7 = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_ex"); + + if (in == NULL || *in == NULL || len < 0) + return NULL; + + if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL) + return NULL; + + pkcs7->len = len; + pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7); + if (pkcs7->data == NULL) { + wolfSSL_PKCS7_free((PKCS7*)pkcs7); + return NULL; + } + XMEMCPY(pkcs7->data, *in, pkcs7->len); + + if (content != NULL) { + pkcs7->pkcs7.content = content; + pkcs7->pkcs7.contentSz = contentSz; + } + + if (p7 != NULL) + *p7 = (PKCS7*)pkcs7; + *in += pkcs7->len; + return (PKCS7*)pkcs7; +} + + +/***************************************************************************** +* wolfSSL_d2i_PKCS7_ex - Converts the given unsigned char buffer of size len +* into a PKCS7 object. Optionally, accepts a byte buffer of content which +* is stored as the PKCS7 object's content, to support detached signatures. +* @param content The content which is signed, in case the signature is +* detached. Ignored if NULL. +* @param contentSz The size of the passed in content. +* +* RETURNS: +* returns pointer to a PKCS7 structure on success, otherwise returns NULL +*/ +PKCS7* wolfSSL_d2i_PKCS7_ex(PKCS7** p7, const unsigned char** in, int len, + byte* content, word32 contentSz) +{ + WOLFSSL_PKCS7* pkcs7 = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_ex"); + + if (in == NULL || *in == NULL || len < 0) + return NULL; + + pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_d2i_PKCS7_only(p7, in, len, content, + contentSz); + if (pkcs7 != NULL) { + if (wc_PKCS7_VerifySignedData(&pkcs7->pkcs7, pkcs7->data, pkcs7->len) + != 0) { + WOLFSSL_MSG("wc_PKCS7_VerifySignedData failed"); + wolfSSL_PKCS7_free((PKCS7*)pkcs7); + if (p7 != NULL) { + *p7 = NULL; + } + return NULL; + } + } + + return (PKCS7*)pkcs7; +} + + +/** + * This API was added as a helper function for libest. It + * extracts a stack of certificates from the pkcs7 object. + * @param pkcs7 PKCS7 parameter object + * @return WOLFSSL_STACK_OF(WOLFSSL_X509)* + */ +WOLFSSL_STACK* wolfSSL_PKCS7_to_stack(PKCS7* pkcs7) +{ + int i; + WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; + WOLF_STACK_OF(WOLFSSL_X509)* ret = NULL; + + WOLFSSL_ENTER("wolfSSL_PKCS7_to_stack"); + + if (!p7) { + WOLFSSL_MSG("Bad parameter"); + return NULL; + } + + if (p7->certs) + return p7->certs; + + for (i = 0; i < MAX_PKCS7_CERTS && p7->pkcs7.cert[i]; i++) { + WOLFSSL_X509* x509 = wolfSSL_X509_d2i_ex(NULL, p7->pkcs7.cert[i], + p7->pkcs7.certSz[i], pkcs7->heap); + if (!ret) + ret = wolfSSL_sk_X509_new_null(); + if (x509) { + if (wolfSSL_sk_X509_push(ret, x509) != WOLFSSL_SUCCESS) { + wolfSSL_X509_free(x509); + WOLFSSL_MSG("wolfSSL_sk_X509_push error"); + goto error; + } + } + else { + WOLFSSL_MSG("wolfSSL_X509_d2i error"); + goto error; + } + } + + /* Save stack to free later */ + if (p7->certs) + wolfSSL_sk_pop_free(p7->certs, NULL); + p7->certs = ret; + + return ret; +error: + if (ret) { + wolfSSL_sk_pop_free(ret, NULL); + } + return NULL; +} + +/** + * Return stack of signers contained in PKCS7 cert. + * Notes: + * - Currently only PKCS#7 messages with a single signer cert is supported. + * - Returned WOLFSSL_STACK must be freed by caller. + * + * pkcs7 - PKCS7 struct to retrieve signer certs from. + * certs - currently unused + * flags - flags to control function behavior. + * + * Return WOLFSSL_STACK of signers on success, NULL on error. + */ +WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs, + int flags) +{ + WOLFSSL_X509* x509 = NULL; + WOLFSSL_STACK* signers = NULL; + WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; + + if (p7 == NULL) + return NULL; + + /* Only PKCS#7 messages with a single cert that is the verifying certificate + * is supported. + */ + if (flags & PKCS7_NOINTERN) { + WOLFSSL_MSG("PKCS7_NOINTERN flag not supported"); + return NULL; + } + + signers = wolfSSL_sk_X509_new_null(); + if (signers == NULL) + return NULL; + + if (wolfSSL_d2i_X509(&x509, (const byte**)&p7->pkcs7.singleCert, + p7->pkcs7.singleCertSz) == NULL) { + wolfSSL_sk_X509_pop_free(signers, NULL); + return NULL; + } + + if (wolfSSL_sk_X509_push(signers, x509) != WOLFSSL_SUCCESS) { + wolfSSL_sk_X509_pop_free(signers, NULL); + return NULL; + } + + (void)certs; + + return signers; +} + +#ifndef NO_BIO + +PKCS7* wolfSSL_d2i_PKCS7_bio(WOLFSSL_BIO* bio, PKCS7** p7) +{ + WOLFSSL_PKCS7* pkcs7; + int ret; + + WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_bio"); + + if (bio == NULL) + return NULL; + + if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL) + return NULL; + + pkcs7->len = wolfSSL_BIO_get_len(bio); + pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7); + if (pkcs7->data == NULL) { + wolfSSL_PKCS7_free((PKCS7*)pkcs7); + return NULL; + } + + if ((ret = wolfSSL_BIO_read(bio, pkcs7->data, pkcs7->len)) <= 0) { + wolfSSL_PKCS7_free((PKCS7*)pkcs7); + return NULL; + } + /* pkcs7->len may change if using b64 for example */ + pkcs7->len = ret; + + if (wc_PKCS7_VerifySignedData(&pkcs7->pkcs7, pkcs7->data, pkcs7->len) + != 0) { + WOLFSSL_MSG("wc_PKCS7_VerifySignedData failed"); + wolfSSL_PKCS7_free((PKCS7*)pkcs7); + return NULL; + } + + if (p7 != NULL) + *p7 = (PKCS7*)pkcs7; + return (PKCS7*)pkcs7; +} + +int wolfSSL_i2d_PKCS7(PKCS7 *p7, unsigned char **out) +{ + byte* output = NULL; + int localBuf = 0; + int len; + WC_RNG rng; + int ret = WOLFSSL_FAILURE; + WOLFSSL_ENTER("wolfSSL_i2d_PKCS7"); + + if (!out || !p7) { + WOLFSSL_MSG("Bad parameter"); + return WOLFSSL_FAILURE; + } + + if (!p7->rng) { + if (wc_InitRng(&rng) != 0) { + WOLFSSL_MSG("wc_InitRng error"); + return WOLFSSL_FAILURE; + } + p7->rng = &rng; /* cppcheck-suppress autoVariables + */ + } + + if ((len = wc_PKCS7_EncodeSignedData(p7, NULL, 0)) < 0) { + WOLFSSL_MSG("wc_PKCS7_EncodeSignedData error"); + goto cleanup; + } + + if (*out == NULL) { + output = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (!output) { + WOLFSSL_MSG("malloc error"); + goto cleanup; + } + localBuf = 1; + } + else { + output = *out; + } + + if ((len = wc_PKCS7_EncodeSignedData(p7, output, len)) < 0) { + WOLFSSL_MSG("wc_PKCS7_EncodeSignedData error"); + goto cleanup; + } + + ret = len; +cleanup: + if (p7->rng == &rng) { + wc_FreeRng(&rng); + p7->rng = NULL; + } + if (ret == WOLFSSL_FAILURE && localBuf && output) + XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (ret != WOLFSSL_FAILURE) + *out = output; + return ret; +} + +int wolfSSL_i2d_PKCS7_bio(WOLFSSL_BIO *bio, PKCS7 *p7) +{ + byte* output = NULL; + int len; + int ret = WOLFSSL_FAILURE; + WOLFSSL_ENTER("wolfSSL_i2d_PKCS7_bio"); + + if (!bio || !p7) { + WOLFSSL_MSG("Bad parameter"); + return WOLFSSL_FAILURE; + } + + if ((len = wolfSSL_i2d_PKCS7(p7, &output)) == WOLFSSL_FAILURE) { + WOLFSSL_MSG("wolfSSL_i2d_PKCS7 error"); + goto cleanup; + } + + if (wolfSSL_BIO_write(bio, output, len) <= 0) { + WOLFSSL_MSG("wolfSSL_BIO_write error"); + goto cleanup; + } + + ret = WOLFSSL_SUCCESS; +cleanup: + if (output) + XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} + +/** + * Creates and returns a PKCS7 signedData structure. + * + * Inner content type is set to DATA to match OpenSSL behavior. + * + * signer - certificate to sign bundle with + * pkey - private key matching signer + * certs - optional additional set of certificates to include + * in - input data to be signed + * flags - optional set of flags to control sign behavior + * + * PKCS7_BINARY - Do not translate input data to MIME canonical + * format (\r\n line endings), thus preventing corruption of + * binary content. + * PKCS7_TEXT - Prepend MIME headers for text/plain to content. + * PKCS7_DETACHED - Set signature detached, omit content from output bundle. + * PKCS7_STREAM - initialize PKCS7 struct for signing, do not read data. + * + * Flags not currently supported: + * PKCS7_NOCERTS - Do not include the signer cert in the output bundle. + * PKCS7_PARTIAL - Allow for PKCS7_sign() to be only partially set up, + * then signers etc to be added separately before + * calling PKCS7_final(). + * + * Returns valid PKCS7 structure pointer, or NULL if an error occurred. + */ +PKCS7* wolfSSL_PKCS7_sign(WOLFSSL_X509* signer, WOLFSSL_EVP_PKEY* pkey, + WOLFSSL_STACK* certs, WOLFSSL_BIO* in, int flags) +{ + int err = 0; + WOLFSSL_PKCS7* p7 = NULL; + WOLFSSL_STACK* cert = certs; + + WOLFSSL_ENTER("wolfSSL_PKCS7_sign"); + + if (flags & PKCS7_NOCERTS) { + WOLFSSL_MSG("PKCS7_NOCERTS flag not yet supported"); + err = 1; + } + + if (flags & PKCS7_PARTIAL) { + WOLFSSL_MSG("PKCS7_PARTIAL flag not yet supported"); + err = 1; + } + + if ((err == 0) && (signer == NULL || signer->derCert == NULL || + signer->derCert->length == 0)) { + WOLFSSL_MSG("Bad function arg, signer is NULL or incomplete"); + err = 1; + } + + if ((err == 0) && (pkey == NULL || pkey->pkey.ptr == NULL || + pkey->pkey_sz <= 0)) { + WOLFSSL_MSG("Bad function arg, pkey is NULL or incomplete"); + err = 1; + } + + if ((err == 0) && (in == NULL) && !(flags & PKCS7_STREAM)) { + WOLFSSL_MSG("input data required unless PKCS7_STREAM used"); + err = 1; + } + + if ((err == 0) && ((p7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL)) { + WOLFSSL_MSG("Error allocating new WOLFSSL_PKCS7"); + err = 1; + } + + /* load signer certificate */ + if (err == 0) { + if (wc_PKCS7_InitWithCert(&p7->pkcs7, signer->derCert->buffer, + signer->derCert->length) != 0) { + WOLFSSL_MSG("Failed to load signer certificate"); + err = 1; + } + } + + /* set signer private key, data types, defaults */ + if (err == 0) { + p7->pkcs7.privateKey = (byte*)pkey->pkey.ptr; + p7->pkcs7.privateKeySz = pkey->pkey_sz; + p7->pkcs7.contentOID = DATA; /* inner content default is DATA */ + p7->pkcs7.hashOID = SHA256h; /* default to SHA-256 hash type */ + p7->type = SIGNED_DATA; /* PKCS7_final switches on type */ + } + + /* add additional chain certs if provided */ + while (cert && (err == 0)) { + if (cert->data.x509 != NULL && cert->data.x509->derCert != NULL) { + if (wc_PKCS7_AddCertificate(&p7->pkcs7, + cert->data.x509->derCert->buffer, + cert->data.x509->derCert->length) != 0) { + WOLFSSL_MSG("Error in wc_PKCS7_AddCertificate"); + err = 1; + } + } + cert = cert->next; + } + + if ((err == 0) && (flags & PKCS7_DETACHED)) { + if (wc_PKCS7_SetDetached(&p7->pkcs7, 1) != 0) { + WOLFSSL_MSG("Failed to set signature detached"); + err = 1; + } + } + + if ((err == 0) && (flags & PKCS7_STREAM)) { + /* if streaming, return before finalizing */ + return (PKCS7*)p7; + } + + if ((err == 0) && (wolfSSL_PKCS7_final((PKCS7*)p7, in, flags) != 1)) { + WOLFSSL_MSG("Error calling wolfSSL_PKCS7_final"); + err = 1; + } + + if ((err != 0) && (p7 != NULL)) { + wolfSSL_PKCS7_free((PKCS7*)p7); + p7 = NULL; + } + + return (PKCS7*)p7; +} + +#ifdef HAVE_SMIME + +#ifndef MAX_MIME_LINE_LEN + #define MAX_MIME_LINE_LEN 1024 +#endif + +/** + * Copy input BIO to output BIO, but convert all line endings to CRLF (\r\n), + * used by PKCS7_final(). + * + * in - input WOLFSSL_BIO to be converted + * out - output WOLFSSL_BIO to hold copy of in, with line endings adjusted + * + * Return 0 on success, negative on error + */ +static int wolfSSL_BIO_to_MIME_crlf(WOLFSSL_BIO* in, WOLFSSL_BIO* out) +{ + int ret = 0; + int lineLen = 0; + word32 canonLineLen = 0; + char* canonLine = NULL; +#ifdef WOLFSSL_SMALL_STACK + char* line = NULL; +#else + char line[MAX_MIME_LINE_LEN]; +#endif + + if (in == NULL || out == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK + line = (char*)XMALLOC(MAX_MIME_LINE_LEN, in->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (line == NULL) { + return MEMORY_E; + } +#endif + XMEMSET(line, 0, MAX_MIME_LINE_LEN); + + while ((lineLen = wolfSSL_BIO_gets(in, line, MAX_MIME_LINE_LEN)) > 0) { + + if (line[lineLen - 1] == '\r' || line[lineLen - 1] == '\n') { + canonLineLen = (word32)lineLen; + if ((canonLine = wc_MIME_single_canonicalize( + line, &canonLineLen)) == NULL) { + ret = -1; + break; + } + + /* remove trailing null */ + if (canonLineLen >= 1 && canonLine[canonLineLen-1] == '\0') { + canonLineLen--; + } + + if (wolfSSL_BIO_write(out, canonLine, (int)canonLineLen) < 0) { + ret = -1; + break; + } + XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); + canonLine = NULL; + } + else { + /* no line ending in current line, write direct to out */ + if (wolfSSL_BIO_write(out, line, lineLen) < 0) { + ret = -1; + break; + } + } + } + + if (canonLine != NULL) { + XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); + } +#ifdef WOLFSSL_SMALL_STACK + XFREE(line, in->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +#endif /* HAVE_SMIME */ + +/* Used by both PKCS7_final() and PKCS7_verify() */ +static const char contTypeText[] = "Content-Type: text/plain\r\n\r\n"; + +/** + * Finalize PKCS7 structure, currently supports signedData only. + * + * Does not generate final bundle (ie: signedData), but finalizes + * the PKCS7 structure in preparation for a output function to be called next. + * + * pkcs7 - initialized PKCS7 structure, populated with signer, etc + * in - input data + * flags - flags to control PKCS7 behavior. Other flags except those noted + * below are ignored: + * + * PKCS7_BINARY - Do not translate input data to MIME canonical + * format (\r\n line endings), thus preventing corruption of + * binary content. + * PKCS7_TEXT - Prepend MIME headers for text/plain to content. + * + * Returns 1 on success, 0 on error + */ +int wolfSSL_PKCS7_final(PKCS7* pkcs7, WOLFSSL_BIO* in, int flags) +{ + int ret = 1; + int memSz = 0; + unsigned char* mem = NULL; + WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; + WOLFSSL_BIO* data = NULL; + + WOLFSSL_ENTER("wolfSSL_PKCS7_final"); + + if (p7 == NULL || in == NULL) { + WOLFSSL_MSG("Bad input args to PKCS7_final"); + ret = 0; + } + + if (ret == 1) { + if ((data = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())) == NULL) { + WOLFSSL_MSG("Error in wolfSSL_BIO_new"); + ret = 0; + } + } + + /* prepend Content-Type header if PKCS7_TEXT */ + if ((ret == 1) && (flags & PKCS7_TEXT)) { + if (wolfSSL_BIO_write(data, contTypeText, + (int)XSTR_SIZEOF(contTypeText)) < 0) { + WOLFSSL_MSG("Error prepending Content-Type header"); + ret = 0; + } + } + + /* convert line endings to CRLF if !PKCS7_BINARY */ + if (ret == 1) { + if (flags & PKCS7_BINARY) { + + /* no CRLF conversion, direct copy content */ + if ((memSz = wolfSSL_BIO_get_len(in)) <= 0) { + ret = 0; + } + if (ret == 1) { + mem = (unsigned char*)XMALLOC(memSz, in->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + WOLFSSL_MSG("Failed to allocate memory for input data"); + ret = 0; + } + } + + if (ret == 1) { + if (wolfSSL_BIO_read(in, mem, memSz) != memSz) { + WOLFSSL_MSG("Error reading from input BIO"); + ret = 0; + } + else if (wolfSSL_BIO_write(data, mem, memSz) < 0) { + ret = 0; + } + } + + if (mem != NULL) { + XFREE(mem, in->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + } + else { + #ifdef HAVE_SMIME + /* convert content line endings to CRLF */ + if (wolfSSL_BIO_to_MIME_crlf(in, data) != 0) { + WOLFSSL_MSG("Error converting line endings to CRLF"); + ret = 0; + } + else { + p7->pkcs7.contentCRLF = 1; + } + #else + WOLFSSL_MSG("Without PKCS7_BINARY requires wolfSSL to be built " + "with HAVE_SMIME"); + ret = 0; + #endif + } + } + + if ((ret == 1) && ((memSz = wolfSSL_BIO_get_mem_data(data, &mem)) < 0)) { + WOLFSSL_MSG("Error in wolfSSL_BIO_get_mem_data"); + ret = 0; + } + + if (ret == 1) { + if (p7->data != NULL) { + XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7); + } + p7->data = (byte*)XMALLOC(memSz, NULL, DYNAMIC_TYPE_PKCS7); + if (p7->data == NULL) { + ret = 0; + } + else { + XMEMCPY(p7->data, mem, memSz); + p7->len = memSz; + } + } + + if (ret == 1) { + p7->pkcs7.content = p7->data; + p7->pkcs7.contentSz = p7->len; + } + + if (data != NULL) { + wolfSSL_BIO_free(data); + } + + return ret; +} + +int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs, + WOLFSSL_X509_STORE* store, WOLFSSL_BIO* in, WOLFSSL_BIO* out, int flags) +{ + int i, ret = 0; + unsigned char* mem = NULL; + int memSz = 0; + WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; + int contTypeLen; + WOLFSSL_X509* signer = NULL; + WOLFSSL_STACK* signers = NULL; + + WOLFSSL_ENTER("wolfSSL_PKCS7_verify"); + + if (pkcs7 == NULL) + return WOLFSSL_FAILURE; + + if (in != NULL) { + if ((memSz = wolfSSL_BIO_get_mem_data(in, &mem)) < 0) + return WOLFSSL_FAILURE; + + p7->pkcs7.content = mem; + p7->pkcs7.contentSz = memSz; + } + + /* certs is the list of certificates to find the cert with issuer/serial. */ + (void)certs; + /* store is the certificate store to use to verify signer certificate + * associated with the signers. + */ + (void)store; + + ret = wc_PKCS7_VerifySignedData(&p7->pkcs7, p7->data, p7->len); + if (ret != 0) + return WOLFSSL_FAILURE; + + if ((flags & PKCS7_NOVERIFY) != PKCS7_NOVERIFY) { + /* Verify signer certificates */ + if (store == NULL || store->cm == NULL) { + WOLFSSL_MSG("No store or store certs, but PKCS7_NOVERIFY not set"); + return WOLFSSL_FAILURE; + } + + signers = wolfSSL_PKCS7_get0_signers(pkcs7, certs, flags); + if (signers == NULL) { + WOLFSSL_MSG("No signers found to verify"); + return WOLFSSL_FAILURE; + } + for (i = 0; i < wolfSSL_sk_X509_num(signers); i++) { + signer = wolfSSL_sk_X509_value(signers, i); + + if (wolfSSL_CertManagerVerifyBuffer(store->cm, + signer->derCert->buffer, + signer->derCert->length, + WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Failed to verify signer certificate"); + wolfSSL_sk_X509_pop_free(signers, NULL); + return WOLFSSL_FAILURE; + } + } + wolfSSL_sk_X509_pop_free(signers, NULL); + } + + if (flags & PKCS7_TEXT) { + /* strip MIME header for text/plain, otherwise error */ + contTypeLen = XSTR_SIZEOF(contTypeText); + if ((p7->pkcs7.contentSz < (word32)contTypeLen) || + (XMEMCMP(p7->pkcs7.content, contTypeText, contTypeLen) != 0)) { + WOLFSSL_MSG("Error PKCS7 Content-Type not found with PKCS7_TEXT"); + return WOLFSSL_FAILURE; + } + p7->pkcs7.content += contTypeLen; + p7->pkcs7.contentSz -= contTypeLen; + } + + if (out != NULL) { + wolfSSL_BIO_write(out, p7->pkcs7.content, p7->pkcs7.contentSz); + } + + WOLFSSL_LEAVE("wolfSSL_PKCS7_verify", WOLFSSL_SUCCESS); + + return WOLFSSL_SUCCESS; +} + +/** + * This API was added as a helper function for libest. It + * encodes a stack of certificates to pkcs7 format. + * @param pkcs7 PKCS7 parameter object + * @param certs WOLFSSL_STACK_OF(WOLFSSL_X509)* + * @param out Output bio + * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure + */ +int wolfSSL_PKCS7_encode_certs(PKCS7* pkcs7, WOLFSSL_STACK* certs, + WOLFSSL_BIO* out) +{ + int ret; + WOLFSSL_PKCS7* p7; + WOLFSSL_ENTER("wolfSSL_PKCS7_encode_certs"); + + if (!pkcs7 || !certs || !out) { + WOLFSSL_MSG("Bad parameter"); + return WOLFSSL_FAILURE; + } + + p7 = (WOLFSSL_PKCS7*)pkcs7; + + /* take ownership of certs */ + p7->certs = certs; + /* TODO: takes ownership even on failure below but not on above failure. */ + + if (pkcs7->certList) { + WOLFSSL_MSG("wolfSSL_PKCS7_encode_certs called multiple times on same " + "struct"); + return WOLFSSL_FAILURE; + } + + if (certs) { + /* Save some of the values */ + int hashOID = pkcs7->hashOID; + byte version = pkcs7->version; + + if (!certs->data.x509 || !certs->data.x509->derCert) { + WOLFSSL_MSG("Missing cert"); + return WOLFSSL_FAILURE; + } + + if (wc_PKCS7_InitWithCert(pkcs7, certs->data.x509->derCert->buffer, + certs->data.x509->derCert->length) != 0) { + WOLFSSL_MSG("wc_PKCS7_InitWithCert error"); + return WOLFSSL_FAILURE; + } + certs = certs->next; + + pkcs7->hashOID = hashOID; + pkcs7->version = version; + } + + /* Add the certs to the PKCS7 struct */ + while (certs) { + if (!certs->data.x509 || !certs->data.x509->derCert) { + WOLFSSL_MSG("Missing cert"); + return WOLFSSL_FAILURE; + } + if (wc_PKCS7_AddCertificate(pkcs7, certs->data.x509->derCert->buffer, + certs->data.x509->derCert->length) != 0) { + WOLFSSL_MSG("wc_PKCS7_AddCertificate error"); + return WOLFSSL_FAILURE; + } + certs = certs->next; + } + + if (wc_PKCS7_SetSignerIdentifierType(pkcs7, DEGENERATE_SID) != 0) { + WOLFSSL_MSG("wc_PKCS7_SetSignerIdentifierType error"); + return WOLFSSL_FAILURE; + } + + ret = wolfSSL_i2d_PKCS7_bio(out, pkcs7); + + return ret; +} + +/****************************************************************************** +* wolfSSL_PEM_write_bio_PKCS7 - writes the PKCS7 data to BIO +* +* RETURNS: +* returns WOLFSSL_SUCCESS on success, otherwise returns WOLFSSL_FAILURE +*/ +int wolfSSL_PEM_write_bio_PKCS7(WOLFSSL_BIO* bio, PKCS7* p7) +{ +#ifdef WOLFSSL_SMALL_STACK + byte* outputHead; + byte* outputFoot; +#else + byte outputHead[2048]; + byte outputFoot[2048]; +#endif + word32 outputHeadSz = 2048; + word32 outputFootSz = 2048; + word32 outputSz = 0; + byte* output = NULL; + byte* pem = NULL; + int pemSz = -1; + enum wc_HashType hashType; + byte hashBuf[WC_MAX_DIGEST_SIZE]; + word32 hashSz = -1; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PKCS7"); + + if (bio == NULL || p7 == NULL) + return WOLFSSL_FAILURE; + +#ifdef WOLFSSL_SMALL_STACK + outputHead = (byte*)XMALLOC(outputHeadSz, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (outputHead == NULL) + return MEMORY_E; + + outputFoot = (byte*)XMALLOC(outputFootSz, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (outputFoot == NULL) + goto error; + +#endif + + XMEMSET(hashBuf, 0, WC_MAX_DIGEST_SIZE); + XMEMSET(outputHead, 0, outputHeadSz); + XMEMSET(outputFoot, 0, outputFootSz); + + hashType = wc_OidGetHash(p7->hashOID); + hashSz = wc_HashGetDigestSize(hashType); + if (hashSz > WC_MAX_DIGEST_SIZE) + goto error; + + /* only SIGNED_DATA is supported */ + switch (p7->contentOID) { + case SIGNED_DATA: + break; + default: + WOLFSSL_MSG("Unknown PKCS#7 Type"); + goto error; + }; + + if ((wc_PKCS7_EncodeSignedData_ex(p7, hashBuf, hashSz, + outputHead, &outputHeadSz, outputFoot, &outputFootSz)) != 0) + goto error; + + outputSz = outputHeadSz + p7->contentSz + outputFootSz; + output = (byte*)XMALLOC(outputSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + + if (!output) + goto error; + + XMEMSET(output, 0, outputSz); + outputSz = 0; + XMEMCPY(&output[outputSz], outputHead, outputHeadSz); + outputSz += outputHeadSz; + XMEMCPY(&output[outputSz], p7->content, p7->contentSz); + outputSz += p7->contentSz; + XMEMCPY(&output[outputSz], outputFoot, outputFootSz); + outputSz += outputFootSz; + + /* get PEM size */ + pemSz = wc_DerToPemEx(output, outputSz, NULL, 0, NULL, CERT_TYPE); + if (pemSz < 0) + goto error; + + pemSz++; /* for '\0'*/ + + /* create PEM buffer and convert from DER to PEM*/ + if ((pem = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER)) + == NULL) + goto error; + + XMEMSET(pem, 0, pemSz); + + if (wc_DerToPemEx(output, outputSz, pem, pemSz, NULL, CERT_TYPE) < 0) { + goto error; + } + if ((wolfSSL_BIO_write(bio, pem, pemSz) == pemSz)) { + XFREE(output, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); +#ifdef WOLFSSL_SMALL_STACK + XFREE(outputHead, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(outputFoot, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return WOLFSSL_SUCCESS; + } + +error: +#ifdef WOLFSSL_SMALL_STACK + if (outputHead) { + XFREE(outputHead, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + if (outputFoot) { + XFREE(outputFoot, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + if (output) { + XFREE(output, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + if (pem) { + XFREE(pem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + return WOLFSSL_FAILURE; +} + +#ifdef HAVE_SMIME +/***************************************************************************** +* wolfSSL_SMIME_read_PKCS7 - Reads the given S/MIME message and parses it into +* a PKCS7 object. In case of a multipart message, stores the signed data in +* bcont. +* +* RETURNS: +* returns pointer to a PKCS7 structure on success, otherwise returns NULL +*/ +PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, + WOLFSSL_BIO** bcont) +{ + MimeHdr* allHdrs = NULL; + MimeHdr* curHdr = NULL; + MimeParam* curParam = NULL; + int inLen = 0; + byte* bcontMem = NULL; + int bcontMemSz = 0; + int sectionLen = 0; + int ret = -1; + char* section = NULL; + char* canonLine = NULL; + char* canonSection = NULL; + PKCS7* pkcs7 = NULL; + word32 outLen = 0; + word32 canonLineLen = 0; + byte* out = NULL; + byte* outHead = NULL; + + int canonPos = 0; + int lineLen = 0; + int remainLen = 0; + byte isEnd = 0; + size_t canonSize = 0; + size_t boundLen = 0; + char* boundary = NULL; + + static const char kContType[] = "Content-Type"; + static const char kCTE[] = "Content-Transfer-Encoding"; + static const char kMultSigned[] = "multipart/signed"; + static const char kAppPkcsSign[] = "application/pkcs7-signature"; + static const char kAppXPkcsSign[] = "application/x-pkcs7-signature"; + static const char kAppPkcs7Mime[] = "application/pkcs7-mime"; + static const char kAppXPkcs7Mime[] = "application/x-pkcs7-mime"; + + WOLFSSL_ENTER("wolfSSL_SMIME_read_PKCS7"); + + if (in == NULL || bcont == NULL) { + goto error; + } + inLen = wolfSSL_BIO_get_len(in); + if (inLen <= 0) { + goto error; + } + remainLen = wolfSSL_BIO_get_len(in); + if (remainLen <= 0) { + goto error; + } + + section = (char*)XMALLOC(remainLen+1, NULL, DYNAMIC_TYPE_PKCS7); + if (section == NULL) { + goto error; + } + lineLen = wolfSSL_BIO_gets(in, section, remainLen); + if (lineLen <= 0) { + goto error; + } + while (isEnd == 0 && remainLen > 0) { + sectionLen += lineLen; + remainLen -= lineLen; + lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], remainLen); + if (lineLen <= 0) { + goto error; + } + /* Line with just newline signals end of headers. */ + if ((lineLen==2 && !XSTRNCMP(§ion[sectionLen], + "\r\n", 2)) || + (lineLen==1 && (section[sectionLen] == '\r' || + section[sectionLen] == '\n'))) { + isEnd = 1; + } + } + section[sectionLen] = '\0'; + ret = wc_MIME_parse_headers(section, sectionLen, &allHdrs); + if (ret < 0) { + WOLFSSL_MSG("Parsing MIME headers failed."); + goto error; + } + isEnd = 0; + section[0] = '\0'; + sectionLen = 0; + + curHdr = wc_MIME_find_header_name(kContType, allHdrs); + if (curHdr && !XSTRNCMP(curHdr->body, kMultSigned, + XSTR_SIZEOF(kMultSigned))) { + curParam = wc_MIME_find_param_attr("protocol", curHdr->params); + if (curParam && (!XSTRNCMP(curParam->value, kAppPkcsSign, + XSTR_SIZEOF(kAppPkcsSign)) || + !XSTRNCMP(curParam->value, kAppXPkcsSign, + XSTR_SIZEOF(kAppXPkcsSign)))) { + curParam = wc_MIME_find_param_attr("boundary", curHdr->params); + if (curParam == NULL) { + goto error; + } + + boundLen = XSTRLEN(curParam->value) + 2; + boundary = (char*)XMALLOC(boundLen+1, NULL, DYNAMIC_TYPE_PKCS7); + if (boundary == NULL) { + goto error; + } + XMEMSET(boundary, 0, (word32)(boundLen+1)); + boundary[0] = boundary[1] = '-'; + XSTRNCPY(&boundary[2], curParam->value, boundLen-2); + + /* Parse up to first boundary, ignore everything here. */ + lineLen = wolfSSL_BIO_gets(in, section, remainLen); + if (lineLen <= 0) { + goto error; + } + while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && + remainLen > 0) { + sectionLen += lineLen; + remainLen -= lineLen; + lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], + remainLen); + if (lineLen <= 0) { + goto error; + } + } + + section[0] = '\0'; + sectionLen = 0; + canonSize = remainLen + 1; + canonSection = (char*)XMALLOC(canonSize, NULL, + DYNAMIC_TYPE_PKCS7); + if (canonSection == NULL) { + goto error; + } + + lineLen = wolfSSL_BIO_gets(in, section, remainLen); + if (lineLen < 0) { + goto error; + } + while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && + remainLen > 0) { + canonLineLen = lineLen; + canonLine = wc_MIME_single_canonicalize(§ion[sectionLen], + &canonLineLen); + if (canonLine == NULL) { + goto error; + } + /* If line endings were added, the initial length may be + * exceeded. */ + if ((canonPos + canonLineLen) >= canonSize) { + canonSize = canonPos + canonLineLen; + canonSection = (char*)XREALLOC(canonSection, canonSize, + NULL, DYNAMIC_TYPE_PKCS7); + if (canonSection == NULL) { + goto error; + } + } + XMEMCPY(&canonSection[canonPos], canonLine, + (int)canonLineLen - 1); + canonPos += canonLineLen - 1; + XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); + canonLine = NULL; + + sectionLen += lineLen; + remainLen -= lineLen; + + lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], + remainLen); + if (lineLen <= 0) { + goto error; + } + } + + if (canonPos > 0) { + canonPos--; + } + + /* Strip the final trailing newline. Support \r, \n or \r\n. */ + if (canonSection[canonPos] == '\n') { + if (canonPos > 0) { + canonPos--; + } + } + + if (canonSection[canonPos] == '\r') { + if (canonPos > 0) { + canonPos--; + } + } + + canonSection[canonPos+1] = '\0'; + + *bcont = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); + ret = wolfSSL_BIO_write(*bcont, canonSection, + canonPos + 1); + if (ret != (canonPos+1)) { + goto error; + } + if ((bcontMemSz = wolfSSL_BIO_get_mem_data(*bcont, &bcontMem)) + < 0) { + goto error; + } + XFREE(canonSection, NULL, DYNAMIC_TYPE_PKCS7); + canonSection = NULL; + + wc_MIME_free_hdrs(allHdrs); + allHdrs = NULL; + section[0] = '\0'; + sectionLen = 0; + lineLen = wolfSSL_BIO_gets(in, section, remainLen); + if (lineLen <= 0) { + goto error; + } + while (isEnd == 0 && remainLen > 0) { + sectionLen += lineLen; + remainLen -= lineLen; + lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], + remainLen); + if (lineLen <= 0) { + goto error; + } + /* Line with just newline signals end of headers. */ + if ((lineLen==2 && !XSTRNCMP(§ion[sectionLen], + "\r\n", 2)) || + (lineLen==1 && (section[sectionLen] == '\r' || + section[sectionLen] == '\n'))) { + isEnd = 1; + } + } + section[sectionLen] = '\0'; + ret = wc_MIME_parse_headers(section, sectionLen, &allHdrs); + if (ret < 0) { + WOLFSSL_MSG("Parsing MIME headers failed."); + goto error; + } + curHdr = wc_MIME_find_header_name(kContType, allHdrs); + if (curHdr == NULL || (XSTRNCMP(curHdr->body, kAppPkcsSign, + XSTR_SIZEOF(kAppPkcsSign)) && + XSTRNCMP(curHdr->body, kAppXPkcsSign, + XSTR_SIZEOF(kAppXPkcsSign)))) { + WOLFSSL_MSG("S/MIME headers not found inside " + "multipart message.\n"); + goto error; + } + + section[0] = '\0'; + sectionLen = 0; + lineLen = wolfSSL_BIO_gets(in, section, remainLen); + while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && + remainLen > 0) { + sectionLen += lineLen; + remainLen -= lineLen; + lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], + remainLen); + if (lineLen <= 0) { + goto error; + } + } + + XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7); + boundary = NULL; + } + } + else if (curHdr && (!XSTRNCMP(curHdr->body, kAppPkcs7Mime, + XSTR_SIZEOF(kAppPkcs7Mime)) || + !XSTRNCMP(curHdr->body, kAppXPkcs7Mime, + XSTR_SIZEOF(kAppXPkcs7Mime)))) { + sectionLen = wolfSSL_BIO_get_len(in); + if (sectionLen <= 0) { + goto error; + } + ret = wolfSSL_BIO_read(in, section, sectionLen); + if (ret < 0 || ret != sectionLen) { + WOLFSSL_MSG("Error reading input BIO."); + goto error; + } + } + else { + WOLFSSL_MSG("S/MIME headers not found."); + goto error; + } + + curHdr = wc_MIME_find_header_name(kCTE, allHdrs); + if (curHdr == NULL) { + WOLFSSL_MSG("Content-Transfer-Encoding header not found, " + "assuming base64 encoding."); + } + else if (XSTRNCMP(curHdr->body, "base64", XSTRLEN("base64"))) { + WOLFSSL_MSG("S/MIME encodings other than base64 are not " + "currently supported.\n"); + goto error; + } + + if (section == NULL || sectionLen <= 0) { + goto error; + } + outLen = ((sectionLen*3+3)/4)+1; + out = (byte*)XMALLOC(outLen*sizeof(byte), NULL, DYNAMIC_TYPE_PKCS7); + outHead = out; + if (outHead == NULL) { + goto error; + } + /* Strip trailing newlines. */ + while ((sectionLen > 0) && + (section[sectionLen-1] == '\r' || section[sectionLen-1] == '\n')) { + sectionLen--; + } + section[sectionLen] = '\0'; + ret = Base64_Decode((const byte*)section, sectionLen, out, &outLen); + if (ret < 0) { + WOLFSSL_MSG("Error base64 decoding S/MIME message."); + goto error; + } + pkcs7 = wolfSSL_d2i_PKCS7_only(NULL, (const unsigned char**)&out, outLen, + bcontMem, bcontMemSz); + + wc_MIME_free_hdrs(allHdrs); + XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7); + XFREE(section, NULL, DYNAMIC_TYPE_PKCS7); + + return pkcs7; + +error: + wc_MIME_free_hdrs(allHdrs); + XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7); + XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7); + XFREE(section, NULL, DYNAMIC_TYPE_PKCS7); + if (canonSection != NULL) + XFREE(canonSection, NULL, DYNAMIC_TYPE_PKCS7); + if (canonLine != NULL) + XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); + if (bcont) { + wolfSSL_BIO_free(*bcont); + *bcont = NULL; /* reset 'bcount' pointer to NULL on failure */ + } + + return NULL; +} + +/* Convert hash algo OID (from Hash_Sum in asn.h) to SMIME string equivalent. + * Returns hash algorithm string or "unknown" if not found */ +static const char* wolfSSL_SMIME_HashOIDToString(int hashOID) +{ + switch (hashOID) { + case MD5h: + return "md5"; + case SHAh: + return "sha1"; + case SHA224h: + return "sha-224"; + case SHA256h: + return "sha-256"; + case SHA384h: + return "sha-384"; + case SHA512h: + return "sha-512"; + case SHA3_224h: + return "sha3-224"; + case SHA3_384h: + return "sha3-384"; + case SHA3_512h: + return "sha3-512"; + default: + break; + } + + return "unknown"; +} + +/* Convert PKCS#7 type (from PKCS7_TYPES in pkcs7.h) to SMIME string. + * RFC2633 only defines signed-data, enveloped-data, certs-only. + * Returns string on success, NULL on unknown type. */ +static const char* wolfSSL_SMIME_PKCS7TypeToString(int type) +{ + switch (type) { + case SIGNED_DATA: + return "signed-data"; + case ENVELOPED_DATA: + return "enveloped-data"; + default: + break; + } + + return NULL; +} + +/** + * Convert PKCS7 structure to SMIME format, adding necessary headers. + * + * Handles generation of PKCS7 bundle (ie: signedData). PKCS7 structure + * should be set up beforehand with PKCS7_sign/final/etc. Output is always + * Base64 encoded. + * + * out - output BIO for SMIME formatted data to be placed + * pkcs7 - input PKCS7 structure, initialized and set up + * in - input content to be encoded into PKCS7 + * flags - flags to control behavior of PKCS7 generation + * + * Returns 1 on success, 0 or negative on failure + */ +int wolfSSL_SMIME_write_PKCS7(WOLFSSL_BIO* out, PKCS7* pkcs7, WOLFSSL_BIO* in, + int flags) +{ + int i; + int ret = 1; + WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; + byte* p7out = NULL; + int len = 0; + + char boundary[33]; /* 32 chars + \0 */ + byte* sigBase64 = NULL; + word32 sigBase64Len = 0; + const char* p7TypeString = NULL; + + static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + if (out == NULL || p7 == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return 0; + } + + if (in != NULL && (p7->pkcs7.content == NULL || p7->pkcs7.contentSz == 0 || + p7->pkcs7.contentCRLF == 0)) { + /* store and adjust content line endings for CRLF if needed */ + if (wolfSSL_PKCS7_final((PKCS7*)p7, in, flags) != 1) { + ret = 0; + } + } + + if (ret > 0) { + /* Generate signedData bundle, DER in output (dynamic) */ + if ((len = wolfSSL_i2d_PKCS7((PKCS7*)p7, &p7out)) == WOLFSSL_FAILURE) { + WOLFSSL_MSG("Error in wolfSSL_i2d_PKCS7"); + ret = 0; + } + } + + /* Base64 encode signedData bundle */ + if (ret > 0) { + if (Base64_Encode(p7out, len, NULL, &sigBase64Len) != LENGTH_ONLY_E) { + ret = 0; + } + else { + sigBase64 = (byte*)XMALLOC(sigBase64Len, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (sigBase64 == NULL) { + ret = 0; + } + } + } + + if (ret > 0) { + XMEMSET(sigBase64, 0, sigBase64Len); + if (Base64_Encode(p7out, len, sigBase64, &sigBase64Len) < 0) { + WOLFSSL_MSG("Error in Base64_Encode of signature"); + ret = 0; + } + } + + /* build up SMIME message */ + if (ret > 0) { + if (flags & PKCS7_DETACHED) { + + /* generate random boundary */ + if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("No RNG to use"); + ret = 0; + } + + /* no need to generate random byte for null terminator (size-1) */ + if ((ret > 0) && (wc_RNG_GenerateBlock(&globalRNG, (byte*)boundary, + sizeof(boundary) - 1 ) != 0)) { + WOLFSSL_MSG("Error in wc_RNG_GenerateBlock"); + ret = 0; + } + + if (ret > 0) { + for (i = 0; i < (int)sizeof(boundary) - 1; i++) { + boundary[i] = + alphanum[boundary[i] % XSTR_SIZEOF(alphanum)]; + } + boundary[sizeof(boundary)-1] = 0; + } + + if (ret > 0) { + /* S/MIME header beginning */ + ret = wolfSSL_BIO_printf(out, + "MIME-Version: 1.0\n" + "Content-Type: multipart/signed; " + "protocol=\"application/x-pkcs7-signature\"; " + "micalg=\"%s\"; " + "boundary=\"----%s\"\n\n" + "This is an S/MIME signed message\n\n" + "------%s\n", + wolfSSL_SMIME_HashOIDToString(p7->pkcs7.hashOID), + boundary, boundary); + } + + if (ret > 0) { + /* S/MIME content */ + ret = wolfSSL_BIO_write(out, + p7->pkcs7.content, p7->pkcs7.contentSz); + } + + if (ret > 0) { + /* S/SMIME header end boundary */ + ret = wolfSSL_BIO_printf(out, + "\n------%s\n", boundary); + } + + if (ret > 0) { + /* Signature and header */ + ret = wolfSSL_BIO_printf(out, + "Content-Type: application/x-pkcs7-signature; " + "name=\"smime.p7s\"\n" + "Content-Transfer-Encoding: base64\n" + "Content-Disposition: attachment; " + "filename=\"smime.p7s\"\n\n" + "%.*s\n" /* Base64 encoded signature */ + "------%s--\n\n", + sigBase64Len, sigBase64, + boundary); + } + } + else { + p7TypeString = wolfSSL_SMIME_PKCS7TypeToString(p7->type); + if (p7TypeString == NULL) { + WOLFSSL_MSG("Unsupported PKCS7 SMIME type"); + ret = 0; + } + + if (ret > 0) { + /* not detached */ + ret = wolfSSL_BIO_printf(out, + "MIME-Version: 1.0\n" + "Content-Disposition: attachment; " + "filename=\"smime.p7m\"\n" + "Content-Type: application/x-pkcs7-mime; " + "smime-type=%s; name=\"smime.p7m\"\n" + "Content-Transfer-Encoding: base64\n\n" + "%.*s\n" /* signature */, + p7TypeString, sigBase64Len, sigBase64); + } + } + } + + if (p7out != NULL) { + XFREE(p7out, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + if (sigBase64 != NULL) { + XFREE(sigBase64, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + + if (ret > 0) { + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + +#endif /* HAVE_SMIME */ +#endif /* !NO_BIO */ +#endif /* OPENSSL_ALL */ + +#endif /* HAVE_PKCS7 */ +/******************************************************************************* + * END OF PKCS7 APIs + ******************************************************************************/ + +/******************************************************************************* + * START OF PKCS12 APIs + ******************************************************************************/ +#ifdef OPENSSL_EXTRA + +/* no-op function. Was initially used for adding encryption algorithms available + * for PKCS12 */ +void wolfSSL_PKCS12_PBE_add(void) +{ + WOLFSSL_ENTER("wolfSSL_PKCS12_PBE_add"); +} + +#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) +WOLFSSL_X509_PKCS12 *wolfSSL_d2i_PKCS12_fp(XFILE fp, + WOLFSSL_X509_PKCS12 **pkcs12) +{ + WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_fp"); + return (WOLFSSL_X509_PKCS12 *)wolfSSL_d2i_X509_fp_ex(fp, (void **)pkcs12, + PKCS12_TYPE); +} +#endif /* !NO_FILESYSTEM */ + +#endif /* OPENSSL_EXTRA */ + +#if defined(HAVE_PKCS12) + +#ifdef OPENSSL_EXTRA + +#if !defined(NO_ASN) && !defined(NO_PWDBASED) + +#ifndef NO_BIO +WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio, WC_PKCS12** pkcs12) +{ + WC_PKCS12* localPkcs12 = NULL; + unsigned char* mem = NULL; + long memSz; + int ret = -1; + + WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_bio"); + + if (bio == NULL) { + WOLFSSL_MSG("Bad Function Argument bio is NULL"); + return NULL; + } + + memSz = wolfSSL_BIO_get_len(bio); + if (memSz <= 0) { + return NULL; + } + mem = (unsigned char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + return NULL; + } + + if (mem != NULL) { + localPkcs12 = wc_PKCS12_new(); + if (localPkcs12 == NULL) { + WOLFSSL_MSG("Memory error"); + } + } + + if (mem != NULL && localPkcs12 != NULL) { + if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) { + ret = wc_d2i_PKCS12(mem, (word32)memSz, localPkcs12); + if (ret < 0) { + WOLFSSL_MSG("Failed to get PKCS12 sequence"); + } + } + else { + WOLFSSL_MSG("Failed to get data from bio struct"); + } + } + + /* cleanup */ + if (mem != NULL) + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (ret < 0 && localPkcs12 != NULL) { + wc_PKCS12_free(localPkcs12); + localPkcs12 = NULL; + } + if (pkcs12 != NULL) + *pkcs12 = localPkcs12; + + return localPkcs12; +} + +/* Converts the PKCS12 to DER format and outputs it into bio. + * + * bio is the structure to hold output DER + * pkcs12 structure to create DER from + * + * return 1 for success or 0 if an error occurs + */ +int wolfSSL_i2d_PKCS12_bio(WOLFSSL_BIO *bio, WC_PKCS12 *pkcs12) +{ + int ret = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_i2d_PKCS12_bio"); + + if ((bio != NULL) && (pkcs12 != NULL)) { + word32 certSz = 0; + byte *certDer = NULL; + + certSz = wc_i2d_PKCS12(pkcs12, &certDer, NULL); + if ((certSz > 0) && (certDer != NULL)) { + if (wolfSSL_BIO_write(bio, certDer, certSz) == (int)certSz) { + ret = WOLFSSL_SUCCESS; + } + } + + if (certDer != NULL) { + XFREE(certDer, NULL, DYNAMIC_TYPE_PKCS); + } + } + + return ret; +} +#endif /* !NO_BIO */ + +/* Creates a new WC_PKCS12 structure + * + * pass password to use + * name friendlyName to use + * pkey private key to go into PKCS12 bundle + * cert certificate to go into PKCS12 bundle + * ca extra certificates that can be added to bundle. Can be NULL + * keyNID type of encryption to use on the key (-1 means no encryption) + * certNID type of encryption to use on the certificate + * itt number of iterations with encryption + * macItt number of iterations with mac creation + * keyType flag for signature and/or encryption key + * + * returns a pointer to a new WC_PKCS12 structure on success and NULL on fail + */ +WC_PKCS12* wolfSSL_PKCS12_create(char* pass, char* name, WOLFSSL_EVP_PKEY* pkey, + WOLFSSL_X509* cert, WOLF_STACK_OF(WOLFSSL_X509)* ca, int keyNID, + int certNID, int itt, int macItt, int keyType) +{ + WC_PKCS12* pkcs12; + WC_DerCertList* list = NULL; + word32 passSz; + byte* keyDer = NULL; + word32 keyDerSz; + byte* certDer; + int certDerSz; + + WOLFSSL_ENTER("wolfSSL_PKCS12_create"); + + if (pass == NULL || pkey == NULL || cert == NULL) { + WOLFSSL_LEAVE("wolfSSL_PKCS12_create", BAD_FUNC_ARG); + return NULL; + } + passSz = (word32)XSTRLEN(pass); + + keyDer = (byte*)pkey->pkey.ptr; + keyDerSz = pkey->pkey_sz; + + certDer = (byte*)wolfSSL_X509_get_der(cert, &certDerSz); + if (certDer == NULL) { + return NULL; + } + + if (ca != NULL) { + unsigned long numCerts = ca->num; + WOLFSSL_STACK* sk = ca; + + while (numCerts > 0 && sk != NULL) { + byte* curDer; + WC_DerCertList* cur; + int curDerSz = 0; + + cur = (WC_DerCertList*)XMALLOC(sizeof(WC_DerCertList), NULL, + DYNAMIC_TYPE_PKCS); + if (cur == NULL) { + wc_FreeCertList(list, NULL); + return NULL; + } + + curDer = (byte*)wolfSSL_X509_get_der(sk->data.x509, &curDerSz); + if (curDer == NULL || curDerSz < 0) { + XFREE(cur, NULL, DYNAMIC_TYPE_PKCS); + wc_FreeCertList(list, NULL); + return NULL; + } + + cur->buffer = (byte*)XMALLOC(curDerSz, NULL, DYNAMIC_TYPE_PKCS); + if (cur->buffer == NULL) { + XFREE(cur, NULL, DYNAMIC_TYPE_PKCS); + wc_FreeCertList(list, NULL); + return NULL; + } + XMEMCPY(cur->buffer, curDer, curDerSz); + cur->bufferSz = curDerSz; + cur->next = list; + list = cur; + + sk = sk->next; + numCerts--; + } + } + + pkcs12 = wc_PKCS12_create(pass, passSz, name, keyDer, keyDerSz, + certDer, certDerSz, list, keyNID, certNID, itt, macItt, + keyType, NULL); + + if (ca != NULL) { + wc_FreeCertList(list, NULL); + } + + return pkcs12; +} + + +/* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure */ +int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw, + WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, + WOLF_STACK_OF(WOLFSSL_X509)** ca) +{ + void* heap = NULL; + int ret; + byte* certData = NULL; + word32 certDataSz; + byte* pk = NULL; + word32 pkSz; + WC_DerCertList* certList = NULL; +#ifdef WOLFSSL_SMALL_STACK + DecodedCert *DeCert; +#else + DecodedCert DeCert[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_PKCS12_parse"); + + /* make sure we init return args */ + if (pkey) *pkey = NULL; + if (cert) *cert = NULL; + if (ca) *ca = NULL; + + if (pkcs12 == NULL || psw == NULL || pkey == NULL || cert == NULL) { + WOLFSSL_MSG("Bad argument value"); + return WOLFSSL_FAILURE; + } + + heap = wc_PKCS12_GetHeap(pkcs12); + + if (ca == NULL) { + ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz, + NULL); + } + else { + ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz, + &certList); + } + if (ret < 0) { + WOLFSSL_LEAVE("wolfSSL_PKCS12_parse", ret); + return WOLFSSL_FAILURE; + } + +#ifdef WOLFSSL_SMALL_STACK + DeCert = (DecodedCert *)XMALLOC(sizeof(*DeCert), heap, + DYNAMIC_TYPE_DCERT); + if (DeCert == NULL) { + WOLFSSL_MSG("out of memory"); + return WOLFSSL_FAILURE; + } +#endif + + /* Decode cert and place in X509 stack struct */ + if (certList != NULL) { + WC_DerCertList* current = certList; + + *ca = (WOLF_STACK_OF(WOLFSSL_X509)*)XMALLOC( + sizeof(WOLF_STACK_OF(WOLFSSL_X509)), heap, DYNAMIC_TYPE_X509); + if (*ca == NULL) { + if (pk != NULL) { + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + if (certData != NULL) { + XFREE(certData, heap, DYNAMIC_TYPE_PKCS); + } + /* Free up WC_DerCertList and move on */ + while (current != NULL) { + WC_DerCertList* next = current->next; + + XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); + XFREE(current, heap, DYNAMIC_TYPE_PKCS); + current = next; + } + ret = WOLFSSL_FAILURE; + goto out; + } + XMEMSET(*ca, 0, sizeof(WOLF_STACK_OF(WOLFSSL_X509))); + + /* add list of DER certs as X509's to stack */ + while (current != NULL) { + WC_DerCertList* toFree = current; + WOLFSSL_X509* x509; + + x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, + DYNAMIC_TYPE_X509); + InitX509(x509, 1, heap); + InitDecodedCert(DeCert, current->buffer, current->bufferSz, heap); + if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL) != 0) { + WOLFSSL_MSG("Issue with parsing certificate"); + FreeDecodedCert(DeCert); + wolfSSL_X509_free(x509); + } + else { + if (CopyDecodedToX509(x509, DeCert) != 0) { + WOLFSSL_MSG("Failed to copy decoded cert"); + FreeDecodedCert(DeCert); + wolfSSL_X509_free(x509); + wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; + if (pk != NULL) { + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + if (certData != NULL) { + XFREE(certData, heap, DYNAMIC_TYPE_PKCS); + } + /* Free up WC_DerCertList */ + while (current != NULL) { + WC_DerCertList* next = current->next; + + XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); + XFREE(current, heap, DYNAMIC_TYPE_PKCS); + current = next; + } + ret = WOLFSSL_FAILURE; + goto out; + } + FreeDecodedCert(DeCert); + + if (wolfSSL_sk_X509_push(*ca, x509) != 1) { + WOLFSSL_MSG("Failed to push x509 onto stack"); + wolfSSL_X509_free(x509); + wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; + if (pk != NULL) { + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + if (certData != NULL) { + XFREE(certData, heap, DYNAMIC_TYPE_PKCS); + } + + /* Free up WC_DerCertList */ + while (current != NULL) { + WC_DerCertList* next = current->next; + + XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); + XFREE(current, heap, DYNAMIC_TYPE_PKCS); + current = next; + } + ret = WOLFSSL_FAILURE; + goto out; + } + } + current = current->next; + XFREE(toFree->buffer, heap, DYNAMIC_TYPE_PKCS); + XFREE(toFree, heap, DYNAMIC_TYPE_PKCS); + } + } + + + /* Decode cert and place in X509 struct */ + if (certData != NULL) { + *cert = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, + DYNAMIC_TYPE_X509); + if (*cert == NULL) { + if (pk != NULL) { + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + if (ca != NULL) { + wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; + } + XFREE(certData, heap, DYNAMIC_TYPE_PKCS); + ret = WOLFSSL_FAILURE; + goto out; + } + InitX509(*cert, 1, heap); + InitDecodedCert(DeCert, certData, certDataSz, heap); + if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL) != 0) { + WOLFSSL_MSG("Issue with parsing certificate"); + } + if (CopyDecodedToX509(*cert, DeCert) != 0) { + WOLFSSL_MSG("Failed to copy decoded cert"); + FreeDecodedCert(DeCert); + if (pk != NULL) { + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + if (ca != NULL) { + wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; + } + wolfSSL_X509_free(*cert); *cert = NULL; + XFREE(certData, heap, DYNAMIC_TYPE_PKCS); + ret = WOLFSSL_FAILURE; + goto out; + } + FreeDecodedCert(DeCert); + XFREE(certData, heap, DYNAMIC_TYPE_PKCS); + } + + + /* get key type */ + ret = BAD_STATE_E; + if (pk != NULL) { /* decode key if present */ + *pkey = wolfSSL_EVP_PKEY_new_ex(heap); + if (*pkey == NULL) { + wolfSSL_X509_free(*cert); *cert = NULL; + if (ca != NULL) { + wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; + } + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + ret = WOLFSSL_FAILURE; + goto out; + } + + #ifndef NO_RSA + { + const unsigned char* pt = pk; + if (wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, pkey, &pt, pkSz) != + NULL) { + ret = 0; + } + } + #endif /* NO_RSA */ + + #ifdef HAVE_ECC + if (ret != 0) { /* if is in fail state check if ECC key */ + const unsigned char* pt = pk; + if (wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, pkey, &pt, pkSz) != + NULL) { + ret = 0; + } + } + #endif /* HAVE_ECC */ + if (pk != NULL) + XFREE(pk, heap, DYNAMIC_TYPE_PKCS); + if (ret != 0) { /* if is in fail state and no PKEY then fail */ + wolfSSL_X509_free(*cert); *cert = NULL; + if (ca != NULL) { + wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; + } + wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL; + WOLFSSL_MSG("Bad PKCS12 key format"); + ret = WOLFSSL_FAILURE; + goto out; + } + + if (pkey != NULL && *pkey != NULL) { + (*pkey)->save_type = 0; + } + } + + (void)ret; + (void)ca; + + ret = WOLFSSL_SUCCESS; + +out: + +#ifdef WOLFSSL_SMALL_STACK + XFREE(DeCert, heap, DYNAMIC_TYPE_DCERT); +#endif + + return ret; +} + +int wolfSSL_PKCS12_verify_mac(WC_PKCS12 *pkcs12, const char *psw, + int pswLen) +{ + WOLFSSL_ENTER("wolfSSL_PKCS12_verify_mac"); + + if (!pkcs12) { + return WOLFSSL_FAILURE; + } + + return wc_PKCS12_verify_ex(pkcs12, (const byte*)psw, pswLen) == 0 ? + WOLFSSL_SUCCESS : WOLFSSL_FAILURE; +} + +#endif /* !NO_ASN && !NO_PWDBASED */ + +#endif /* OPENSSL_EXTRA */ + +#endif /* HAVE_PKCS12 */ +/******************************************************************************* + * END OF PKCS12 APIs + ******************************************************************************/ + +#endif /* !WOLFCRYPT_ONLY && !NO_CERTS */ + +#endif /* !WOLFSSL_SSL_P7P12_INCLUDED */ diff --git a/src/ssl_sess.c b/src/ssl_sess.c new file mode 100644 index 000000000..4a2b1f7c2 --- /dev/null +++ b/src/ssl_sess.c @@ -0,0 +1,4535 @@ +/* ssl_sess.c + * + * Copyright (C) 2006-2024 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#if !defined(WOLFSSL_SSL_SESS_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_sess.c does not need to be compiled separately from ssl.c + #endif +#else + +#ifndef NO_SESSION_CACHE + + /* basic config gives a cache with 33 sessions, adequate for clients and + embedded servers + + TITAN_SESSION_CACHE allows just over 2 million sessions, for servers + with titanic amounts of memory with long session ID timeouts and high + levels of traffic. + + ENABLE_SESSION_CACHE_ROW_LOCK: Allows row level locking for increased + performance with large session caches + + HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load, + allows over 13,000 new sessions per minute or over 200 new sessions per + second + + BIG_SESSION_CACHE yields 20,027 sessions + + MEDIUM_SESSION_CACHE allows 1055 sessions, adequate for servers that + aren't under heavy load, basically allows 200 new sessions per minute + + SMALL_SESSION_CACHE only stores 6 sessions, good for embedded clients + or systems where the default of is too much RAM. + SessionCache takes about 2K, ClientCache takes about 3Kbytes + + MICRO_SESSION_CACHE only stores 1 session, good for embedded clients + or systems where memory is at a premium. + SessionCache takes about 400 bytes, ClientCache takes 576 bytes + + default SESSION_CACHE stores 33 sessions (no XXX_SESSION_CACHE defined) + SessionCache takes about 13K bytes, ClientCache takes 17K bytes + */ + #if defined(TITAN_SESSION_CACHE) + #define SESSIONS_PER_ROW 31 + #define SESSION_ROWS 64937 + #ifndef ENABLE_SESSION_CACHE_ROW_LOCK + #define ENABLE_SESSION_CACHE_ROW_LOCK + #endif + #elif defined(HUGE_SESSION_CACHE) + #define SESSIONS_PER_ROW 11 + #define SESSION_ROWS 5981 + #elif defined(BIG_SESSION_CACHE) + #define SESSIONS_PER_ROW 7 + #define SESSION_ROWS 2861 + #elif defined(MEDIUM_SESSION_CACHE) + #define SESSIONS_PER_ROW 5 + #define SESSION_ROWS 211 + #elif defined(SMALL_SESSION_CACHE) + #define SESSIONS_PER_ROW 2 + #define SESSION_ROWS 3 + #elif defined(MICRO_SESSION_CACHE) + #define SESSIONS_PER_ROW 1 + #define SESSION_ROWS 1 + #else + #define SESSIONS_PER_ROW 3 + #define SESSION_ROWS 11 + #endif + #define INVALID_SESSION_ROW (-1) + + #ifdef NO_SESSION_CACHE_ROW_LOCK + #undef ENABLE_SESSION_CACHE_ROW_LOCK + #endif + + typedef struct SessionRow { + int nextIdx; /* where to place next one */ + int totalCount; /* sessions ever on this row */ +#ifdef SESSION_CACHE_DYNAMIC_MEM + WOLFSSL_SESSION* Sessions[SESSIONS_PER_ROW]; + void* heap; +#else + WOLFSSL_SESSION Sessions[SESSIONS_PER_ROW]; +#endif + + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + /* not included in import/export */ + wolfSSL_RwLock row_lock; + int lock_valid; + #endif + } SessionRow; + #define SIZEOF_SESSION_ROW (sizeof(WOLFSSL_SESSION) + (sizeof(int) * 2)) + + static WOLFSSL_GLOBAL SessionRow SessionCache[SESSION_ROWS]; + + #if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) + static WOLFSSL_GLOBAL word32 PeakSessions; + #endif + + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + #define SESSION_ROW_RD_LOCK(row) wc_LockRwLock_Rd(&(row)->row_lock) + #define SESSION_ROW_WR_LOCK(row) wc_LockRwLock_Wr(&(row)->row_lock) + #define SESSION_ROW_UNLOCK(row) wc_UnLockRwLock(&(row)->row_lock); + #else + static WOLFSSL_GLOBAL wolfSSL_RwLock session_lock; /* SessionCache lock */ + static WOLFSSL_GLOBAL int session_lock_valid = 0; + #define SESSION_ROW_RD_LOCK(row) wc_LockRwLock_Rd(&session_lock) + #define SESSION_ROW_WR_LOCK(row) wc_LockRwLock_Wr(&session_lock) + #define SESSION_ROW_UNLOCK(row) wc_UnLockRwLock(&session_lock); + #endif + + #if !defined(NO_SESSION_CACHE_REF) && defined(NO_CLIENT_CACHE) + #error ClientCache is required when not using NO_SESSION_CACHE_REF + #endif + + #ifndef NO_CLIENT_CACHE + + #ifndef CLIENT_SESSIONS_MULTIPLIER + #ifdef NO_SESSION_CACHE_REF + #define CLIENT_SESSIONS_MULTIPLIER 1 + #else + /* ClientSession objects are lightweight (compared to + * WOLFSSL_SESSION) so to decrease chance that user will reuse + * the wrong session, increase the ClientCache size. This will + * make the entire ClientCache about the size of one + * WOLFSSL_SESSION object. */ + #define CLIENT_SESSIONS_MULTIPLIER 8 + #endif + #endif + #define CLIENT_SESSIONS_PER_ROW \ + (SESSIONS_PER_ROW * CLIENT_SESSIONS_MULTIPLIER) + #define CLIENT_SESSION_ROWS (SESSION_ROWS * CLIENT_SESSIONS_MULTIPLIER) + + #if CLIENT_SESSIONS_PER_ROW > 65535 + #error CLIENT_SESSIONS_PER_ROW too big + #endif + #if CLIENT_SESSION_ROWS > 65535 + #error CLIENT_SESSION_ROWS too big + #endif + + struct ClientSession { + word16 serverRow; /* SessionCache Row id */ + word16 serverIdx; /* SessionCache Idx (column) */ + word32 sessionIDHash; + }; + #ifndef WOLFSSL_CLIENT_SESSION_DEFINED + typedef struct ClientSession ClientSession; + #define WOLFSSL_CLIENT_SESSION_DEFINED + #endif + + typedef struct ClientRow { + int nextIdx; /* where to place next one */ + int totalCount; /* sessions ever on this row */ + ClientSession Clients[CLIENT_SESSIONS_PER_ROW]; + } ClientRow; + + static WOLFSSL_GLOBAL ClientRow ClientCache[CLIENT_SESSION_ROWS]; + /* Client Cache */ + /* uses session mutex */ + + /* ClientCache mutex */ + static WOLFSSL_GLOBAL wolfSSL_Mutex clisession_mutex + WOLFSSL_MUTEX_INITIALIZER_CLAUSE(clisession_mutex); + #ifndef WOLFSSL_MUTEX_INITIALIZER + static WOLFSSL_GLOBAL int clisession_mutex_valid = 0; + #endif + #endif /* !NO_CLIENT_CACHE */ + + void EvictSessionFromCache(WOLFSSL_SESSION* session) + { +#ifdef HAVE_EX_DATA + int save_ownExData = session->ownExData; + session->ownExData = 1; /* Make sure ex_data access doesn't lead back + * into the cache. */ +#endif +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + if (session->rem_sess_cb != NULL) { + session->rem_sess_cb(NULL, session); + session->rem_sess_cb = NULL; + } +#endif + ForceZero(session->masterSecret, SECRET_LEN); + XMEMSET(session->sessionID, 0, ID_LEN); + session->sessionIDSz = 0; +#ifdef HAVE_SESSION_TICKET + if (session->ticketLenAlloc > 0) { + XFREE(session->ticket, NULL, DYNAMIC_TYPE_SESSION_TICK); + session->ticket = session->staticTicket; + session->ticketLen = 0; + session->ticketLenAlloc = 0; + } +#endif +#ifdef HAVE_EX_DATA + session->ownExData = save_ownExData; +#endif + } + +WOLFSSL_ABI +WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_session"); + if (ssl) { +#ifdef NO_SESSION_CACHE_REF + return ssl->session; +#else + if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* On the client side we want to return a persistent reference for + * backwards compatibility. */ +#ifndef NO_CLIENT_CACHE + if (ssl->clientSession) { + return (WOLFSSL_SESSION*)ssl->clientSession; + } + else { + /* Try to add a ClientCache entry to associate with the current + * session. Ignore any session cache options. */ + int err; + const byte* id = ssl->session->sessionID; + byte idSz = ssl->session->sessionIDSz; + if (ssl->session->haveAltSessionID) { + id = ssl->session->altSessionID; + idSz = ID_LEN; + } + err = AddSessionToCache(ssl->ctx, ssl->session, id, idSz, + NULL, ssl->session->side, + #ifdef HAVE_SESSION_TICKET + ssl->session->ticketLen > 0, + #else + 0, + #endif + &ssl->clientSession); + if (err == 0) { + return (WOLFSSL_SESSION*)ssl->clientSession; + } + } +#endif + } + else { + return ssl->session; + } +#endif + } + + return NULL; +} + +/* The get1 version requires caller to call SSL_SESSION_free */ +WOLFSSL_SESSION* wolfSSL_get1_session(WOLFSSL* ssl) +{ + WOLFSSL_SESSION* sess = NULL; + WOLFSSL_ENTER("wolfSSL_get1_session"); + if (ssl != NULL) { + sess = ssl->session; + if (sess != NULL) { + /* increase reference count if allocated session */ + if (sess->type == WOLFSSL_SESSION_TYPE_HEAP) { + if (wolfSSL_SESSION_up_ref(sess) != WOLFSSL_SUCCESS) + sess = NULL; + } + } + } + return sess; +} + + +/* + * Sets the session object to use when establishing a TLS/SSL session using + * the ssl object. Therefore, this function must be called before + * wolfSSL_connect. The session object to use can be obtained in a previous + * TLS/SSL connection using wolfSSL_get_session. + * + * This function rejects the session if it has been expired when this function + * is called. Note that this expiration check is wolfSSL specific and differs + * from OpenSSL return code behavior. + * + * By default, wolfSSL_set_session returns WOLFSSL_SUCCESS on successfully + * setting the session, WOLFSSL_FAILURE on failure due to the session cache + * being disabled, or the session has expired. + * + * To match OpenSSL return code behavior when session is expired, define + * OPENSSL_EXTRA and WOLFSSL_ERROR_CODE_OPENSSL. This behavior will return + * WOLFSSL_SUCCESS even when the session is expired and rejected. + */ +WOLFSSL_ABI +int wolfSSL_set_session(WOLFSSL* ssl, WOLFSSL_SESSION* session) +{ + WOLFSSL_ENTER("wolfSSL_set_session"); + if (session) + return wolfSSL_SetSession(ssl, session); + + return WOLFSSL_FAILURE; +} + + +#ifndef NO_CLIENT_CACHE + +/* Associate client session with serverID, find existing or store for saving + if newSession flag on, don't reuse existing session + WOLFSSL_SUCCESS on ok */ +int wolfSSL_SetServerID(WOLFSSL* ssl, const byte* id, int len, int newSession) +{ + WOLFSSL_SESSION* session = NULL; + byte idHash[SERVER_ID_LEN]; + + WOLFSSL_ENTER("wolfSSL_SetServerID"); + + if (ssl == NULL || id == NULL || len <= 0) + return BAD_FUNC_ARG; + + if (len > SERVER_ID_LEN) { +#if defined(NO_SHA) && !defined(NO_SHA256) + if (wc_Sha256Hash(id, len, idHash) != 0) + return WOLFSSL_FAILURE; +#else + if (wc_ShaHash(id, len, idHash) != 0) + return WOLFSSL_FAILURE; +#endif + id = idHash; + len = SERVER_ID_LEN; + } + + if (newSession == 0) { + session = wolfSSL_GetSessionClient(ssl, id, len); + if (session) { + if (wolfSSL_SetSession(ssl, session) != WOLFSSL_SUCCESS) { + #ifdef HAVE_EXT_CACHE + wolfSSL_FreeSession(ssl->ctx, session); + #endif + WOLFSSL_MSG("wolfSSL_SetSession failed"); + session = NULL; + } + } + } + + if (session == NULL) { + WOLFSSL_MSG("Valid ServerID not cached already"); + + ssl->session->idLen = (word16)len; + XMEMCPY(ssl->session->serverID, id, len); + } +#ifdef HAVE_EXT_CACHE + else { + wolfSSL_FreeSession(ssl->ctx, session); + } +#endif + + return WOLFSSL_SUCCESS; +} + +#endif /* !NO_CLIENT_CACHE */ + +/* TODO: Add SESSION_CACHE_DYNAMIC_MEM support for PERSIST_SESSION_CACHE. + * Need a count of current sessions to get an accurate memsize (totalCount is + * not decremented when sessions are removed). + * Need to determine ideal layout for mem/filesave. + * Also need mem/filesave checking to ensure not restoring non DYNAMIC_MEM + * cache. + */ +#if defined(PERSIST_SESSION_CACHE) && !defined(SESSION_CACHE_DYNAMIC_MEM) + +/* for persistence, if changes to layout need to increment and modify + save_session_cache() and restore_session_cache and memory versions too */ +#define WOLFSSL_CACHE_VERSION 2 + +/* Session Cache Header information */ +typedef struct { + int version; /* cache layout version id */ + int rows; /* session rows */ + int columns; /* session columns */ + int sessionSz; /* sizeof WOLFSSL_SESSION */ +} cache_header_t; + +/* current persistence layout is: + + 1) cache_header_t + 2) SessionCache + 3) ClientCache + + update WOLFSSL_CACHE_VERSION if change layout for the following + PERSISTENT_SESSION_CACHE functions +*/ + +/* get how big the the session cache save buffer needs to be */ +int wolfSSL_get_session_cache_memsize(void) +{ + int sz = (int)(sizeof(SessionCache) + sizeof(cache_header_t)); +#ifndef NO_CLIENT_CACHE + sz += (int)(sizeof(ClientCache)); +#endif + return sz; +} + + +/* Persist session cache to memory */ +int wolfSSL_memsave_session_cache(void* mem, int sz) +{ + int i; + cache_header_t cache_header; + SessionRow* row = (SessionRow*)((byte*)mem + sizeof(cache_header)); + + WOLFSSL_ENTER("wolfSSL_memsave_session_cache"); + + if (sz < wolfSSL_get_session_cache_memsize()) { + WOLFSSL_MSG("Memory buffer too small"); + return BUFFER_E; + } + + cache_header.version = WOLFSSL_CACHE_VERSION; + cache_header.rows = SESSION_ROWS; + cache_header.columns = SESSIONS_PER_ROW; + cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION); + XMEMCPY(mem, &cache_header, sizeof(cache_header)); + +#ifndef ENABLE_SESSION_CACHE_ROW_LOCK + if (SESSION_ROW_RD_LOCK(row) != 0) { + WOLFSSL_MSG("Session cache mutex lock failed"); + return BAD_MUTEX_E; + } +#endif + for (i = 0; i < cache_header.rows; ++i) { + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + if (SESSION_ROW_RD_LOCK(&SessionCache[i]) != 0) { + WOLFSSL_MSG("Session row cache mutex lock failed"); + return BAD_MUTEX_E; + } + #endif + + XMEMCPY(row++, &SessionCache[i], SIZEOF_SESSION_ROW); + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_UNLOCK(&SessionCache[i]); + #endif + } +#ifndef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_UNLOCK(row); +#endif + +#ifndef NO_CLIENT_CACHE + if (wc_LockMutex(&clisession_mutex) != 0) { + WOLFSSL_MSG("Client cache mutex lock failed"); + return BAD_MUTEX_E; + } + XMEMCPY(row, ClientCache, sizeof(ClientCache)); + wc_UnLockMutex(&clisession_mutex); +#endif + + WOLFSSL_LEAVE("wolfSSL_memsave_session_cache", WOLFSSL_SUCCESS); + + return WOLFSSL_SUCCESS; +} + + +/* Restore the persistent session cache from memory */ +int wolfSSL_memrestore_session_cache(const void* mem, int sz) +{ + int i; + cache_header_t cache_header; + SessionRow* row = (SessionRow*)((byte*)mem + sizeof(cache_header)); + + WOLFSSL_ENTER("wolfSSL_memrestore_session_cache"); + + if (sz < wolfSSL_get_session_cache_memsize()) { + WOLFSSL_MSG("Memory buffer too small"); + return BUFFER_E; + } + + XMEMCPY(&cache_header, mem, sizeof(cache_header)); + if (cache_header.version != WOLFSSL_CACHE_VERSION || + cache_header.rows != SESSION_ROWS || + cache_header.columns != SESSIONS_PER_ROW || + cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) { + + WOLFSSL_MSG("Session cache header match failed"); + return CACHE_MATCH_ERROR; + } + +#ifndef ENABLE_SESSION_CACHE_ROW_LOCK + if (SESSION_ROW_WR_LOCK(&SessionCache[0]) != 0) { + WOLFSSL_MSG("Session cache mutex lock failed"); + return BAD_MUTEX_E; + } +#endif + for (i = 0; i < cache_header.rows; ++i) { + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) { + WOLFSSL_MSG("Session row cache mutex lock failed"); + return BAD_MUTEX_E; + } + #endif + + XMEMCPY(&SessionCache[i], row++, SIZEOF_SESSION_ROW); + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_UNLOCK(&SessionCache[i]); + #endif + } +#ifndef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_UNLOCK(&SessionCache[0]); +#endif + +#ifndef NO_CLIENT_CACHE + if (wc_LockMutex(&clisession_mutex) != 0) { + WOLFSSL_MSG("Client cache mutex lock failed"); + return BAD_MUTEX_E; + } + XMEMCPY(ClientCache, row, sizeof(ClientCache)); + wc_UnLockMutex(&clisession_mutex); +#endif + + WOLFSSL_LEAVE("wolfSSL_memrestore_session_cache", WOLFSSL_SUCCESS); + + return WOLFSSL_SUCCESS; +} + +#if !defined(NO_FILESYSTEM) + +/* Persist session cache to file */ +/* doesn't use memsave because of additional memory use */ +int wolfSSL_save_session_cache(const char *fname) +{ + XFILE file; + int ret; + int rc = WOLFSSL_SUCCESS; + int i; + cache_header_t cache_header; + + WOLFSSL_ENTER("wolfSSL_save_session_cache"); + + file = XFOPEN(fname, "w+b"); + if (file == XBADFILE) { + WOLFSSL_MSG("Couldn't open session cache save file"); + return WOLFSSL_BAD_FILE; + } + cache_header.version = WOLFSSL_CACHE_VERSION; + cache_header.rows = SESSION_ROWS; + cache_header.columns = SESSIONS_PER_ROW; + cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION); + + /* cache header */ + ret = (int)XFWRITE(&cache_header, sizeof cache_header, 1, file); + if (ret != 1) { + WOLFSSL_MSG("Session cache header file write failed"); + XFCLOSE(file); + return FWRITE_ERROR; + } + +#ifndef ENABLE_SESSION_CACHE_ROW_LOCK + if (SESSION_ROW_RD_LOCK(&SessionCache[0]) != 0) { + WOLFSSL_MSG("Session cache mutex lock failed"); + XFCLOSE(file); + return BAD_MUTEX_E; + } +#endif + /* session cache */ + for (i = 0; i < cache_header.rows; ++i) { + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + if (SESSION_ROW_RD_LOCK(&SessionCache[i]) != 0) { + WOLFSSL_MSG("Session row cache mutex lock failed"); + XFCLOSE(file); + return BAD_MUTEX_E; + } + #endif + + ret = (int)XFWRITE(&SessionCache[i], SIZEOF_SESSION_ROW, 1, file); + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_UNLOCK(&SessionCache[i]); + #endif + if (ret != 1) { + WOLFSSL_MSG("Session cache member file write failed"); + rc = FWRITE_ERROR; + break; + } + } +#ifndef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_UNLOCK(&SessionCache[0]); +#endif + +#ifndef NO_CLIENT_CACHE + /* client cache */ + if (wc_LockMutex(&clisession_mutex) != 0) { + WOLFSSL_MSG("Client cache mutex lock failed"); + XFCLOSE(file); + return BAD_MUTEX_E; + } + ret = (int)XFWRITE(ClientCache, sizeof(ClientCache), 1, file); + if (ret != 1) { + WOLFSSL_MSG("Client cache member file write failed"); + rc = FWRITE_ERROR; + } + wc_UnLockMutex(&clisession_mutex); +#endif /* !NO_CLIENT_CACHE */ + + XFCLOSE(file); + WOLFSSL_LEAVE("wolfSSL_save_session_cache", rc); + + return rc; +} + + +/* Restore the persistent session cache from file */ +/* doesn't use memstore because of additional memory use */ +int wolfSSL_restore_session_cache(const char *fname) +{ + XFILE file; + int rc = WOLFSSL_SUCCESS; + int ret; + int i; + cache_header_t cache_header; + + WOLFSSL_ENTER("wolfSSL_restore_session_cache"); + + file = XFOPEN(fname, "rb"); + if (file == XBADFILE) { + WOLFSSL_MSG("Couldn't open session cache save file"); + return WOLFSSL_BAD_FILE; + } + /* cache header */ + ret = (int)XFREAD(&cache_header, sizeof(cache_header), 1, file); + if (ret != 1) { + WOLFSSL_MSG("Session cache header file read failed"); + XFCLOSE(file); + return FREAD_ERROR; + } + if (cache_header.version != WOLFSSL_CACHE_VERSION || + cache_header.rows != SESSION_ROWS || + cache_header.columns != SESSIONS_PER_ROW || + cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) { + + WOLFSSL_MSG("Session cache header match failed"); + XFCLOSE(file); + return CACHE_MATCH_ERROR; + } + +#ifndef ENABLE_SESSION_CACHE_ROW_LOCK + if (SESSION_ROW_WR_LOCK(&SessionCache[0]) != 0) { + WOLFSSL_MSG("Session cache mutex lock failed"); + XFCLOSE(file); + return BAD_MUTEX_E; + } +#endif + /* session cache */ + for (i = 0; i < cache_header.rows; ++i) { + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) { + WOLFSSL_MSG("Session row cache mutex lock failed"); + XFCLOSE(file); + return BAD_MUTEX_E; + } + #endif + + ret = (int)XFREAD(&SessionCache[i], SIZEOF_SESSION_ROW, 1, file); + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_UNLOCK(&SessionCache[i]); + #endif + if (ret != 1) { + WOLFSSL_MSG("Session cache member file read failed"); + XMEMSET(SessionCache, 0, sizeof SessionCache); + rc = FREAD_ERROR; + break; + } + } +#ifndef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_UNLOCK(&SessionCache[0]); +#endif + +#ifndef NO_CLIENT_CACHE + /* client cache */ + if (wc_LockMutex(&clisession_mutex) != 0) { + WOLFSSL_MSG("Client cache mutex lock failed"); + XFCLOSE(file); + return BAD_MUTEX_E; + } + ret = (int)XFREAD(ClientCache, sizeof(ClientCache), 1, file); + if (ret != 1) { + WOLFSSL_MSG("Client cache member file read failed"); + XMEMSET(ClientCache, 0, sizeof ClientCache); + rc = FREAD_ERROR; + } + wc_UnLockMutex(&clisession_mutex); +#endif /* !NO_CLIENT_CACHE */ + + XFCLOSE(file); + WOLFSSL_LEAVE("wolfSSL_restore_session_cache", rc); + + return rc; +} + +#endif /* !NO_FILESYSTEM */ +#endif /* PERSIST_SESSION_CACHE && !SESSION_CACHE_DYNAMIC_MEM */ + + +/* on by default if built in but allow user to turn off */ +WOLFSSL_ABI +long wolfSSL_CTX_set_session_cache_mode(WOLFSSL_CTX* ctx, long mode) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_session_cache_mode"); + + if (ctx == NULL) + return WOLFSSL_FAILURE; + + if (mode == WOLFSSL_SESS_CACHE_OFF) { + ctx->sessionCacheOff = 1; +#ifdef HAVE_EXT_CACHE + ctx->internalCacheOff = 1; + ctx->internalCacheLookupOff = 1; +#endif + } + + if ((mode & WOLFSSL_SESS_CACHE_NO_AUTO_CLEAR) != 0) + ctx->sessionCacheFlushOff = 1; + +#ifdef HAVE_EXT_CACHE + /* WOLFSSL_SESS_CACHE_NO_INTERNAL activates both if's */ + if ((mode & WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE) != 0) + ctx->internalCacheOff = 1; + if ((mode & WOLFSSL_SESS_CACHE_NO_INTERNAL_LOOKUP) != 0) + ctx->internalCacheLookupOff = 1; +#endif + + return WOLFSSL_SUCCESS; +} + +#ifdef OPENSSL_EXTRA +/* Get the session cache mode for CTX + * + * ctx WOLFSSL_CTX struct to get cache mode from + * + * Returns a bit mask that has the session cache mode */ +long wolfSSL_CTX_get_session_cache_mode(WOLFSSL_CTX* ctx) +{ + long m = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_get_session_cache_mode"); + + if (ctx == NULL) { + return m; + } + + if (ctx->sessionCacheOff != 1) { + m |= WOLFSSL_SESS_CACHE_SERVER; + } + + if (ctx->sessionCacheFlushOff == 1) { + m |= WOLFSSL_SESS_CACHE_NO_AUTO_CLEAR; + } + +#ifdef HAVE_EXT_CACHE + if (ctx->internalCacheOff == 1) { + m |= WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE; + } + if (ctx->internalCacheLookupOff == 1) { + m |= WOLFSSL_SESS_CACHE_NO_INTERNAL_LOOKUP; + } +#endif + + return m; +} +#endif /* OPENSSL_EXTRA */ + +#endif /* !NO_SESSION_CACHE */ + +#ifndef NO_SESSION_CACHE + +WOLFSSL_ABI +void wolfSSL_flush_sessions(WOLFSSL_CTX* ctx, long tm) +{ + /* static table now, no flushing needed */ + (void)ctx; + (void)tm; +} + +void wolfSSL_CTX_flush_sessions(WOLFSSL_CTX* ctx, long tm) +{ + int i, j; + byte id[ID_LEN]; + + (void)ctx; + XMEMSET(id, 0, ID_LEN); + WOLFSSL_ENTER("wolfSSL_flush_sessions"); + for (i = 0; i < SESSION_ROWS; ++i) { + if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) { + WOLFSSL_MSG("Session cache mutex lock failed"); + return; + } + for (j = 0; j < SESSIONS_PER_ROW; j++) { +#ifdef SESSION_CACHE_DYNAMIC_MEM + WOLFSSL_SESSION* s = SessionCache[i].Sessions[j]; +#else + WOLFSSL_SESSION* s = &SessionCache[i].Sessions[j]; +#endif + if ( +#ifdef SESSION_CACHE_DYNAMIC_MEM + s != NULL && +#endif + XMEMCMP(s->sessionID, id, ID_LEN) != 0 && + s->bornOn + s->timeout < (word32)tm + ) + { + EvictSessionFromCache(s); +#ifdef SESSION_CACHE_DYNAMIC_MEM + XFREE(s, s->heap, DYNAMIC_TYPE_SESSION); + SessionCache[i].Sessions[j] = NULL; +#endif + } + } + SESSION_ROW_UNLOCK(&SessionCache[i]); + } +} + + +/* set ssl session timeout in seconds */ +WOLFSSL_ABI +int wolfSSL_set_timeout(WOLFSSL* ssl, unsigned int to) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (to == 0) + to = WOLFSSL_SESSION_TIMEOUT; + ssl->timeout = to; + + return WOLFSSL_SUCCESS; +} + + +/** + * Sets ctx session timeout in seconds. + * The timeout value set here should be reflected in the + * "session ticket lifetime hint" if this API works in the openssl compat-layer. + * Therefore wolfSSL_CTX_set_TicketHint is called internally. + * Arguments: + * - ctx WOLFSSL_CTX object which the timeout is set to + * - to timeout value in second + * Returns: + * WOLFSSL_SUCCESS on success, BAD_FUNC_ARG on failure. + * When WOLFSSL_ERROR_CODE_OPENSSL is defined, returns previous timeout value + * on success, BAD_FUNC_ARG on failure. + */ +WOLFSSL_ABI +int wolfSSL_CTX_set_timeout(WOLFSSL_CTX* ctx, unsigned int to) +{ + #if defined(WOLFSSL_ERROR_CODE_OPENSSL) + word32 prev_timeout = 0; + #endif + + int ret = WOLFSSL_SUCCESS; + (void)ret; + + if (ctx == NULL) + ret = BAD_FUNC_ARG; + + if (ret == WOLFSSL_SUCCESS) { + #if defined(WOLFSSL_ERROR_CODE_OPENSSL) + prev_timeout = ctx->timeout; + #endif + if (to == 0) { + ctx->timeout = WOLFSSL_SESSION_TIMEOUT; + } + else { + ctx->timeout = to; + } + } +#if defined(OPENSSL_EXTRA) && defined(HAVE_SESSION_TICKET) && \ + !defined(NO_WOLFSSL_SERVER) + if (ret == WOLFSSL_SUCCESS) { + if (to == 0) { + ret = wolfSSL_CTX_set_TicketHint(ctx, SESSION_TICKET_HINT_DEFAULT); + } + else { + ret = wolfSSL_CTX_set_TicketHint(ctx, to); + } + } +#endif /* OPENSSL_EXTRA && HAVE_SESSION_TICKET && !NO_WOLFSSL_SERVER */ + +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + if (ret == WOLFSSL_SUCCESS) { + return prev_timeout; + } + else { + return ret; + } +#else + return ret; +#endif /* WOLFSSL_ERROR_CODE_OPENSSL */ +} + + +#ifndef NO_CLIENT_CACHE + +/* Get Session from Client cache based on id/len, return NULL on failure */ +WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len) +{ + WOLFSSL_SESSION* ret = NULL; + word32 row; + int idx; + int count; + int error = 0; + ClientSession* clSess; + + WOLFSSL_ENTER("wolfSSL_GetSessionClient"); + + if (ssl->ctx->sessionCacheOff) { + WOLFSSL_MSG("Session Cache off"); + return NULL; + } + + if (ssl->options.side == WOLFSSL_SERVER_END) + return NULL; + + len = min(SERVER_ID_LEN, (word32)len); + + /* Do not access ssl->ctx->get_sess_cb from here. It is using a different + * set of ID's */ + + row = HashObject(id, len, &error) % CLIENT_SESSION_ROWS; + if (error != 0) { + WOLFSSL_MSG("Hash session failed"); + return NULL; + } + + if (wc_LockMutex(&clisession_mutex) != 0) { + WOLFSSL_MSG("Client cache mutex lock failed"); + return NULL; + } + + /* start from most recently used */ + count = min((word32)ClientCache[row].totalCount, CLIENT_SESSIONS_PER_ROW); + idx = ClientCache[row].nextIdx - 1; + if (idx < 0 || idx >= CLIENT_SESSIONS_PER_ROW) { + /* if back to front, the previous was end */ + idx = CLIENT_SESSIONS_PER_ROW - 1; + } + clSess = ClientCache[row].Clients; + + for (; count > 0; --count) { + WOLFSSL_SESSION* current; + SessionRow* sessRow; + + if (clSess[idx].serverRow >= SESSION_ROWS) { + WOLFSSL_MSG("Client cache serverRow invalid"); + break; + } + + /* lock row */ + sessRow = &SessionCache[clSess[idx].serverRow]; + if (SESSION_ROW_RD_LOCK(sessRow) != 0) { + WOLFSSL_MSG("Session cache row lock failure"); + break; + } + +#ifdef SESSION_CACHE_DYNAMIC_MEM + current = sessRow->Sessions[clSess[idx].serverIdx]; +#else + current = &sessRow->Sessions[clSess[idx].serverIdx]; +#endif + if (current && XMEMCMP(current->serverID, id, len) == 0) { + WOLFSSL_MSG("Found a serverid match for client"); + if (LowResTimer() < (current->bornOn + current->timeout)) { + WOLFSSL_MSG("Session valid"); + ret = current; + SESSION_ROW_UNLOCK(sessRow); + break; + } else { + WOLFSSL_MSG("Session timed out"); /* could have more for id */ + } + } else { + WOLFSSL_MSG("ServerID not a match from client table"); + } + SESSION_ROW_UNLOCK(sessRow); + + idx = idx > 0 ? idx - 1 : CLIENT_SESSIONS_PER_ROW - 1; + } + + wc_UnLockMutex(&clisession_mutex); + + return ret; +} + +#endif /* !NO_CLIENT_CACHE */ + +static int SslSessionCacheOff(const WOLFSSL* ssl, + const WOLFSSL_SESSION* session) +{ + (void)session; + return ssl->options.sessionCacheOff + #if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_FORCE_CACHE_ON_TICKET) + && session->ticketLen == 0 + #endif + ; +} + +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) +/** + * SessionTicketNoncePrealloc() - prealloc a buffer for ticket nonces + * @output: [in] pointer to WOLFSSL_SESSION object that will soon be a + * destination of a session duplication + * @buf: [out] address of the preallocated buf + * @len: [out] len of the preallocated buf + * + * prealloc a buffer that will likely suffice to contain a ticket nonce. It's + * used when copying session under lock, when syscalls need to be avoided. If + * output already has a dynamic buffer, it's reused. + */ +static int SessionTicketNoncePrealloc(byte** buf, byte* len, void *heap) +{ + (void)heap; + + *buf = (byte*)XMALLOC(PREALLOC_SESSION_TICKET_NONCE_LEN, heap, + DYNAMIC_TYPE_SESSION_TICK); + if (*buf == NULL) { + WOLFSSL_MSG("Failed to preallocate ticket nonce buffer"); + *len = 0; + return 1; + } + + *len = PREALLOC_SESSION_TICKET_NONCE_LEN; + return 0; +} +#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */ + +static int wolfSSL_DupSessionEx(const WOLFSSL_SESSION* input, + WOLFSSL_SESSION* output, int avoidSysCalls, byte* ticketNonceBuf, + byte* ticketNonceLen, byte* preallocUsed); + +void TlsSessionCacheUnlockRow(word32 row) +{ + SessionRow* sessRow; + + sessRow = &SessionCache[row]; + (void)sessRow; + SESSION_ROW_UNLOCK(sessRow); +} + +/* Don't use this function directly. Use TlsSessionCacheGetAndRdLock and + * TlsSessionCacheGetAndWrLock to fully utilize compiler const support. */ +static int TlsSessionCacheGetAndLock(const byte *id, + const WOLFSSL_SESSION **sess, word32 *lockedRow, byte readOnly, byte side) +{ + SessionRow *sessRow; + const WOLFSSL_SESSION *s; + word32 row; + int count; + int error; + int idx; + + *sess = NULL; + row = HashObject(id, ID_LEN, &error) % SESSION_ROWS; + if (error != 0) + return error; + sessRow = &SessionCache[row]; + if (readOnly) + error = SESSION_ROW_RD_LOCK(sessRow); + else + error = SESSION_ROW_WR_LOCK(sessRow); + if (error != 0) + return FATAL_ERROR; + + /* start from most recently used */ + count = min((word32)sessRow->totalCount, SESSIONS_PER_ROW); + idx = sessRow->nextIdx - 1; + if (idx < 0 || idx >= SESSIONS_PER_ROW) { + idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */ + } + for (; count > 0; --count) { +#ifdef SESSION_CACHE_DYNAMIC_MEM + s = sessRow->Sessions[idx]; +#else + s = &sessRow->Sessions[idx]; +#endif + if (s && XMEMCMP(s->sessionID, id, ID_LEN) == 0 && s->side == side) { + *sess = s; + break; + } + idx = idx > 0 ? idx - 1 : SESSIONS_PER_ROW - 1; + } + if (*sess == NULL) { + SESSION_ROW_UNLOCK(sessRow); + } + else { + *lockedRow = row; + } + + return 0; +} + +static int CheckSessionMatch(const WOLFSSL* ssl, const WOLFSSL_SESSION* sess) +{ + if (ssl == NULL || sess == NULL) + return 0; +#ifdef OPENSSL_EXTRA + if (ssl->sessionCtxSz > 0 && (ssl->sessionCtxSz != sess->sessionCtxSz || + XMEMCMP(ssl->sessionCtx, sess->sessionCtx, sess->sessionCtxSz) != 0)) + return 0; +#endif +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) + if (IsAtLeastTLSv1_3(ssl->version) != IsAtLeastTLSv1_3(sess->version)) + return 0; +#endif + return 1; +} + +int TlsSessionCacheGetAndRdLock(const byte *id, const WOLFSSL_SESSION **sess, + word32 *lockedRow, byte side) +{ + return TlsSessionCacheGetAndLock(id, sess, lockedRow, 1, side); +} + +int TlsSessionCacheGetAndWrLock(const byte *id, WOLFSSL_SESSION **sess, + word32 *lockedRow, byte side) +{ + return TlsSessionCacheGetAndLock(id, (const WOLFSSL_SESSION**)sess, + lockedRow, 0, side); +} + +int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) +{ + const WOLFSSL_SESSION* sess = NULL; + const byte* id = NULL; + word32 row; + int error = 0; +#ifdef HAVE_SESSION_TICKET +#ifndef WOLFSSL_SMALL_STACK + byte tmpTicket[PREALLOC_SESSION_TICKET_LEN]; +#else + byte* tmpTicket = NULL; +#endif +#ifdef WOLFSSL_TLS13 + byte *preallocNonce = NULL; + byte preallocNonceLen = 0; + byte preallocNonceUsed = 0; +#endif /* WOLFSSL_TLS13 */ + byte tmpBufSet = 0; +#endif +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + WOLFSSL_X509* peer = NULL; +#endif + byte bogusID[ID_LEN]; + byte bogusIDSz = 0; + + WOLFSSL_ENTER("wolfSSL_GetSessionFromCache"); + + if (output == NULL) { + WOLFSSL_MSG("NULL output"); + return WOLFSSL_FAILURE; + } + + if (SslSessionCacheOff(ssl, ssl->session)) + return WOLFSSL_FAILURE; + + if (ssl->options.haveSessionId == 0 && !ssl->session->haveAltSessionID) + return WOLFSSL_FAILURE; + +#ifdef HAVE_SESSION_TICKET + if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1) + return WOLFSSL_FAILURE; +#endif + + XMEMSET(bogusID, 0, sizeof(bogusID)); + if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL + && !ssl->session->haveAltSessionID) + id = ssl->arrays->sessionID; + else if (ssl->session->haveAltSessionID) { + id = ssl->session->altSessionID; + /* We want to restore the bogus ID for TLS compatibility */ + if (output == ssl->session) { + XMEMCPY(bogusID, ssl->session->sessionID, ID_LEN); + bogusIDSz = ssl->session->sessionIDSz; + } + } + else + id = ssl->session->sessionID; + + +#ifdef HAVE_EXT_CACHE + if (ssl->ctx->get_sess_cb != NULL) { + int copy = 0; + int found = 0; + WOLFSSL_SESSION* extSess; + /* Attempt to retrieve the session from the external cache. */ + WOLFSSL_MSG("Calling external session cache"); + extSess = ssl->ctx->get_sess_cb(ssl, (byte*)id, ID_LEN, ©); + if ((extSess != NULL) + && CheckSessionMatch(ssl, extSess) + ) { + WOLFSSL_MSG("Session found in external cache"); + found = 1; + + error = wolfSSL_DupSession(extSess, output, 0); +#ifdef HAVE_EX_DATA + extSess->ownExData = 1; + output->ownExData = 0; +#endif + /* We want to restore the bogus ID for TLS compatibility */ + if (ssl->session->haveAltSessionID && + output == ssl->session) { + XMEMCPY(ssl->session->sessionID, bogusID, ID_LEN); + ssl->session->sessionIDSz = bogusIDSz; + } + } + /* If copy not set then free immediately */ + if (extSess != NULL && !copy) + wolfSSL_FreeSession(ssl->ctx, extSess); + if (found) + return error; + WOLFSSL_MSG("Session not found in external cache"); + } + + if (ssl->options.internalCacheLookupOff) { + WOLFSSL_MSG("Internal cache lookup turned off"); + return WOLFSSL_FAILURE; + } +#endif + +#ifdef HAVE_SESSION_TICKET + if (output->ticket == NULL || + output->ticketLenAlloc < PREALLOC_SESSION_TICKET_LEN) { +#ifdef WOLFSSL_SMALL_STACK + tmpTicket = (byte*)XMALLOC(PREALLOC_SESSION_TICKET_LEN, output->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (tmpTicket == NULL) { + WOLFSSL_MSG("tmpTicket malloc failed"); + return WOLFSSL_FAILURE; + } +#endif + if (output->ticketLenAlloc) + XFREE(output->ticket, output->heap, DYNAMIC_TYPE_SESSION_TICK); + output->ticket = tmpTicket; /* cppcheck-suppress autoVariables + */ + output->ticketLenAlloc = PREALLOC_SESSION_TICKET_LEN; + output->ticketLen = 0; + tmpBufSet = 1; + } +#endif + +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + if (output->peer != NULL) { + wolfSSL_X509_free(output->peer); + output->peer = NULL; + } +#endif + +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (output->ticketNonce.data != output->ticketNonce.dataStatic) { + XFREE(output->ticketNonce.data, output->heap, + DYNAMIC_TYPE_SESSION_TICK); + output->ticketNonce.data = output->ticketNonce.dataStatic; + output->ticketNonce.len = 0; + } + error = SessionTicketNoncePrealloc(&preallocNonce, &preallocNonceLen, + output->heap); + if (error != 0) { + if (tmpBufSet) { + output->ticket = output->staticTicket; + output->ticketLenAlloc = 0; + } +#ifdef WOLFSSL_SMALL_STACK + if (tmpTicket != NULL) + XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return WOLFSSL_FAILURE; + } +#endif /* WOLFSSL_TLS13 && HAVE_SESSION_TICKET*/ + + /* init to avoid clang static analyzer false positive */ + row = 0; + error = TlsSessionCacheGetAndRdLock(id, &sess, &row, + (byte)ssl->options.side); + error = (error == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + if (error != WOLFSSL_SUCCESS || sess == NULL) { + WOLFSSL_MSG("Get Session from cache failed"); + error = WOLFSSL_FAILURE; +#ifdef HAVE_SESSION_TICKET + if (tmpBufSet) { + output->ticket = output->staticTicket; + output->ticketLenAlloc = 0; + } +#ifdef WOLFSSL_TLS13 + if (preallocNonce != NULL) { + XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK); + preallocNonce = NULL; + } +#endif /* WOLFSSL_TLS13 */ +#ifdef WOLFSSL_SMALL_STACK + if (tmpTicket != NULL) { + XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); + tmpTicket = NULL; + } +#endif +#endif + } + else { + if (!CheckSessionMatch(ssl, sess)) { + WOLFSSL_MSG("Invalid session: can't be used in this context"); + TlsSessionCacheUnlockRow(row); + error = WOLFSSL_FAILURE; + } + else if (LowResTimer() >= (sess->bornOn + sess->timeout)) { + WOLFSSL_SESSION* wrSess = NULL; + WOLFSSL_MSG("Invalid session: timed out"); + sess = NULL; + TlsSessionCacheUnlockRow(row); + /* Attempt to get a write lock */ + error = TlsSessionCacheGetAndWrLock(id, &wrSess, &row, + (byte)ssl->options.side); + if (error == 0 && wrSess != NULL) { + EvictSessionFromCache(wrSess); + TlsSessionCacheUnlockRow(row); + } + error = WOLFSSL_FAILURE; + } + } + + /* mollify confused cppcheck nullPointer warning. */ + if (sess == NULL) + error = WOLFSSL_FAILURE; + + if (error == WOLFSSL_SUCCESS) { +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) + error = wolfSSL_DupSessionEx(sess, output, 1, + preallocNonce, &preallocNonceLen, &preallocNonceUsed); +#else + error = wolfSSL_DupSession(sess, output, 1); +#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */ +#ifdef HAVE_EX_DATA + output->ownExData = !sess->ownExData; /* Session may own ex_data */ +#endif + TlsSessionCacheUnlockRow(row); + } + + /* We want to restore the bogus ID for TLS compatibility */ + if (ssl->session->haveAltSessionID && + output == ssl->session) { + XMEMCPY(ssl->session->sessionID, bogusID, ID_LEN); + ssl->session->sessionIDSz = bogusIDSz; + } + +#ifdef HAVE_SESSION_TICKET + if (tmpBufSet) { + if (error == WOLFSSL_SUCCESS) { + if (output->ticketLen > SESSION_TICKET_LEN) { + output->ticket = (byte*)XMALLOC(output->ticketLen, output->heap, + DYNAMIC_TYPE_SESSION_TICK); + if (output->ticket == NULL) { + error = WOLFSSL_FAILURE; + output->ticket = output->staticTicket; + output->ticketLenAlloc = 0; + output->ticketLen = 0; + } + } + else { + output->ticket = output->staticTicket; + output->ticketLenAlloc = 0; + } + } + else { + output->ticket = output->staticTicket; + output->ticketLenAlloc = 0; + output->ticketLen = 0; + } + if (error == WOLFSSL_SUCCESS) { + XMEMCPY(output->ticket, tmpTicket, output->ticketLen); + } + } +#ifdef WOLFSSL_SMALL_STACK + if (tmpTicket != NULL) + XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (error == WOLFSSL_SUCCESS && preallocNonceUsed) { + if (preallocNonceLen < PREALLOC_SESSION_TICKET_NONCE_LEN) { + /* buffer bigger than needed */ +#ifndef XREALLOC + output->ticketNonce.data = (byte*)XMALLOC(preallocNonceLen, + output->heap, DYNAMIC_TYPE_SESSION_TICK); + if (output->ticketNonce.data != NULL) + XMEMCPY(output->ticketNonce.data, preallocNonce, + preallocNonceLen); + XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK); + preallocNonce = NULL; +#else + output->ticketNonce.data = (byte*)XREALLOC(preallocNonce, + preallocNonceLen, output->heap, DYNAMIC_TYPE_SESSION_TICK); + if (output->ticketNonce.data != NULL) { + /* don't free the reallocated pointer */ + preallocNonce = NULL; + } +#endif /* !XREALLOC */ + if (output->ticketNonce.data == NULL) { + output->ticketNonce.data = output->ticketNonce.dataStatic; + output->ticketNonce.len = 0; + error = WOLFSSL_FAILURE; + /* preallocNonce will be free'd after the if */ + } + } + else { + output->ticketNonce.data = preallocNonce; + output->ticketNonce.len = preallocNonceLen; + preallocNonce = NULL; + } + } + if (preallocNonce != NULL) + XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK); +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ + +#endif + +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + if (peer != NULL) { + wolfSSL_X509_free(peer); + } +#endif + + return error; +} + +WOLFSSL_SESSION* wolfSSL_GetSession(WOLFSSL* ssl, byte* masterSecret, + byte restoreSessionCerts) +{ + WOLFSSL_SESSION* ret = NULL; + + (void)restoreSessionCerts; /* Kept for compatibility */ + + if (wolfSSL_GetSessionFromCache(ssl, ssl->session) == WOLFSSL_SUCCESS) { + ret = ssl->session; + } + else { + WOLFSSL_MSG("wolfSSL_GetSessionFromCache did not return a session"); + } + + if (ret != NULL && masterSecret != NULL) + XMEMCPY(masterSecret, ret->masterSecret, SECRET_LEN); + + return ret; +} + +int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) +{ + SessionRow* sessRow = NULL; + int ret = WOLFSSL_SUCCESS; + + session = ClientSessionToSession(session); + + if (ssl == NULL || session == NULL || !session->isSetup) { + WOLFSSL_MSG("ssl or session NULL or not set up"); + return WOLFSSL_FAILURE; + } + + /* We need to lock the session as the first step if its in the cache */ + if (session->type == WOLFSSL_SESSION_TYPE_CACHE) { + if (session->cacheRow < SESSION_ROWS) { + sessRow = &SessionCache[session->cacheRow]; + if (SESSION_ROW_RD_LOCK(sessRow) != 0) { + WOLFSSL_MSG("Session row lock failed"); + return WOLFSSL_FAILURE; + } + } + } + + if (ret == WOLFSSL_SUCCESS && ssl->options.side != WOLFSSL_NEITHER_END && + (byte)ssl->options.side != session->side) { + WOLFSSL_MSG("Setting session for wrong role"); + ret = WOLFSSL_FAILURE; + } + + if (ret == WOLFSSL_SUCCESS) { + if (ssl->session == session) { + WOLFSSL_MSG("ssl->session and session same"); + } + else if (session->type != WOLFSSL_SESSION_TYPE_CACHE) { + if (wolfSSL_SESSION_up_ref(session) == WOLFSSL_SUCCESS) { + wolfSSL_FreeSession(ssl->ctx, ssl->session); + ssl->session = session; + } + else + ret = WOLFSSL_FAILURE; + } + else { + ret = wolfSSL_DupSession(session, ssl->session, 0); + if (ret != WOLFSSL_SUCCESS) + WOLFSSL_MSG("Session duplicate failed"); + } + } + + /* Let's copy over the altSessionID for local cache purposes */ + if (ret == WOLFSSL_SUCCESS && session->haveAltSessionID && + ssl->session != session) { + ssl->session->haveAltSessionID = 1; + XMEMCPY(ssl->session->altSessionID, session->altSessionID, ID_LEN); + } + + if (sessRow != NULL) { + SESSION_ROW_UNLOCK(sessRow); + sessRow = NULL; + } + + /* Note: the `session` variable cannot be used below, since the row is + * un-locked */ + + if (ret != WOLFSSL_SUCCESS) + return ret; + +#ifdef WOLFSSL_SESSION_ID_CTX + /* check for application context id */ + if (ssl->sessionCtxSz > 0) { + if (XMEMCMP(ssl->sessionCtx, ssl->session->sessionCtx, + ssl->sessionCtxSz)) { + /* context id did not match! */ + WOLFSSL_MSG("Session context did not match"); + return WOLFSSL_FAILURE; + } + } +#endif /* WOLFSSL_SESSION_ID_CTX */ + + if (LowResTimer() >= (ssl->session->bornOn + ssl->session->timeout)) { +#if !defined(OPENSSL_EXTRA) || !defined(WOLFSSL_ERROR_CODE_OPENSSL) + return WOLFSSL_FAILURE; /* session timed out */ +#else /* defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) */ + WOLFSSL_MSG("Session is expired but return success for " + "OpenSSL compatibility"); +#endif + } + ssl->options.resuming = 1; + ssl->options.haveEMS = ssl->session->haveEMS; + +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + ssl->version = ssl->session->version; + if (IsAtLeastTLSv1_3(ssl->version)) + ssl->options.tls1_3 = 1; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + ssl->options.cipherSuite0 = ssl->session->cipherSuite0; + ssl->options.cipherSuite = ssl->session->cipherSuite; +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ssl->peerVerifyRet = (unsigned long)ssl->session->peerVerifyRet; +#endif + + return WOLFSSL_SUCCESS; +} + + +#ifdef WOLFSSL_SESSION_STATS +static int get_locked_session_stats(word32* active, word32* total, + word32* peak); +#endif + +#ifndef NO_CLIENT_CACHE +ClientSession* AddSessionToClientCache(int side, int row, int idx, + byte* serverID, word16 idLen, const byte* sessionID, word16 useTicket) +{ + int error = -1; + word32 clientRow = 0, clientIdx = 0; + ClientSession* ret = NULL; + + (void)useTicket; + if (side == WOLFSSL_CLIENT_END + && row != INVALID_SESSION_ROW + && (idLen +#ifdef HAVE_SESSION_TICKET + || useTicket == 1 +#endif + || serverID != NULL + )) { + + WOLFSSL_MSG("Trying to add client cache entry"); + + if (idLen) { + clientRow = HashObject(serverID, + idLen, &error) % CLIENT_SESSION_ROWS; + } + else if (serverID != NULL) { + clientRow = HashObject(sessionID, + ID_LEN, &error) % CLIENT_SESSION_ROWS; + } + else { + error = -1; + } + if (error == 0 && wc_LockMutex(&clisession_mutex) == 0) { + clientIdx = ClientCache[clientRow].nextIdx; + if (clientIdx < CLIENT_SESSIONS_PER_ROW) { + ClientCache[clientRow].Clients[clientIdx].serverRow = + (word16)row; + ClientCache[clientRow].Clients[clientIdx].serverIdx = + (word16)idx; + if (sessionID != NULL) { + word32 sessionIDHash = HashObject(sessionID, ID_LEN, + &error); + if (error == 0) { + ClientCache[clientRow].Clients[clientIdx].sessionIDHash + = sessionIDHash; + } + } + } + else { + error = -1; + ClientCache[clientRow].nextIdx = 0; /* reset index as safety */ + WOLFSSL_MSG("Invalid client cache index! " + "Possible corrupted memory"); + } + if (error == 0) { + WOLFSSL_MSG("Adding client cache entry"); + + ret = &ClientCache[clientRow].Clients[clientIdx]; + + if (ClientCache[clientRow].totalCount < CLIENT_SESSIONS_PER_ROW) + ClientCache[clientRow].totalCount++; + ClientCache[clientRow].nextIdx++; + ClientCache[clientRow].nextIdx %= CLIENT_SESSIONS_PER_ROW; + } + + wc_UnLockMutex(&clisession_mutex); + } + else { + WOLFSSL_MSG("Hash session or lock failed"); + } + } + else { + WOLFSSL_MSG("Skipping client cache"); + } + + return ret; +} +#endif /* !NO_CLIENT_CACHE */ + +/** + * For backwards compatibility, this API needs to be used in *ALL* functions + * that access the WOLFSSL_SESSION members directly. + * + * This API checks if the passed in session is actually a ClientSession object + * and returns the matching session cache object. Otherwise just return the + * input. ClientSession objects only occur in the ClientCache. They are not + * allocated anywhere else. + */ +WOLFSSL_SESSION* ClientSessionToSession(const WOLFSSL_SESSION* session) +{ + WOLFSSL_ENTER("ClientSessionToSession"); +#ifdef NO_SESSION_CACHE_REF + return (WOLFSSL_SESSION*)session; +#else +#ifndef NO_CLIENT_CACHE + if (session == NULL) + return NULL; + /* Check if session points into ClientCache */ + if ((byte*)session >= (byte*)ClientCache && + /* Cast to byte* to make pointer arithmetic work per byte */ + (byte*)session < ((byte*)ClientCache) + sizeof(ClientCache)) { + ClientSession* clientSession = (ClientSession*)session; + SessionRow* sessRow = NULL; + WOLFSSL_SESSION* cacheSession = NULL; + word32 sessionIDHash = 0; + int error = 0; + session = NULL; /* Default to NULL for failure case */ + if (wc_LockMutex(&clisession_mutex) != 0) { + WOLFSSL_MSG("Client cache mutex lock failed"); + return NULL; + } + if (clientSession->serverRow >= SESSION_ROWS || + clientSession->serverIdx >= SESSIONS_PER_ROW) { + WOLFSSL_MSG("Client cache serverRow or serverIdx invalid"); + error = -1; + } + /* Prevent memory access before clientSession->serverRow and + * clientSession->serverIdx are sanitized. */ + XFENCE(); + if (error == 0) { + /* Lock row */ + sessRow = &SessionCache[clientSession->serverRow]; + error = SESSION_ROW_RD_LOCK(sessRow); + if (error != 0) { + WOLFSSL_MSG("Session cache row lock failure"); + sessRow = NULL; + } + } + if (error == 0) { +#ifdef SESSION_CACHE_DYNAMIC_MEM + cacheSession = sessRow->Sessions[clientSession->serverIdx]; +#else + cacheSession = &sessRow->Sessions[clientSession->serverIdx]; +#endif + if (cacheSession && cacheSession->sessionIDSz == 0) { + cacheSession = NULL; + WOLFSSL_MSG("Session cache entry not set"); + error = -1; + } + } + if (error == 0) { + /* Calculate the hash of the session ID */ + sessionIDHash = HashObject(cacheSession->sessionID, ID_LEN, + &error); + } + if (error == 0) { + /* Check the session ID hash matches */ + error = clientSession->sessionIDHash != sessionIDHash; + if (error != 0) + WOLFSSL_MSG("session ID hash don't match"); + } + if (error == 0) { + /* Hashes match */ + session = cacheSession; + WOLFSSL_MSG("Found session cache matching client session object"); + } + if (sessRow != NULL) { + SESSION_ROW_UNLOCK(sessRow); + } + wc_UnLockMutex(&clisession_mutex); + return (WOLFSSL_SESSION*)session; + } + else { + /* Plain WOLFSSL_SESSION object */ + return (WOLFSSL_SESSION*)session; + } +#else + return (WOLFSSL_SESSION*)session; +#endif +#endif +} + +int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, + const byte* id, byte idSz, int* sessionIndex, int side, + word16 useTicket, ClientSession** clientCacheEntry) +{ + WOLFSSL_SESSION* cacheSession = NULL; + SessionRow* sessRow = NULL; + word32 idx = 0; +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + WOLFSSL_X509* cachePeer = NULL; + WOLFSSL_X509* addPeer = NULL; +#endif +#ifdef HAVE_SESSION_TICKET + byte* cacheTicBuff = NULL; + byte ticBuffUsed = 0; + byte* ticBuff = NULL; + int ticLen = 0; +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + byte *preallocNonce = NULL; + byte preallocNonceLen = 0; + byte preallocNonceUsed = 0; + byte *toFree = NULL; +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC */ +#endif /* HAVE_SESSION_TICKET */ + int ret = 0; + int row; + int i; + int overwrite = 0; + (void)ctx; + (void)sessionIndex; + (void)useTicket; + (void)clientCacheEntry; + + WOLFSSL_ENTER("AddSessionToCache"); + + if (idSz == 0) { + WOLFSSL_MSG("AddSessionToCache idSz == 0"); + return BAD_FUNC_ARG; + } + + addSession = ClientSessionToSession(addSession); + if (addSession == NULL) { + WOLFSSL_MSG("AddSessionToCache is NULL"); + return MEMORY_E; + } + +#ifdef HAVE_SESSION_TICKET + ticLen = addSession->ticketLen; + /* Alloc Memory here to avoid syscalls during lock */ + if (ticLen > SESSION_TICKET_LEN) { + ticBuff = (byte*)XMALLOC(ticLen, NULL, + DYNAMIC_TYPE_SESSION_TICK); + if (ticBuff == NULL) { + return MEMORY_E; + } + } +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (addSession->ticketNonce.data != addSession->ticketNonce.dataStatic) { + /* use the AddSession->heap even if the buffer maybe saved in + * CachedSession objects. CachedSession heap and AddSession heap should + * be the same */ + preallocNonce = (byte*)XMALLOC(addSession->ticketNonce.len, + addSession->heap, DYNAMIC_TYPE_SESSION_TICK); + if (preallocNonce == NULL) { + if (ticBuff != NULL) + XFREE(ticBuff, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); + return MEMORY_E; + } + preallocNonceLen = addSession->ticketNonce.len; + } +#endif /* WOLFSSL_TLS13 && WOLFSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3) */ +#endif /* HAVE_SESSION_TICKET */ + + /* Find a position for the new session in cache and use that */ + /* Use the session object in the cache for external cache if required */ + row = (int)(HashObject(id, ID_LEN, &ret) % SESSION_ROWS); + if (ret != 0) { + WOLFSSL_MSG("Hash session failed"); + #ifdef HAVE_SESSION_TICKET + XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) + XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); + #endif + #endif + return ret; + } + + sessRow = &SessionCache[row]; + if (SESSION_ROW_WR_LOCK(sessRow) != 0) { + #ifdef HAVE_SESSION_TICKET + XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) + XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); + #endif + #endif + WOLFSSL_MSG("Session row lock failed"); + return BAD_MUTEX_E; + } + + for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) { +#ifdef SESSION_CACHE_DYNAMIC_MEM + cacheSession = sessRow->Sessions[i]; +#else + cacheSession = &sessRow->Sessions[i]; +#endif + if (cacheSession && XMEMCMP(id, + cacheSession->sessionID, ID_LEN) == 0 && + cacheSession->side == side) { + WOLFSSL_MSG("Session already exists. Overwriting."); + overwrite = 1; + idx = i; + break; + } + } + + if (!overwrite) + idx = sessRow->nextIdx; +#ifdef SESSION_INDEX + if (sessionIndex != NULL) + *sessionIndex = (row << SESSIDX_ROW_SHIFT) | idx; +#endif + +#ifdef SESSION_CACHE_DYNAMIC_MEM + cacheSession = sessRow->Sessions[idx]; + if (cacheSession == NULL) { + cacheSession = (WOLFSSL_SESSION*) XMALLOC(sizeof(WOLFSSL_SESSION), + sessRow->heap, DYNAMIC_TYPE_SESSION); + if (cacheSession == NULL) { + #ifdef HAVE_SESSION_TICKET + XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) + XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); + #endif + #endif + SESSION_ROW_UNLOCK(sessRow); + return MEMORY_E; + } + XMEMSET(cacheSession, 0, sizeof(WOLFSSL_SESSION)); + sessRow->Sessions[idx] = cacheSession; + } +#else + cacheSession = &sessRow->Sessions[idx]; +#endif + +#ifdef HAVE_EX_DATA + if (overwrite) { + /* Figure out who owns the ex_data */ + if (cacheSession->ownExData) { + /* Prioritize cacheSession copy */ + XMEMCPY(&addSession->ex_data, &cacheSession->ex_data, + sizeof(WOLFSSL_CRYPTO_EX_DATA)); + } + /* else will be copied in wolfSSL_DupSession call */ + } + else if (cacheSession->ownExData) { + crypto_ex_cb_free_data(cacheSession, crypto_ex_cb_ctx_session, + &cacheSession->ex_data); + cacheSession->ownExData = 0; + } +#endif + + if (!overwrite) + EvictSessionFromCache(cacheSession); + + cacheSession->type = WOLFSSL_SESSION_TYPE_CACHE; + cacheSession->cacheRow = row; + +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + /* Save the peer field to free after unlocking the row */ + if (cacheSession->peer != NULL) + cachePeer = cacheSession->peer; + cacheSession->peer = NULL; +#endif +#ifdef HAVE_SESSION_TICKET + /* If we can reuse the existing buffer in cacheSession then we won't touch + * ticBuff at all making it a very cheap malloc/free. The page on a modern + * OS will most likely not even be allocated to the process. */ + if (ticBuff != NULL && cacheSession->ticketLenAlloc < ticLen) { + /* Save pointer only if separately allocated */ + if (cacheSession->ticket != cacheSession->staticTicket) + cacheTicBuff = cacheSession->ticket; + ticBuffUsed = 1; + cacheSession->ticket = ticBuff; + cacheSession->ticketLenAlloc = (word16) ticLen; + } +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + /* cache entry never used */ + if (cacheSession->ticketNonce.data == NULL) + cacheSession->ticketNonce.data = cacheSession->ticketNonce.dataStatic; + + if (cacheSession->ticketNonce.data != + cacheSession->ticketNonce.dataStatic) { + toFree = cacheSession->ticketNonce.data; + cacheSession->ticketNonce.data = cacheSession->ticketNonce.dataStatic; + cacheSession->ticketNonce.len = 0; + } +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ +#endif +#ifdef SESSION_CERTS + if (overwrite && + addSession->chain.count == 0 && + cacheSession->chain.count > 0) { + /* Copy in the certs from the session */ + addSession->chain.count = cacheSession->chain.count; + XMEMCPY(addSession->chain.certs, cacheSession->chain.certs, + sizeof(x509_buffer) * cacheSession->chain.count); + } +#endif /* SESSION_CERTS */ +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + /* Don't copy the peer cert into cache */ + addPeer = addSession->peer; + addSession->peer = NULL; +#endif + cacheSession->heap = NULL; + /* Copy data into the cache object */ +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + ret = wolfSSL_DupSessionEx(addSession, cacheSession, 1, preallocNonce, + &preallocNonceLen, &preallocNonceUsed) == WOLFSSL_FAILURE; +#else + ret = wolfSSL_DupSession(addSession, cacheSession, 1) == WOLFSSL_FAILURE; +#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC + && FIPS_VERSION_GE(5,3)*/ +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + addSession->peer = addPeer; +#endif + + if (ret == 0) { + if (!overwrite) { + /* Increment the totalCount and the nextIdx */ + if (sessRow->totalCount < SESSIONS_PER_ROW) + sessRow->totalCount++; + sessRow->nextIdx = (sessRow->nextIdx + 1) % SESSIONS_PER_ROW; + } + if (id != addSession->sessionID) { + /* ssl->session->sessionID may contain the bogus ID or we want the + * ID from the arrays object */ + XMEMCPY(cacheSession->sessionID, id, ID_LEN); + cacheSession->sessionIDSz = ID_LEN; + } +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + if (ctx->rem_sess_cb != NULL) + cacheSession->rem_sess_cb = ctx->rem_sess_cb; +#endif +#ifdef HAVE_EX_DATA + /* The session in cache now owns the ex_data */ + addSession->ownExData = 0; + cacheSession->ownExData = 1; +#endif +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (preallocNonce != NULL && preallocNonceUsed) { + cacheSession->ticketNonce.data = preallocNonce; + cacheSession->ticketNonce.len = preallocNonceLen; + preallocNonce = NULL; + preallocNonceLen = 0; + } +#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC + * && FIPS_VERSION_GE(5,3)*/ + } +#ifdef HAVE_SESSION_TICKET + else if (ticBuffUsed) { + /* Error occurred. Need to clean up the ticket buffer. */ + cacheSession->ticket = cacheSession->staticTicket; + cacheSession->ticketLenAlloc = 0; + cacheSession->ticketLen = 0; + } +#endif + SESSION_ROW_UNLOCK(sessRow); + cacheSession = NULL; /* Can't access after unlocked */ + +#ifndef NO_CLIENT_CACHE + if (ret == 0 && clientCacheEntry != NULL) { + ClientSession* clientCache = AddSessionToClientCache(side, row, idx, + addSession->serverID, addSession->idLen, id, useTicket); + if (clientCache != NULL) + *clientCacheEntry = clientCache; + } +#endif + +#ifdef HAVE_SESSION_TICKET + if (ticBuff != NULL && !ticBuffUsed) + XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); + XFREE(cacheTicBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); + XFREE(toFree, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ +#endif + +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + if (cachePeer != NULL) { + wolfSSL_X509_free(cachePeer); + cachePeer = NULL; /* Make sure not use after this point */ + } +#endif + + return ret; +} + +void AddSession(WOLFSSL* ssl) +{ + int error = 0; + const byte* id = NULL; + byte idSz = 0; + WOLFSSL_SESSION* session = ssl->session; + + (void)error; + + WOLFSSL_ENTER("AddSession"); + + if (SslSessionCacheOff(ssl, session)) { + WOLFSSL_MSG("Cache off"); + return; + } + + if (session->haveAltSessionID) { + id = session->altSessionID; + idSz = ID_LEN; + } + else { + id = session->sessionID; + idSz = session->sessionIDSz; + } + + /* Do this only for the client because if the server doesn't have an ID at + * this point, it won't on resumption. */ + if (idSz == 0 && ssl->options.side == WOLFSSL_CLIENT_END) { + WC_RNG* rng = NULL; + if (ssl->rng != NULL) + rng = ssl->rng; +#if defined(HAVE_GLOBAL_RNG) && defined(OPENSSL_EXTRA) + else if (initGlobalRNG == 1 || wolfSSL_RAND_Init() == WOLFSSL_SUCCESS) { + rng = &globalRNG; + } +#endif + if (wc_RNG_GenerateBlock(rng, ssl->session->altSessionID, + ID_LEN) != 0) + return; + ssl->session->haveAltSessionID = 1; + id = ssl->session->altSessionID; + idSz = ID_LEN; + } + +#ifdef HAVE_EXT_CACHE + if (!ssl->options.internalCacheOff) +#endif + { + /* Try to add the session to internal cache or external cache + if a new_sess_cb is set. Its ok if we don't succeed. */ + (void)AddSessionToCache(ssl->ctx, session, id, idSz, +#ifdef SESSION_INDEX + &ssl->sessionIndex, +#else + NULL, +#endif + ssl->options.side, +#ifdef HAVE_SESSION_TICKET + ssl->options.useTicket, +#else + 0, +#endif +#ifdef NO_SESSION_CACHE_REF + NULL +#else + (ssl->options.side == WOLFSSL_CLIENT_END) ? + &ssl->clientSession : NULL +#endif + ); + } + +#ifdef HAVE_EXT_CACHE + if (error == 0 && ssl->ctx->new_sess_cb != NULL) { + int cbRet = 0; + wolfSSL_SESSION_up_ref(session); + cbRet = ssl->ctx->new_sess_cb(ssl, session); + if (cbRet == 0) + wolfSSL_FreeSession(ssl->ctx, session); + } +#endif + +#if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) + if (error == 0) { + word32 active = 0; + + error = get_locked_session_stats(&active, NULL, NULL); + if (error == WOLFSSL_SUCCESS) { + error = 0; /* back to this function ok */ + + if (PeakSessions < active) { + PeakSessions = active; + } + } + } +#endif /* WOLFSSL_SESSION_STATS && WOLFSSL_PEAK_SESSIONS */ + (void)error; +} + + +#ifdef SESSION_INDEX + +int wolfSSL_GetSessionIndex(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_GetSessionIndex"); + WOLFSSL_LEAVE("wolfSSL_GetSessionIndex", ssl->sessionIndex); + return ssl->sessionIndex; +} + + +int wolfSSL_GetSessionAtIndex(int idx, WOLFSSL_SESSION* session) +{ + int row, col, result = WOLFSSL_FAILURE; + SessionRow* sessRow; + WOLFSSL_SESSION* cacheSession; + + WOLFSSL_ENTER("wolfSSL_GetSessionAtIndex"); + + session = ClientSessionToSession(session); + + row = idx >> SESSIDX_ROW_SHIFT; + col = idx & SESSIDX_IDX_MASK; + + if (session == NULL || + row < 0 || row >= SESSION_ROWS || col >= SESSIONS_PER_ROW) { + return WOLFSSL_FAILURE; + } + + sessRow = &SessionCache[row]; + if (SESSION_ROW_RD_LOCK(sessRow) != 0) { + return BAD_MUTEX_E; + } + +#ifdef SESSION_CACHE_DYNAMIC_MEM + cacheSession = sessRow->Sessions[col]; +#else + cacheSession = &sessRow->Sessions[col]; +#endif + if (cacheSession) { + XMEMCPY(session, cacheSession, sizeof(WOLFSSL_SESSION)); + result = WOLFSSL_SUCCESS; + } + else { + result = WOLFSSL_FAILURE; + } + + SESSION_ROW_UNLOCK(sessRow); + + WOLFSSL_LEAVE("wolfSSL_GetSessionAtIndex", result); + return result; +} + +#endif /* SESSION_INDEX */ + +#if defined(SESSION_CERTS) + +WOLFSSL_X509_CHAIN* wolfSSL_SESSION_get_peer_chain(WOLFSSL_SESSION* session) +{ + WOLFSSL_X509_CHAIN* chain = NULL; + + WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain"); + + session = ClientSessionToSession(session); + + if (session) + chain = &session->chain; + + WOLFSSL_LEAVE("wolfSSL_SESSION_get_peer_chain", chain ? 1 : 0); + return chain; +} + + +#ifdef OPENSSL_EXTRA +/* gets the peer certificate associated with the session passed in + * returns null on failure, the caller should not free the returned pointer */ +WOLFSSL_X509* wolfSSL_SESSION_get0_peer(WOLFSSL_SESSION* session) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain"); + + session = ClientSessionToSession(session); + if (session) { + int count; + + count = wolfSSL_get_chain_count(&session->chain); + if (count < 1 || count >= MAX_CHAIN_DEPTH) { + WOLFSSL_MSG("bad count found"); + return NULL; + } + + if (session->peer == NULL) { + session->peer = wolfSSL_get_chain_X509(&session->chain, 0); + } + return session->peer; + } + WOLFSSL_MSG("No session passed in"); + + return NULL; +} +#endif /* OPENSSL_EXTRA */ +#endif /* SESSION_INDEX && SESSION_CERTS */ + + +#ifdef WOLFSSL_SESSION_STATS + +static int get_locked_session_stats(word32* active, word32* total, word32* peak) +{ + int result = WOLFSSL_SUCCESS; + int i; + int count; + int idx; + word32 now = 0; + word32 seen = 0; + word32 ticks = LowResTimer(); + + WOLFSSL_ENTER("get_locked_session_stats"); + +#ifndef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_RD_LOCK(&SessionCache[0]); +#endif + for (i = 0; i < SESSION_ROWS; i++) { + SessionRow* row = &SessionCache[i]; + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + if (SESSION_ROW_RD_LOCK(row) != 0) { + WOLFSSL_MSG("Session row cache mutex lock failed"); + return BAD_MUTEX_E; + } + #endif + + seen += row->totalCount; + + if (active == NULL) { + SESSION_ROW_UNLOCK(row); + continue; + } + + count = min((word32)row->totalCount, SESSIONS_PER_ROW); + idx = row->nextIdx - 1; + if (idx < 0 || idx >= SESSIONS_PER_ROW) { + idx = SESSIONS_PER_ROW - 1; /* if back to front previous was end */ + } + + for (; count > 0; --count) { + /* if not expired then good */ +#ifdef SESSION_CACHE_DYNAMIC_MEM + if (row->Sessions[idx] && + ticks < (row->Sessions[idx]->bornOn + + row->Sessions[idx]->timeout) ) +#else + if (ticks < (row->Sessions[idx].bornOn + + row->Sessions[idx].timeout) ) +#endif + { + now++; + } + + idx = idx > 0 ? idx - 1 : SESSIONS_PER_ROW - 1; + } + + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_UNLOCK(row); + #endif + } +#ifndef ENABLE_SESSION_CACHE_ROW_LOCK + SESSION_ROW_UNLOCK(&SessionCache[0]); +#endif + + if (active) { + *active = now; + } + if (total) { + *total = seen; + } + +#ifdef WOLFSSL_PEAK_SESSIONS + if (peak) { + *peak = PeakSessions; + } +#else + (void)peak; +#endif + + WOLFSSL_LEAVE("get_locked_session_stats", result); + + return result; +} + + +/* return WOLFSSL_SUCCESS on ok */ +int wolfSSL_get_session_stats(word32* active, word32* total, word32* peak, + word32* maxSessions) +{ + int result = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_get_session_stats"); + + if (maxSessions) { + *maxSessions = SESSIONS_PER_ROW * SESSION_ROWS; + + if (active == NULL && total == NULL && peak == NULL) + return result; /* we're done */ + } + + /* user must provide at least one query value */ + if (active == NULL && total == NULL && peak == NULL) { + return BAD_FUNC_ARG; + } + + result = get_locked_session_stats(active, total, peak); + + WOLFSSL_LEAVE("wolfSSL_get_session_stats", result); + + return result; +} + +#endif /* WOLFSSL_SESSION_STATS */ + + + #ifdef PRINT_SESSION_STATS + + /* WOLFSSL_SUCCESS on ok */ + int wolfSSL_PrintSessionStats(void) + { + word32 totalSessionsSeen = 0; + word32 totalSessionsNow = 0; + word32 peak = 0; + word32 maxSessions = 0; + int i; + int ret; + double E; /* expected freq */ + double chiSquare = 0; + + ret = wolfSSL_get_session_stats(&totalSessionsNow, &totalSessionsSeen, + &peak, &maxSessions); + if (ret != WOLFSSL_SUCCESS) + return ret; + printf("Total Sessions Seen = %u\n", totalSessionsSeen); + printf("Total Sessions Now = %u\n", totalSessionsNow); +#ifdef WOLFSSL_PEAK_SESSIONS + printf("Peak Sessions = %u\n", peak); +#endif + printf("Max Sessions = %u\n", maxSessions); + + E = (double)totalSessionsSeen / SESSION_ROWS; + + for (i = 0; i < SESSION_ROWS; i++) { + double diff = SessionCache[i].totalCount - E; + diff *= diff; /* square */ + diff /= E; /* normalize */ + + chiSquare += diff; + } + printf(" chi-square = %5.1f, d.f. = %d\n", chiSquare, + SESSION_ROWS - 1); + #if (SESSION_ROWS == 11) + printf(" .05 p value = 18.3, chi-square should be less\n"); + #elif (SESSION_ROWS == 211) + printf(".05 p value = 244.8, chi-square should be less\n"); + #elif (SESSION_ROWS == 5981) + printf(".05 p value = 6161.0, chi-square should be less\n"); + #elif (SESSION_ROWS == 3) + printf(".05 p value = 6.0, chi-square should be less\n"); + #elif (SESSION_ROWS == 2861) + printf(".05 p value = 2985.5, chi-square should be less\n"); + #endif + printf("\n"); + + return ret; + } + + #endif /* SESSION_STATS */ + +#else /* NO_SESSION_CACHE */ + +WOLFSSL_SESSION* ClientSessionToSession(const WOLFSSL_SESSION* session) +{ + return (WOLFSSL_SESSION*)session; +} + +/* No session cache version */ +WOLFSSL_SESSION* wolfSSL_GetSession(WOLFSSL* ssl, byte* masterSecret, + byte restoreSessionCerts) +{ + (void)ssl; + (void)masterSecret; + (void)restoreSessionCerts; + + return NULL; +} + +#endif /* NO_SESSION_CACHE */ + +#ifdef OPENSSL_EXTRA + + /* returns previous set cache size which stays constant */ + long wolfSSL_CTX_sess_set_cache_size(WOLFSSL_CTX* ctx, long sz) + { + /* cache size fixed at compile time in wolfSSL */ + (void)ctx; + (void)sz; + WOLFSSL_MSG("session cache is set at compile time"); + #ifndef NO_SESSION_CACHE + return (long)(SESSIONS_PER_ROW * SESSION_ROWS); + #else + return 0; + #endif + } + + + long wolfSSL_CTX_sess_get_cache_size(WOLFSSL_CTX* ctx) + { + (void)ctx; + #ifndef NO_SESSION_CACHE + return (long)(SESSIONS_PER_ROW * SESSION_ROWS); + #else + return 0; + #endif + } + +#endif + +#ifndef NO_SESSION_CACHE +int wolfSSL_CTX_add_session(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) +{ + int error = 0; + const byte* id = NULL; + byte idSz = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_add_session"); + + session = ClientSessionToSession(session); + if (session == NULL) + return WOLFSSL_FAILURE; + + /* Session cache is global */ + (void)ctx; + + if (session->haveAltSessionID) { + id = session->altSessionID; + idSz = ID_LEN; + } + else { + id = session->sessionID; + idSz = session->sessionIDSz; + } + + error = AddSessionToCache(ctx, session, id, idSz, + NULL, session->side, +#ifdef HAVE_SESSION_TICKET + session->ticketLen > 0, +#else + 0, +#endif + NULL); + + return error == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; +} +#endif + +#if !defined(NO_SESSION_CACHE) && (defined(OPENSSL_EXTRA) || \ + defined(HAVE_EXT_CACHE)) +/* stunnel 4.28 needs + * + * Callback that is called if a session tries to resume but could not find + * the session to resume it. + */ +void wolfSSL_CTX_sess_set_get_cb(WOLFSSL_CTX* ctx, + WOLFSSL_SESSION*(*f)(WOLFSSL*, const unsigned char*, int, int*)) +{ + if (ctx == NULL) + return; + +#ifdef HAVE_EXT_CACHE + ctx->get_sess_cb = f; +#else + (void)f; +#endif +} + +void wolfSSL_CTX_sess_set_new_cb(WOLFSSL_CTX* ctx, + int (*f)(WOLFSSL*, WOLFSSL_SESSION*)) +{ + if (ctx == NULL) + return; + +#ifdef HAVE_EXT_CACHE + ctx->new_sess_cb = f; +#else + (void)f; +#endif +} + +void wolfSSL_CTX_sess_set_remove_cb(WOLFSSL_CTX* ctx, void (*f)(WOLFSSL_CTX*, + WOLFSSL_SESSION*)) +{ + if (ctx == NULL) + return; + +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + ctx->rem_sess_cb = f; +#else + (void)f; +#endif +} + + +/* + * + * Note: It is expected that the importing and exporting function have been + * built with the same settings. For example if session tickets was + * enabled with the wolfSSL library exporting a session then it is + * expected to be turned on with the wolfSSL library importing the + * session. + */ +int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p) +{ + int size = 0; +#ifdef HAVE_EXT_CACHE + int idx = 0; +#ifdef SESSION_CERTS + int i; +#endif + + WOLFSSL_ENTER("wolfSSL_i2d_SSL_SESSION"); + + sess = ClientSessionToSession(sess); + if (sess == NULL) { + return BAD_FUNC_ARG; + } + + /* side | bornOn | timeout | sessionID len | sessionID | masterSecret | + * haveEMS */ + size += OPAQUE8_LEN + OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN + + sess->sessionIDSz + SECRET_LEN + OPAQUE8_LEN; + /* altSessionID */ + size += OPAQUE8_LEN + (sess->haveAltSessionID ? ID_LEN : 0); +#ifdef SESSION_CERTS + /* Peer chain */ + size += OPAQUE8_LEN; + for (i = 0; i < sess->chain.count; i++) + size += OPAQUE16_LEN + sess->chain.certs[i].length; +#endif +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + /* Protocol version */ + size += OPAQUE16_LEN; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + /* cipher suite */ + size += OPAQUE16_LEN; +#endif +#ifndef NO_CLIENT_CACHE + /* ServerID len | ServerID */ + size += OPAQUE16_LEN + sess->idLen; +#endif +#ifdef WOLFSSL_SESSION_ID_CTX + /* session context ID len | session context ID */ + size += OPAQUE8_LEN + sess->sessionCtxSz; +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + /* peerVerifyRet */ + size += OPAQUE8_LEN; +#endif +#ifdef WOLFSSL_TLS13 + /* namedGroup */ + size += OPAQUE16_LEN; +#endif +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifdef WOLFSSL_TLS13 +#ifdef WOLFSSL_32BIT_MILLI_TIME + /* ticketSeen | ticketAdd */ + size += OPAQUE32_LEN + OPAQUE32_LEN; +#else + /* ticketSeen Hi 32 bits | ticketSeen Lo 32 bits | ticketAdd */ + size += OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE32_LEN; +#endif + /* ticketNonce */ + size += OPAQUE8_LEN + sess->ticketNonce.len; +#endif +#ifdef WOLFSSL_EARLY_DATA + size += OPAQUE32_LEN; +#endif +#endif +#ifdef HAVE_SESSION_TICKET + /* ticket len | ticket */ + size += OPAQUE16_LEN + sess->ticketLen; +#endif + + if (p != NULL) { + unsigned char *data; + + if (*p == NULL) + *p = (unsigned char*)XMALLOC(size, NULL, DYNAMIC_TYPE_OPENSSL); + if (*p == NULL) + return 0; + data = *p; + + data[idx++] = sess->side; + c32toa(sess->bornOn, data + idx); idx += OPAQUE32_LEN; + c32toa(sess->timeout, data + idx); idx += OPAQUE32_LEN; + data[idx++] = sess->sessionIDSz; + XMEMCPY(data + idx, sess->sessionID, sess->sessionIDSz); + idx += sess->sessionIDSz; + XMEMCPY(data + idx, sess->masterSecret, SECRET_LEN); idx += SECRET_LEN; + data[idx++] = (byte)sess->haveEMS; + data[idx++] = sess->haveAltSessionID ? ID_LEN : 0; + if (sess->haveAltSessionID) { + XMEMCPY(data + idx, sess->altSessionID, ID_LEN); + idx += ID_LEN; + } +#ifdef SESSION_CERTS + data[idx++] = (byte)sess->chain.count; + for (i = 0; i < sess->chain.count; i++) { + c16toa((word16)sess->chain.certs[i].length, data + idx); + idx += OPAQUE16_LEN; + XMEMCPY(data + idx, sess->chain.certs[i].buffer, + sess->chain.certs[i].length); + idx += sess->chain.certs[i].length; + } +#endif +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + data[idx++] = sess->version.major; + data[idx++] = sess->version.minor; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + data[idx++] = sess->cipherSuite0; + data[idx++] = sess->cipherSuite; +#endif +#ifndef NO_CLIENT_CACHE + c16toa(sess->idLen, data + idx); idx += OPAQUE16_LEN; + XMEMCPY(data + idx, sess->serverID, sess->idLen); + idx += sess->idLen; +#endif +#ifdef WOLFSSL_SESSION_ID_CTX + data[idx++] = sess->sessionCtxSz; + XMEMCPY(data + idx, sess->sessionCtx, sess->sessionCtxSz); + idx += sess->sessionCtxSz; +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + data[idx++] = sess->peerVerifyRet; +#endif +#ifdef WOLFSSL_TLS13 + c16toa(sess->namedGroup, data + idx); + idx += OPAQUE16_LEN; +#endif +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifdef WOLFSSL_TLS13 +#ifdef WOLFSSL_32BIT_MILLI_TIME + c32toa(sess->ticketSeen, data + idx); + idx += OPAQUE32_LEN; +#else + c32toa((word32)(sess->ticketSeen >> 32), data + idx); + idx += OPAQUE32_LEN; + c32toa((word32)sess->ticketSeen, data + idx); + idx += OPAQUE32_LEN; +#endif + c32toa(sess->ticketAdd, data + idx); + idx += OPAQUE32_LEN; + data[idx++] = sess->ticketNonce.len; + XMEMCPY(data + idx, sess->ticketNonce.data, sess->ticketNonce.len); + idx += sess->ticketNonce.len; +#endif +#ifdef WOLFSSL_EARLY_DATA + c32toa(sess->maxEarlyDataSz, data + idx); + idx += OPAQUE32_LEN; +#endif +#endif +#ifdef HAVE_SESSION_TICKET + c16toa(sess->ticketLen, data + idx); idx += OPAQUE16_LEN; + XMEMCPY(data + idx, sess->ticket, sess->ticketLen); + idx += sess->ticketLen; +#endif + } +#endif + + (void)sess; + (void)p; +#ifdef HAVE_EXT_CACHE + (void)idx; +#endif + + return size; +} + + +/* TODO: no function to free new session. + * + * Note: It is expected that the importing and exporting function have been + * built with the same settings. For example if session tickets was + * enabled with the wolfSSL library exporting a session then it is + * expected to be turned on with the wolfSSL library importing the + * session. + */ +WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess, + const unsigned char** p, long i) +{ + WOLFSSL_SESSION* s = NULL; + int ret = 0; +#if defined(HAVE_EXT_CACHE) + int idx = 0; + byte* data; +#ifdef SESSION_CERTS + int j; + word16 length; +#endif +#endif /* HAVE_EXT_CACHE */ + + (void)p; + (void)i; + (void)ret; + (void)sess; + +#ifdef HAVE_EXT_CACHE + if (p == NULL || *p == NULL) + return NULL; + + s = wolfSSL_SESSION_new(); + if (s == NULL) + return NULL; + + idx = 0; + data = (byte*)*p; + + /* side | bornOn | timeout | sessionID len */ + if (i < OPAQUE8_LEN + OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->side = data[idx++]; + ato32(data + idx, &s->bornOn); idx += OPAQUE32_LEN; + ato32(data + idx, &s->timeout); idx += OPAQUE32_LEN; + s->sessionIDSz = data[idx++]; + + /* sessionID | secret | haveEMS | haveAltSessionID */ + if (i - idx < s->sessionIDSz + SECRET_LEN + OPAQUE8_LEN + OPAQUE8_LEN) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->sessionID, data + idx, s->sessionIDSz); + idx += s->sessionIDSz; + XMEMCPY(s->masterSecret, data + idx, SECRET_LEN); idx += SECRET_LEN; + s->haveEMS = data[idx++]; + if (data[idx] != ID_LEN && data[idx] != 0) { + ret = BUFFER_ERROR; + goto end; + } + s->haveAltSessionID = data[idx++] == ID_LEN; + + /* altSessionID */ + if (s->haveAltSessionID) { + if (i - idx < ID_LEN) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->altSessionID, data + idx, ID_LEN); idx += ID_LEN; + } + +#ifdef SESSION_CERTS + /* Certificate chain */ + if (i - idx == 0) { + ret = BUFFER_ERROR; + goto end; + } + s->chain.count = data[idx++]; + for (j = 0; j < s->chain.count; j++) { + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato16(data + idx, &length); idx += OPAQUE16_LEN; + s->chain.certs[j].length = length; + if (i - idx < length) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->chain.certs[j].buffer, data + idx, length); + idx += length; + } +#endif +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + /* Protocol Version */ + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->version.major = data[idx++]; + s->version.minor = data[idx++]; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + /* Cipher suite */ + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->cipherSuite0 = data[idx++]; + s->cipherSuite = data[idx++]; +#endif +#ifndef NO_CLIENT_CACHE + /* ServerID len */ + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato16(data + idx, &s->idLen); idx += OPAQUE16_LEN; + + /* ServerID */ + if (i - idx < s->idLen) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->serverID, data + idx, s->idLen); idx += s->idLen; +#endif +#ifdef WOLFSSL_SESSION_ID_CTX + /* byte for length of session context ID */ + if (i - idx < OPAQUE8_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->sessionCtxSz = data[idx++]; + + /* app session context ID */ + if (i - idx < s->sessionCtxSz) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->sessionCtx, data + idx, s->sessionCtxSz); idx += s->sessionCtxSz; +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + /* byte for peerVerifyRet */ + if (i - idx < OPAQUE8_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->peerVerifyRet = data[idx++]; +#endif +#ifdef WOLFSSL_TLS13 + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato16(data + idx, &s->namedGroup); + idx += OPAQUE16_LEN; +#endif +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifdef WOLFSSL_TLS13 + if (i - idx < (OPAQUE32_LEN * 2)) { + ret = BUFFER_ERROR; + goto end; + } +#ifdef WOLFSSL_32BIT_MILLI_TIME + ato32(data + idx, &s->ticketSeen); + idx += OPAQUE32_LEN; +#else + { + word32 seenHi, seenLo; + + ato32(data + idx, &seenHi); + idx += OPAQUE32_LEN; + ato32(data + idx, &seenLo); + idx += OPAQUE32_LEN; + s->ticketSeen = ((sword64)seenHi << 32) + seenLo; + } +#endif + ato32(data + idx, &s->ticketAdd); + idx += OPAQUE32_LEN; + if (i - idx < OPAQUE8_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->ticketNonce.len = data[idx++]; + + if (i - idx < s->ticketNonce.len) { + ret = BUFFER_ERROR; + goto end; + } +#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + ret = SessionTicketNoncePopulate(s, data + idx, s->ticketNonce.len); + if (ret != 0) + goto end; +#else + if (s->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->ticketNonce.data, data + idx, s->ticketNonce.len); +#endif /* defined(WOLFSSL_TICKET_NONCE_MALLOC) && FIPS_VERSION_GE(5,3) */ + + idx += s->ticketNonce.len; +#endif +#ifdef WOLFSSL_EARLY_DATA + if (i - idx < OPAQUE32_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato32(data + idx, &s->maxEarlyDataSz); + idx += OPAQUE32_LEN; +#endif +#endif +#ifdef HAVE_SESSION_TICKET + /* ticket len */ + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato16(data + idx, &s->ticketLen); idx += OPAQUE16_LEN; + + /* Dispose of ol dynamic ticket and ensure space for new ticket. */ + if (s->ticketLenAlloc > 0) { + XFREE(s->ticket, NULL, DYNAMIC_TYPE_SESSION_TICK); + } + if (s->ticketLen <= SESSION_TICKET_LEN) + s->ticket = s->staticTicket; + else { + s->ticket = (byte*)XMALLOC(s->ticketLen, NULL, + DYNAMIC_TYPE_SESSION_TICK); + if (s->ticket == NULL) { + ret = MEMORY_ERROR; + goto end; + } + s->ticketLenAlloc = (word16)s->ticketLen; + } + + /* ticket */ + if (i - idx < s->ticketLen) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->ticket, data + idx, s->ticketLen); idx += s->ticketLen; +#endif + (void)idx; + + if (sess != NULL) { + *sess = s; + } + + s->isSetup = 1; + + *p += idx; + +end: + if (ret != 0 && (sess == NULL || *sess != s)) { + wolfSSL_FreeSession(NULL, s); + s = NULL; + } +#endif /* HAVE_EXT_CACHE */ + return s; +} + +/* Check if there is a session ticket associated with this WOLFSSL_SESSION. + * + * sess - pointer to WOLFSSL_SESSION struct + * + * Returns 1 if has session ticket, otherwise 0 */ +int wolfSSL_SESSION_has_ticket(const WOLFSSL_SESSION* sess) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_has_ticket"); +#ifdef HAVE_SESSION_TICKET + sess = ClientSessionToSession(sess); + if (sess) { + if ((sess->ticketLen > 0) && (sess->ticket != NULL)) { + return WOLFSSL_SUCCESS; + } + } +#else + (void)sess; +#endif + return WOLFSSL_FAILURE; +} + +unsigned long wolfSSL_SESSION_get_ticket_lifetime_hint( + const WOLFSSL_SESSION* sess) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_get_ticket_lifetime_hint"); + sess = ClientSessionToSession(sess); + if (sess) { + return sess->timeout; + } + return 0; +} + +long wolfSSL_SESSION_get_timeout(const WOLFSSL_SESSION* sess) +{ + long timeout = 0; + WOLFSSL_ENTER("wolfSSL_SESSION_get_timeout"); + sess = ClientSessionToSession(sess); + if (sess) + timeout = sess->timeout; + return timeout; +} + +long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* ses, long t) +{ + word32 tmptime; + + ses = ClientSessionToSession(ses); + if (ses == NULL || t < 0) { + return BAD_FUNC_ARG; + } + + tmptime = t & 0xFFFFFFFF; + ses->timeout = tmptime; + + return WOLFSSL_SUCCESS; +} + +long wolfSSL_SESSION_get_time(const WOLFSSL_SESSION* sess) +{ + long bornOn = 0; + WOLFSSL_ENTER("wolfSSL_SESSION_get_time"); + sess = ClientSessionToSession(sess); + if (sess) + bornOn = sess->bornOn; + return bornOn; +} + +long wolfSSL_SESSION_set_time(WOLFSSL_SESSION *ses, long t) +{ + + ses = ClientSessionToSession(ses); + if (ses == NULL || t < 0) { + return 0; + } + ses->bornOn = (word32)t; + return t; +} + +#endif /* !NO_SESSION_CACHE && OPENSSL_EXTRA || HAVE_EXT_CACHE */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ + defined(HAVE_EX_DATA) + +#if defined(HAVE_EX_DATA) && !defined(NO_SESSION_CACHE) +static void SESSION_ex_data_cache_update(WOLFSSL_SESSION* session, int idx, + void* data, byte get, void** getRet, int* setRet) +{ + int row; + int i; + int error = 0; + SessionRow* sessRow = NULL; + const byte* id; + byte foundCache = 0; + + if (getRet != NULL) + *getRet = NULL; + if (setRet != NULL) + *setRet = WOLFSSL_FAILURE; + + id = session->sessionID; + if (session->haveAltSessionID) + id = session->altSessionID; + + row = (int)(HashObject(id, ID_LEN, &error) % SESSION_ROWS); + if (error != 0) { + WOLFSSL_MSG("Hash session failed"); + return; + } + + sessRow = &SessionCache[row]; + if (get) + error = SESSION_ROW_RD_LOCK(sessRow); + else + error = SESSION_ROW_WR_LOCK(sessRow); + if (error != 0) { + WOLFSSL_MSG("Session row lock failed"); + return; + } + + for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) { + WOLFSSL_SESSION* cacheSession; +#ifdef SESSION_CACHE_DYNAMIC_MEM + cacheSession = sessRow->Sessions[i]; +#else + cacheSession = &sessRow->Sessions[i]; +#endif + if (cacheSession && + XMEMCMP(id, cacheSession->sessionID, ID_LEN) == 0 + && session->side == cacheSession->side + #if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) + && (IsAtLeastTLSv1_3(session->version) == + IsAtLeastTLSv1_3(cacheSession->version)) + #endif + ) { + if (get) { + if (getRet) { + *getRet = wolfSSL_CRYPTO_get_ex_data( + &cacheSession->ex_data, idx); + } + } + else { + if (setRet) { + *setRet = wolfSSL_CRYPTO_set_ex_data( + &cacheSession->ex_data, idx, data); + } + } + foundCache = 1; + break; + } + } + SESSION_ROW_UNLOCK(sessRow); + /* If we don't have a session in cache then clear the ex_data and + * own it */ + if (!foundCache) { + XMEMSET(&session->ex_data, 0, sizeof(WOLFSSL_CRYPTO_EX_DATA)); + session->ownExData = 1; + if (!get) { + *setRet = wolfSSL_CRYPTO_set_ex_data(&session->ex_data, idx, + data); + } + } + +} +#endif + +#endif + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ + || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) + +#ifndef NO_SESSION_CACHE +int wolfSSL_SSL_CTX_remove_session(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *s) +{ +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + int rem_called = FALSE; +#endif + + WOLFSSL_ENTER("wolfSSL_SSL_CTX_remove_session"); + + s = ClientSessionToSession(s); + if (ctx == NULL || s == NULL) + return BAD_FUNC_ARG; + +#ifdef HAVE_EXT_CACHE + if (!ctx->internalCacheOff) +#endif + { + const byte* id; + WOLFSSL_SESSION *sess = NULL; + word32 row = 0; + int ret; + + id = s->sessionID; + if (s->haveAltSessionID) + id = s->altSessionID; + + ret = TlsSessionCacheGetAndWrLock(id, &sess, &row, ctx->method->side); + if (ret == 0 && sess != NULL) { +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + if (sess->rem_sess_cb != NULL) { + rem_called = TRUE; + } +#endif + /* Call this before changing ownExData so that calls to ex_data + * don't try to access the SessionCache again. */ + EvictSessionFromCache(sess); +#ifdef HAVE_EX_DATA + if (sess->ownExData) { + /* Most recent version of ex data is in cache. Copy it + * over so the user can free it. */ + XMEMCPY(&s->ex_data, &sess->ex_data, + sizeof(WOLFSSL_CRYPTO_EX_DATA)); + s->ownExData = 1; + sess->ownExData = 0; + } +#endif +#ifdef SESSION_CACHE_DYNAMIC_MEM + { + /* Find and clear entry. Row is locked so we are good to go. */ + int idx; + for (idx = 0; idx < SESSIONS_PER_ROW; idx++) { + if (sess == SessionCache[row].Sessions[idx]) { + XFREE(sess, sess->heap, DYNAMIC_TYPE_SESSION); + SessionCache[row].Sessions[idx] = NULL; + break; + } + } + } +#endif + TlsSessionCacheUnlockRow(row); + } + } + +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + if (ctx->rem_sess_cb != NULL && !rem_called) { + ctx->rem_sess_cb(ctx, s); + } +#endif + + /* s cannot be resumed at this point */ + s->timeout = 0; + + return 0; +} + +WOLFSSL_SESSION *wolfSSL_SSL_get0_session(const WOLFSSL *ssl) +{ + WOLFSSL_ENTER("wolfSSL_SSL_get0_session"); + + return ssl->session; +} + +#endif /* NO_SESSION_CACHE */ + +#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || + OPENSSL_EXTRA || HAVE_LIGHTY */ + +#ifdef WOLFSSL_SESSION_EXPORT +/* Used to import a serialized TLS session. + * WARNING: buf contains sensitive information about the state and is best to be + * encrypted before storing if stored. + * + * @param ssl WOLFSSL structure to import the session into + * @param buf serialized session + * @param sz size of buffer 'buf' + * @return the number of bytes read from buffer 'buf' + */ +int wolfSSL_tls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz) +{ + if (ssl == NULL || buf == NULL) { + return BAD_FUNC_ARG; + } + return wolfSSL_session_import_internal(ssl, buf, sz, WOLFSSL_EXPORT_TLS); +} + + +/* Used to export a serialized TLS session. + * WARNING: buf contains sensitive information about the state and is best to be + * encrypted before storing if stored. + * + * @param ssl WOLFSSL structure to export the session from + * @param buf output of serialized session + * @param sz size in bytes set in 'buf' + * @return the number of bytes written into buffer 'buf' + */ +int wolfSSL_tls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) +{ + if (ssl == NULL || sz == NULL) { + return BAD_FUNC_ARG; + } + return wolfSSL_session_export_internal(ssl, buf, sz, WOLFSSL_EXPORT_TLS); +} + +#ifdef WOLFSSL_DTLS +int wolfSSL_dtls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz) +{ + WOLFSSL_ENTER("wolfSSL_session_import"); + + if (ssl == NULL || buf == NULL) { + return BAD_FUNC_ARG; + } + + /* sanity checks on buffer and protocol are done in internal function */ + return wolfSSL_session_import_internal(ssl, buf, sz, WOLFSSL_EXPORT_DTLS); +} + + +/* Sets the function to call for serializing the session. This function is + * called right after the handshake is completed. */ +int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, wc_dtls_export func) +{ + + WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_export"); + + /* purposefully allow func to be NULL */ + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + ctx->dtls_export = func; + + return WOLFSSL_SUCCESS; +} + +/* Sets the function in WOLFSSL struct to call for serializing the session. This + * function is called right after the handshake is completed. */ +int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func) +{ + + WOLFSSL_ENTER("wolfSSL_dtls_set_export"); + + /* purposefully allow func to be NULL */ + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + ssl->dtls_export = func; + + return WOLFSSL_SUCCESS; +} + + +/* This function allows for directly serializing a session rather than using + * callbacks. It has less overhead by removing a temporary buffer and gives + * control over when the session gets serialized. When using callbacks the + * session is always serialized immediately after the handshake is finished. + * + * buf is the argument to contain the serialized session + * sz is the size of the buffer passed in + * ssl is the WOLFSSL struct to serialize + * returns the size of serialized session on success, 0 on no action, and + * negative value on error */ +int wolfSSL_dtls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) +{ + WOLFSSL_ENTER("wolfSSL_dtls_export"); + + if (ssl == NULL || sz == NULL) { + return BAD_FUNC_ARG; + } + + if (buf == NULL) { + *sz = MAX_EXPORT_BUFFER; + return 0; + } + + /* if not DTLS do nothing */ + if (!ssl->options.dtls) { + WOLFSSL_MSG("Currently only DTLS export is supported"); + return 0; + } + + /* copy over keys, options, and dtls state struct */ + return wolfSSL_session_export_internal(ssl, buf, sz, WOLFSSL_EXPORT_DTLS); +} + + +/* This function is similar to wolfSSL_dtls_export but only exports the portion + * of the WOLFSSL structure related to the state of the connection, i.e. peer + * sequence number, epoch, AEAD state etc. + * + * buf is the argument to contain the serialized state, if null then set "sz" to + * buffer size required + * sz is the size of the buffer passed in + * ssl is the WOLFSSL struct to serialize + * returns the size of serialized session on success, 0 on no action, and + * negative value on error */ +int wolfSSL_dtls_export_state_only(WOLFSSL* ssl, unsigned char* buf, + unsigned int* sz) +{ + WOLFSSL_ENTER("wolfSSL_dtls_export_state_only"); + + if (ssl == NULL || sz == NULL) { + return BAD_FUNC_ARG; + } + + if (buf == NULL) { + *sz = MAX_EXPORT_STATE_BUFFER; + return 0; + } + + /* if not DTLS do nothing */ + if (!ssl->options.dtls) { + WOLFSSL_MSG("Currently only DTLS export state is supported"); + return 0; + } + + /* copy over keys, options, and dtls state struct */ + return wolfSSL_dtls_export_state_internal(ssl, buf, *sz); +} + + +/* returns 0 on success */ +int wolfSSL_send_session(WOLFSSL* ssl) +{ + int ret; + byte* buf; + word32 bufSz = MAX_EXPORT_BUFFER; + + WOLFSSL_ENTER("wolfSSL_send_session"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + buf = (byte*)XMALLOC(bufSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + return MEMORY_E; + } + + /* if not DTLS do nothing */ + if (!ssl->options.dtls) { + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + WOLFSSL_MSG("Currently only DTLS export is supported"); + return 0; + } + + /* copy over keys, options, and dtls state struct */ + ret = wolfSSL_session_export_internal(ssl, buf, &bufSz, + WOLFSSL_EXPORT_DTLS); + if (ret < 0) { + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + /* if no error ret has size of buffer */ + ret = ssl->dtls_export(ssl, buf, ret, NULL); + if (ret != WOLFSSL_SUCCESS) { + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return 0; +} +#endif /* WOLFSSL_DTLS */ +#endif /* WOLFSSL_SESSION_EXPORT */ + +#ifdef OPENSSL_EXTRA + +/* Copies the master secret over to out buffer. If outSz is 0 returns the size + * of master secret. + * + * ses : a session from completed TLS/SSL handshake + * out : buffer to hold copy of master secret + * outSz : size of out buffer + * returns : number of bytes copied into out buffer on success + * less then or equal to 0 is considered a failure case + */ +int wolfSSL_SESSION_get_master_key(const WOLFSSL_SESSION* ses, + unsigned char* out, int outSz) +{ + int size; + + ses = ClientSessionToSession(ses); + + if (outSz == 0) { + return SECRET_LEN; + } + + if (ses == NULL || out == NULL || outSz < 0) { + return 0; + } + + if (outSz > SECRET_LEN) { + size = SECRET_LEN; + } + else { + size = outSz; + } + + XMEMCPY(out, ses->masterSecret, size); + return size; +} + + +int wolfSSL_SESSION_get_master_key_length(const WOLFSSL_SESSION* ses) +{ + (void)ses; + return SECRET_LEN; +} + +#ifdef WOLFSSL_EARLY_DATA +unsigned int wolfSSL_SESSION_get_max_early_data(const WOLFSSL_SESSION *session) +{ + return session->maxEarlyDataSz; +} +#endif /* WOLFSSL_EARLY_DATA */ + +#endif /* OPENSSL_EXTRA */ + +void SetupSession(WOLFSSL* ssl) +{ + WOLFSSL_SESSION* session = ssl->session; + + WOLFSSL_ENTER("SetupSession"); + + if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) { + /* Make sure the session ID is available when the user calls any + * get_session API */ + if (!session->haveAltSessionID) { + XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN); + session->sessionIDSz = ssl->arrays->sessionIDSz; + } + else { + XMEMCPY(session->sessionID, session->altSessionID, ID_LEN); + session->sessionIDSz = ID_LEN; + } + } + session->side = (byte)ssl->options.side; + if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) + XMEMCPY(session->masterSecret, ssl->arrays->masterSecret, SECRET_LEN); + session->haveEMS = ssl->options.haveEMS; +#ifdef WOLFSSL_SESSION_ID_CTX + /* If using compatibility layer then check for and copy over session context + * id. */ + if (ssl->sessionCtxSz > 0 && ssl->sessionCtxSz < ID_LEN) { + XMEMCPY(ssl->session->sessionCtx, ssl->sessionCtx, ssl->sessionCtxSz); + session->sessionCtxSz = ssl->sessionCtxSz; + } +#endif + session->timeout = ssl->timeout; +#ifndef NO_ASN_TIME + session->bornOn = LowResTimer(); +#endif +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + session->version = ssl->version; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + session->cipherSuite0 = ssl->options.cipherSuite0; + session->cipherSuite = ssl->options.cipherSuite; +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + session->peerVerifyRet = (byte)ssl->peerVerifyRet; +#endif + session->isSetup = 1; +} + +#ifdef WOLFSSL_SESSION_ID_CTX + /* Storing app session context id, this value is inherited by WOLFSSL + * objects created from WOLFSSL_CTX. Any session that is imported with a + * different session context id will be rejected. + * + * ctx structure to set context in + * sid_ctx value of context to set + * sid_ctx_len length of sid_ctx buffer + * + * Returns WOLFSSL_SUCCESS in success case and WOLFSSL_FAILURE when failing + */ + int wolfSSL_CTX_set_session_id_context(WOLFSSL_CTX* ctx, + const unsigned char* sid_ctx, + unsigned int sid_ctx_len) + { + WOLFSSL_ENTER("wolfSSL_CTX_set_session_id_context"); + + /* No application specific context needed for wolfSSL */ + if (sid_ctx_len > ID_LEN || ctx == NULL || sid_ctx == NULL) { + return WOLFSSL_FAILURE; + } + XMEMCPY(ctx->sessionCtx, sid_ctx, sid_ctx_len); + ctx->sessionCtxSz = (byte)sid_ctx_len; + + return WOLFSSL_SUCCESS; + } + + + + /* Storing app session context id. Any session that is imported with a + * different session context id will be rejected. + * + * ssl structure to set context in + * id value of context to set + * len length of sid_ctx buffer + * + * Returns WOLFSSL_SUCCESS in success case and WOLFSSL_FAILURE when failing + */ + int wolfSSL_set_session_id_context(WOLFSSL* ssl, const unsigned char* id, + unsigned int len) + { + WOLFSSL_ENTER("wolfSSL_set_session_id_context"); + + if (len > ID_LEN || ssl == NULL || id == NULL) { + return WOLFSSL_FAILURE; + } + XMEMCPY(ssl->sessionCtx, id, len); + ssl->sessionCtxSz = (byte)len; + + return WOLFSSL_SUCCESS; + } +#endif + +/* return a new malloc'd session with default settings on success */ +WOLFSSL_SESSION* wolfSSL_NewSession(void* heap) +{ + WOLFSSL_SESSION* ret = NULL; + + WOLFSSL_ENTER("wolfSSL_NewSession"); + + ret = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), heap, + DYNAMIC_TYPE_SESSION); + if (ret != NULL) { + int err; + XMEMSET(ret, 0, sizeof(WOLFSSL_SESSION)); + wolfSSL_RefInit(&ret->ref, &err); + #ifdef WOLFSSL_REFCNT_ERROR_RETURN + if (err != 0) { + WOLFSSL_MSG("Error setting up session reference mutex"); + XFREE(ret, ret->heap, DYNAMIC_TYPE_SESSION); + return NULL; + } + #else + (void)err; + #endif +#ifndef NO_SESSION_CACHE + ret->cacheRow = INVALID_SESSION_ROW; /* not in cache */ +#endif + ret->type = WOLFSSL_SESSION_TYPE_HEAP; + ret->heap = heap; +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("SESSION master secret", ret->masterSecret, SECRET_LEN); + wc_MemZero_Add("SESSION id", ret->sessionID, ID_LEN); +#endif + #ifdef HAVE_SESSION_TICKET + ret->ticket = ret->staticTicket; + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + ret->ticketNonce.data = ret->ticketNonce.dataStatic; + #endif + #endif +#ifdef HAVE_EX_DATA + ret->ownExData = 1; + if (crypto_ex_cb_ctx_session != NULL) { + crypto_ex_cb_setup_new_data(ret, crypto_ex_cb_ctx_session, + &ret->ex_data); + } +#endif + } + return ret; +} + + +WOLFSSL_SESSION* wolfSSL_SESSION_new_ex(void* heap) +{ + return wolfSSL_NewSession(heap); +} + +WOLFSSL_SESSION* wolfSSL_SESSION_new(void) +{ + return wolfSSL_SESSION_new_ex(NULL); +} + +/* add one to session reference count + * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error */ +int wolfSSL_SESSION_up_ref(WOLFSSL_SESSION* session) +{ + int ret; + + session = ClientSessionToSession(session); + + if (session == NULL || session->type != WOLFSSL_SESSION_TYPE_HEAP) + return WOLFSSL_FAILURE; + + wolfSSL_RefInc(&session->ref, &ret); +#ifdef WOLFSSL_REFCNT_ERROR_RETURN + if (ret != 0) { + WOLFSSL_MSG("Failed to lock session mutex"); + return WOLFSSL_FAILURE; + } +#else + (void)ret; +#endif + + return WOLFSSL_SUCCESS; +} + +/** + * Deep copy the contents from input to output. + * @param input The source of the copy. + * @param output The destination of the copy. + * @param avoidSysCalls If true, then system calls will be avoided or an error + * will be returned if it is not possible to proceed + * without a system call. This is useful for fetching + * sessions from cache. When a cache row is locked, we + * don't want to block other threads with long running + * system calls. + * @param ticketNonceBuf If not null and @avoidSysCalls is true, the copy of the + * ticketNonce will happen in this pre allocated buffer + * @param ticketNonceLen @ticketNonceBuf len as input, used length on output + * @param ticketNonceUsed if @ticketNonceBuf was used to copy the ticket noncet + * @return WOLFSSL_SUCCESS on success + * WOLFSSL_FAILURE on failure + */ +static int wolfSSL_DupSessionEx(const WOLFSSL_SESSION* input, + WOLFSSL_SESSION* output, int avoidSysCalls, byte* ticketNonceBuf, + byte* ticketNonceLen, byte* preallocUsed) +{ +#ifdef HAVE_SESSION_TICKET + int ticLenAlloc = 0; + byte *ticBuff = NULL; +#endif + const size_t copyOffset = OFFSETOF(WOLFSSL_SESSION, heap) + + sizeof(input->heap); + int ret = WOLFSSL_SUCCESS; + + (void)avoidSysCalls; + (void)ticketNonceBuf; + (void)ticketNonceLen; + (void)preallocUsed; + + input = ClientSessionToSession(input); + output = ClientSessionToSession(output); + + if (input == NULL || output == NULL || input == output) { + WOLFSSL_MSG("input or output are null or same"); + return WOLFSSL_FAILURE; + } + +#ifdef HAVE_SESSION_TICKET + if (output->ticket != output->staticTicket) { + ticBuff = output->ticket; + ticLenAlloc = output->ticketLenAlloc; + } +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + /* free the data, it would be better to reuse the buffer but this + * maintain the code simpler. A smart allocator should reuse the free'd + * buffer in the next malloc without much performance penalties. */ + if (output->ticketNonce.data != output->ticketNonce.dataStatic) { + + /* Callers that avoid syscall should never calls this with + * output->tickeNonce.data being a dynamic buffer.*/ + if (avoidSysCalls) { + WOLFSSL_MSG("can't avoid syscalls with dynamic TicketNonce buffer"); + return WOLFSSL_FAILURE; + } + + XFREE(output->ticketNonce.data, + output->heap, DYNAMIC_TYPE_SESSION_TICK); + output->ticketNonce.data = output->ticketNonce.dataStatic; + output->ticketNonce.len = 0; + } +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ +#endif /* HAVE_SESSION_TICKET */ + +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + if (output->peer != NULL) { + if (avoidSysCalls) { + WOLFSSL_MSG("Can't free cert when avoiding syscalls"); + return WOLFSSL_FAILURE; + } + wolfSSL_X509_free(output->peer); + output->peer = NULL; + } +#endif + + XMEMCPY((byte*)output + copyOffset, (byte*)input + copyOffset, + sizeof(WOLFSSL_SESSION) - copyOffset); + +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + /* fix pointer to static after the copy */ + output->ticketNonce.data = output->ticketNonce.dataStatic; +#endif + /* Set sane values for copy */ +#ifndef NO_SESSION_CACHE + if (output->type != WOLFSSL_SESSION_TYPE_CACHE) + output->cacheRow = INVALID_SESSION_ROW; +#endif +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + if (input->peer != NULL && input->peer->dynamicMemory) { + if (wolfSSL_X509_up_ref(input->peer) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Can't increase peer cert ref count"); + output->peer = NULL; + } + } + else if (!avoidSysCalls) + output->peer = wolfSSL_X509_dup(input->peer); + else + /* output->peer is not that important to copy */ + output->peer = NULL; +#endif +#ifdef HAVE_SESSION_TICKET + if (input->ticketLen > SESSION_TICKET_LEN) { + /* Need dynamic buffer */ + if (ticBuff == NULL || ticLenAlloc < input->ticketLen) { + /* allocate new one */ + byte* tmp; + if (avoidSysCalls) { + WOLFSSL_MSG("Failed to allocate memory for ticket when avoiding" + " syscalls"); + output->ticket = ticBuff; + output->ticketLenAlloc = (word16) ticLenAlloc; + output->ticketLen = 0; + ret = WOLFSSL_FAILURE; + } + else { +#ifdef WOLFSSL_NO_REALLOC + tmp = (byte*)XMALLOC(input->ticketLen, + output->heap, DYNAMIC_TYPE_SESSION_TICK); + XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK); + ticBuff = NULL; +#else + tmp = (byte*)XREALLOC(ticBuff, input->ticketLen, + output->heap, DYNAMIC_TYPE_SESSION_TICK); +#endif /* WOLFSSL_NO_REALLOC */ + if (tmp == NULL) { + WOLFSSL_MSG("Failed to allocate memory for ticket"); +#ifndef WOLFSSL_NO_REALLOC + XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK); + ticBuff = NULL; +#endif /* WOLFSSL_NO_REALLOC */ + output->ticket = NULL; + output->ticketLen = 0; + output->ticketLenAlloc = 0; + ret = WOLFSSL_FAILURE; + } + else { + ticBuff = tmp; + ticLenAlloc = input->ticketLen; + } + } + } + if (ticBuff != NULL && ret == WOLFSSL_SUCCESS) { + XMEMCPY(ticBuff, input->ticket, input->ticketLen); + output->ticket = ticBuff; + output->ticketLenAlloc = (word16) ticLenAlloc; + } + } + else { + /* Default ticket to non dynamic */ + if (avoidSysCalls) { + /* Try to use ticBuf if available. Caller can later move it to + * the static buffer. */ + if (ticBuff != NULL) { + if (ticLenAlloc >= input->ticketLen) { + output->ticket = ticBuff; + output->ticketLenAlloc = ticLenAlloc; + } + else { + WOLFSSL_MSG("ticket dynamic buffer too small but we are " + "avoiding system calls"); + ret = WOLFSSL_FAILURE; + output->ticket = ticBuff; + output->ticketLenAlloc = (word16) ticLenAlloc; + output->ticketLen = 0; + } + } + else { + output->ticket = output->staticTicket; + output->ticketLenAlloc = 0; + } + } + else { + if (ticBuff != NULL) + XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK); + output->ticket = output->staticTicket; + output->ticketLenAlloc = 0; + } + if (input->ticketLenAlloc > 0 && ret == WOLFSSL_SUCCESS) { + /* Shouldn't happen as session should have placed this in + * the static buffer */ + XMEMCPY(output->ticket, input->ticket, + input->ticketLen); + } + } + ticBuff = NULL; + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (preallocUsed != NULL) + *preallocUsed = 0; + + if (input->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ && + ret == WOLFSSL_SUCCESS) { + /* TicketNonce does not fit in the static buffer */ + if (!avoidSysCalls) { + output->ticketNonce.data = (byte*)XMALLOC(input->ticketNonce.len, + output->heap, DYNAMIC_TYPE_SESSION_TICK); + + if (output->ticketNonce.data == NULL) { + WOLFSSL_MSG("Failed to allocate space for ticket nonce"); + output->ticketNonce.data = output->ticketNonce.dataStatic; + output->ticketNonce.len = 0; + ret = WOLFSSL_FAILURE; + } + else { + output->ticketNonce.len = input->ticketNonce.len; + XMEMCPY(output->ticketNonce.data, input->ticketNonce.data, + input->ticketNonce.len); + ret = WOLFSSL_SUCCESS; + } + } + /* we can't do syscalls. Use prealloc buffers if provided from the + * caller. */ + else if (ticketNonceBuf != NULL && + *ticketNonceLen >= input->ticketNonce.len) { + XMEMCPY(ticketNonceBuf, input->ticketNonce.data, + input->ticketNonce.len); + *ticketNonceLen = input->ticketNonce.len; + if (preallocUsed != NULL) + *preallocUsed = 1; + ret = WOLFSSL_SUCCESS; + } + else { + WOLFSSL_MSG("TicketNonce bigger than static buffer, and we can't " + "do syscalls"); + ret = WOLFSSL_FAILURE; + } + } +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ + +#endif /* HAVE_SESSION_TICKET */ + +#ifdef HAVE_EX_DATA + if (input->type != WOLFSSL_SESSION_TYPE_CACHE && + output->type != WOLFSSL_SESSION_TYPE_CACHE) { + /* Not called with cache as that passes ownership of ex_data */ + ret = crypto_ex_cb_dup_data(&input->ex_data, &output->ex_data, + crypto_ex_cb_ctx_session); + } +#endif + + return ret; +} + +/** + * Deep copy the contents from input to output. + * @param input The source of the copy. + * @param output The destination of the copy. + * @param avoidSysCalls If true, then system calls will be avoided or an error + * will be returned if it is not possible to proceed + * without a system call. This is useful for fetching + * sessions from cache. When a cache row is locked, we + * don't want to block other threads with long running + * system calls. + * @return WOLFSSL_SUCCESS on success + * WOLFSSL_FAILURE on failure + */ +int wolfSSL_DupSession(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output, + int avoidSysCalls) +{ + return wolfSSL_DupSessionEx(input, output, avoidSysCalls, NULL, NULL, NULL); +} + +WOLFSSL_SESSION* wolfSSL_SESSION_dup(WOLFSSL_SESSION* session) +{ + WOLFSSL_SESSION* copy; + + WOLFSSL_ENTER("wolfSSL_SESSION_dup"); + + session = ClientSessionToSession(session); + if (session == NULL) + return NULL; + +#ifdef HAVE_SESSION_TICKET + if (session->ticketLenAlloc > 0 && !session->ticket) { + WOLFSSL_MSG("Session dynamic flag is set but ticket pointer is null"); + return NULL; + } +#endif + + copy = wolfSSL_NewSession(session->heap); + if (copy != NULL && + wolfSSL_DupSession(session, copy, 0) != WOLFSSL_SUCCESS) { + wolfSSL_FreeSession(NULL, copy); + copy = NULL; + } + return copy; +} + +void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) +{ + session = ClientSessionToSession(session); + if (session == NULL) + return; + + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_FreeSession"); + + if (session->ref.count > 0) { + int ret; + int isZero; + wolfSSL_RefDec(&session->ref, &isZero, &ret); + (void)ret; + if (!isZero) { + return; + } + wolfSSL_RefFree(&session->ref); + } + + WOLFSSL_MSG("wolfSSL_FreeSession full free"); + +#ifdef HAVE_EX_DATA + if (session->ownExData) { + crypto_ex_cb_free_data(session, crypto_ex_cb_ctx_session, + &session->ex_data); + } +#endif + +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS + wolfSSL_CRYPTO_cleanup_ex_data(&session->ex_data); +#endif + +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + if (session->peer) { + wolfSSL_X509_free(session->peer); + session->peer = NULL; + } +#endif + +#ifdef HAVE_SESSION_TICKET + if (session->ticketLenAlloc > 0) { + XFREE(session->ticket, session->heap, DYNAMIC_TYPE_SESSION_TICK); + session->ticket = session->staticTicket; + session->ticketLen = 0; + session->ticketLenAlloc = 0; + } +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (session->ticketNonce.data != session->ticketNonce.dataStatic) { + XFREE(session->ticketNonce.data, session->heap, + DYNAMIC_TYPE_SESSION_TICK); + session->ticketNonce.data = session->ticketNonce.dataStatic; + session->ticketNonce.len = 0; + } +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ +#endif + +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS + wolfSSL_CRYPTO_cleanup_ex_data(&session->ex_data); +#endif + + /* Make sure masterSecret is zeroed. */ + ForceZero(session->masterSecret, SECRET_LEN); + /* Session ID is sensitive information too. */ + ForceZero(session->sessionID, ID_LEN); + + if (session->type == WOLFSSL_SESSION_TYPE_HEAP) { + XFREE(session, session->heap, DYNAMIC_TYPE_SESSION); + } +} + +/* DO NOT use this API internally. Use wolfSSL_FreeSession directly instead + * and pass in the ctx parameter if possible (like from ssl->ctx). */ +void wolfSSL_SESSION_free(WOLFSSL_SESSION* session) +{ + session = ClientSessionToSession(session); + wolfSSL_FreeSession(NULL, session); +} + +#if defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE) + +/** +* set cipher to WOLFSSL_SESSION from WOLFSSL_CIPHER +* @param session a pointer to WOLFSSL_SESSION structure +* @param cipher a function pointer to WOLFSSL_CIPHER +* @return WOLFSSL_SUCCESS on success, otherwise WOLFSSL_FAILURE +*/ +int wolfSSL_SESSION_set_cipher(WOLFSSL_SESSION* session, + const WOLFSSL_CIPHER* cipher) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_set_cipher"); + + session = ClientSessionToSession(session); + /* sanity check */ + if (session == NULL || cipher == NULL) { + WOLFSSL_MSG("bad argument"); + return WOLFSSL_FAILURE; + } + session->cipherSuite0 = cipher->cipherSuite0; + session->cipherSuite = cipher->cipherSuite; + + WOLFSSL_LEAVE("wolfSSL_SESSION_set_cipher", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; +} +#endif /* OPENSSL_EXTRA || HAVE_EXT_CACHE */ + +const char* wolfSSL_SESSION_CIPHER_get_name(const WOLFSSL_SESSION* session) +{ + session = ClientSessionToSession(session); + if (session == NULL) { + return NULL; + } + +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + #if !defined(WOLFSSL_CIPHER_INTERNALNAME) && !defined(NO_ERROR_STRINGS) + return GetCipherNameIana(session->cipherSuite0, session->cipherSuite); + #else + return GetCipherNameInternal(session->cipherSuite0, + session->cipherSuite); + #endif +#else + return NULL; +#endif +} + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) +const unsigned char *wolfSSL_SESSION_get0_id_context( + const WOLFSSL_SESSION *sess, unsigned int *sid_ctx_length) +{ + return wolfSSL_SESSION_get_id((WOLFSSL_SESSION *)sess, sid_ctx_length); +} +int wolfSSL_SESSION_set1_id(WOLFSSL_SESSION *s, + const unsigned char *sid, unsigned int sid_len) +{ + if (s == NULL) { + return WOLFSSL_FAILURE; + } + if (sid_len > ID_LEN) { + return WOLFSSL_FAILURE; + } + s->sessionIDSz = sid_len; + if (sid != s->sessionID) { + XMEMCPY(s->sessionID, sid, sid_len); + } + return WOLFSSL_SUCCESS; +} + +int wolfSSL_SESSION_set1_id_context(WOLFSSL_SESSION *s, + const unsigned char *sid_ctx, unsigned int sid_ctx_len) +{ + if (s == NULL) { + return WOLFSSL_FAILURE; + } + if (sid_ctx_len > ID_LEN) { + return WOLFSSL_FAILURE; + } + s->sessionCtxSz = sid_ctx_len; + if (sid_ctx != s->sessionCtx) { + XMEMCPY(s->sessionCtx, sid_ctx, sid_ctx_len); + } + + return WOLFSSL_SUCCESS; +} + +#endif + +#ifdef OPENSSL_EXTRA + +/* Return the total number of sessions */ +long wolfSSL_CTX_sess_number(WOLFSSL_CTX* ctx) +{ + word32 total = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_sess_number"); + (void)ctx; + +#if defined(WOLFSSL_SESSION_STATS) && !defined(NO_SESSION_CACHE) + if (wolfSSL_get_session_stats(NULL, &total, NULL, NULL) != + WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error getting session stats"); + } +#else + WOLFSSL_MSG("Please use macro WOLFSSL_SESSION_STATS for session stats"); +#endif + + return (long)total; +} + +#endif + +#ifdef SESSION_CERTS + +/* get session ID */ +WOLFSSL_ABI +const byte* wolfSSL_get_sessionID(const WOLFSSL_SESSION* session) +{ + WOLFSSL_ENTER("wolfSSL_get_sessionID"); + session = ClientSessionToSession(session); + if (session) + return session->sessionID; + + return NULL; +} + +#endif + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ + defined(HAVE_EX_DATA) + +int wolfSSL_SESSION_set_ex_data(WOLFSSL_SESSION* session, int idx, void* data) +{ + int ret = WOLFSSL_FAILURE; + WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data"); +#ifdef HAVE_EX_DATA + session = ClientSessionToSession(session); + if (session != NULL) { +#ifndef NO_SESSION_CACHE + if (!session->ownExData) { + /* Need to update in cache */ + SESSION_ex_data_cache_update(session, idx, data, 0, NULL, &ret); + } + else +#endif + { + ret = wolfSSL_CRYPTO_set_ex_data(&session->ex_data, idx, data); + } + } +#else + (void)session; + (void)idx; + (void)data; +#endif + return ret; +} + +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS +int wolfSSL_SESSION_set_ex_data_with_cleanup( + WOLFSSL_SESSION* session, + int idx, + void* data, + wolfSSL_ex_data_cleanup_routine_t cleanup_routine) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data_with_cleanup"); + session = ClientSessionToSession(session); + if(session != NULL) { + return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&session->ex_data, idx, + data, cleanup_routine); + } + return WOLFSSL_FAILURE; +} +#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ + +void* wolfSSL_SESSION_get_ex_data(const WOLFSSL_SESSION* session, int idx) +{ + void* ret = NULL; + WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_data"); +#ifdef HAVE_EX_DATA + session = ClientSessionToSession(session); + if (session != NULL) { +#ifndef NO_SESSION_CACHE + if (!session->ownExData) { + /* Need to retrieve the data from the session cache */ + SESSION_ex_data_cache_update((WOLFSSL_SESSION*)session, idx, NULL, + 1, &ret, NULL); + } + else +#endif + { + ret = wolfSSL_CRYPTO_get_ex_data(&session->ex_data, idx); + } + } +#else + (void)session; + (void)idx; +#endif + return ret; +} +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL || HAVE_EX_DATA */ + +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB))) +#ifdef HAVE_EX_DATA +int wolfSSL_SESSION_get_ex_new_index(long ctx_l,void* ctx_ptr, + WOLFSSL_CRYPTO_EX_new* new_func, WOLFSSL_CRYPTO_EX_dup* dup_func, + WOLFSSL_CRYPTO_EX_free* free_func) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_new_index"); + return wolfssl_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_SESSION, ctx_l, + ctx_ptr, new_func, dup_func, free_func); +} +#endif +#endif + + +#if defined(OPENSSL_ALL) || \ + defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + +const byte* wolfSSL_SESSION_get_id(const WOLFSSL_SESSION* sess, + unsigned int* idLen) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_get_id"); + sess = ClientSessionToSession(sess); + if (sess == NULL || idLen == NULL) { + WOLFSSL_MSG("Bad func args. Please provide idLen"); + return NULL; + } +#ifdef HAVE_SESSION_TICKET + if (sess->haveAltSessionID) { + *idLen = ID_LEN; + return sess->altSessionID; + } +#endif + *idLen = sess->sessionIDSz; + return sess->sessionID; +} + +#if (defined(HAVE_SESSION_TICKET) || defined(SESSION_CERTS)) && \ + !defined(NO_FILESYSTEM) + +#ifndef NO_BIO + +#if defined(SESSION_CERTS) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) +static const char* wolfSSL_internal_get_version(const ProtocolVersion* version); + +/* returns a pointer to the protocol used by the session */ +static const char* wolfSSL_SESSION_get_protocol(const WOLFSSL_SESSION* in) +{ + in = ClientSessionToSession(in); + return wolfSSL_internal_get_version((ProtocolVersion*)&in->version); +} +#endif + +/* returns true (non 0) if the session has EMS (extended master secret) */ +static int wolfSSL_SESSION_haveEMS(const WOLFSSL_SESSION* in) +{ + in = ClientSessionToSession(in); + if (in == NULL) + return 0; + return in->haveEMS; +} + +#if defined(HAVE_SESSION_TICKET) +/* prints out the ticket to bio passed in + * return WOLFSSL_SUCCESS on success + */ +static int wolfSSL_SESSION_print_ticket(WOLFSSL_BIO* bio, + const WOLFSSL_SESSION* in, const char* tab) +{ + unsigned short i, j, z, sz; + short tag = 0; + byte* pt; + + + in = ClientSessionToSession(in); + if (in == NULL || bio == NULL) { + return BAD_FUNC_ARG; + } + + sz = in->ticketLen; + pt = in->ticket; + + if (wolfSSL_BIO_printf(bio, "%s\n", (sz == 0)? " NONE": "") <= 0) + return WOLFSSL_FAILURE; + + for (i = 0; i < sz;) { + char asc[16]; + XMEMSET(asc, 0, sizeof(asc)); + + if (sz - i < 16) { + if (wolfSSL_BIO_printf(bio, "%s%04X -", tab, tag + (sz - i)) <= 0) + return WOLFSSL_FAILURE; + } + else { + if (wolfSSL_BIO_printf(bio, "%s%04X -", tab, tag) <= 0) + return WOLFSSL_FAILURE; + } + for (j = 0; i < sz && j < 8; j++,i++) { + asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; + if (wolfSSL_BIO_printf(bio, " %02X", pt[i]) <= 0) + return WOLFSSL_FAILURE; + } + + if (i < sz) { + asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; + if (wolfSSL_BIO_printf(bio, "-%02X", pt[i]) <= 0) + return WOLFSSL_FAILURE; + j++; + i++; + } + + for (; i < sz && j < 16; j++,i++) { + asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; + if (wolfSSL_BIO_printf(bio, " %02X", pt[i]) <= 0) + return WOLFSSL_FAILURE; + } + + /* pad out spacing */ + for (z = j; z < 17; z++) { + if (wolfSSL_BIO_printf(bio, " ") <= 0) + return WOLFSSL_FAILURE; + } + + for (z = 0; z < j; z++) { + if (wolfSSL_BIO_printf(bio, "%c", asc[z]) <= 0) + return WOLFSSL_FAILURE; + } + if (wolfSSL_BIO_printf(bio, "\n") <= 0) + return WOLFSSL_FAILURE; + + tag += 16; + } + return WOLFSSL_SUCCESS; +} +#endif /* HAVE_SESSION_TICKET */ + + +/* prints out the session information in human readable form + * return WOLFSSL_SUCCESS on success + */ +int wolfSSL_SESSION_print(WOLFSSL_BIO *bp, const WOLFSSL_SESSION *session) +{ + const unsigned char* pt; + unsigned char buf[SECRET_LEN]; + unsigned int sz = 0, i; + int ret; + + session = ClientSessionToSession(session); + if (session == NULL) { + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_printf(bp, "%s\n", "SSL-Session:") <= 0) + return WOLFSSL_FAILURE; + +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + if (wolfSSL_BIO_printf(bp, " Protocol : %s\n", + wolfSSL_SESSION_get_protocol(session)) <= 0) + return WOLFSSL_FAILURE; +#endif + + if (wolfSSL_BIO_printf(bp, " Cipher : %s\n", + wolfSSL_SESSION_CIPHER_get_name(session)) <= 0) + return WOLFSSL_FAILURE; + + pt = wolfSSL_SESSION_get_id(session, &sz); + if (wolfSSL_BIO_printf(bp, " Session-ID: ") <= 0) + return WOLFSSL_FAILURE; + + for (i = 0; i < sz; i++) { + if (wolfSSL_BIO_printf(bp, "%02X", pt[i]) <= 0) + return WOLFSSL_FAILURE; + } + if (wolfSSL_BIO_printf(bp, "\n") <= 0) + return WOLFSSL_FAILURE; + + if (wolfSSL_BIO_printf(bp, " Session-ID-ctx: \n") <= 0) + return WOLFSSL_FAILURE; + + ret = wolfSSL_SESSION_get_master_key(session, buf, sizeof(buf)); + if (wolfSSL_BIO_printf(bp, " Master-Key: ") <= 0) + return WOLFSSL_FAILURE; + + if (ret > 0) { + sz = (unsigned int)ret; + for (i = 0; i < sz; i++) { + if (wolfSSL_BIO_printf(bp, "%02X", buf[i]) <= 0) + return WOLFSSL_FAILURE; + } + } + if (wolfSSL_BIO_printf(bp, "\n") <= 0) + return WOLFSSL_FAILURE; + + /* @TODO PSK identity hint and SRP */ + + if (wolfSSL_BIO_printf(bp, " TLS session ticket:") <= 0) + return WOLFSSL_FAILURE; + +#ifdef HAVE_SESSION_TICKET + if (wolfSSL_SESSION_print_ticket(bp, session, " ") != WOLFSSL_SUCCESS) + return WOLFSSL_FAILURE; +#endif + +#if !defined(NO_SESSION_CACHE) && (defined(OPENSSL_EXTRA) || \ + defined(HAVE_EXT_CACHE)) + if (wolfSSL_BIO_printf(bp, " Start Time: %ld\n", + wolfSSL_SESSION_get_time(session)) <= 0) + return WOLFSSL_FAILURE; + + if (wolfSSL_BIO_printf(bp, " Timeout : %ld (sec)\n", + wolfSSL_SESSION_get_timeout(session)) <= 0) + return WOLFSSL_FAILURE; +#endif /* !NO_SESSION_CACHE && OPENSSL_EXTRA || HAVE_EXT_CACHE */ + + /* @TODO verify return code print */ + + if (wolfSSL_BIO_printf(bp, " Extended master secret: %s\n", + (wolfSSL_SESSION_haveEMS(session) == 0)? "no" : "yes") <= 0) + return WOLFSSL_FAILURE; + + return WOLFSSL_SUCCESS; +} + +#endif /* !NO_BIO */ +#endif /* (HAVE_SESSION_TICKET || SESSION_CERTS) && !NO_FILESYSTEM */ + +#endif /* OPENSSL_ALL || OPENSSL_EXTRA || HAVE_STUNNEL || WOLFSSL_NGINX || + * WOLFSSL_HAPROXY */ + +#ifdef OPENSSL_EXTRA +/** + * Determine whether a WOLFSSL_SESSION object can be used for resumption + * @param s a pointer to WOLFSSL_SESSION structure + * @return return 1 if session is resumable, otherwise 0. + */ +int wolfSSL_SESSION_is_resumable(const WOLFSSL_SESSION *s) +{ + s = ClientSessionToSession(s); + if (s == NULL) + return 0; + +#ifdef HAVE_SESSION_TICKET + if (s->ticketLen > 0) + return 1; +#endif + + if (s->sessionIDSz > 0) + return 1; + + return 0; +} +#endif /* OPENSSL_EXTRA */ + +#endif /* !WOLFSSL_SSL_SESS_INCLUDED */ + diff --git a/src/x509.c b/src/x509.c index f39df7743..56fd9aa40 100644 --- a/src/x509.c +++ b/src/x509.c @@ -11262,6 +11262,27 @@ cleanup: return loadX509orX509REQFromPemBio(bp, x, cb, u, CERT_TYPE); } + /* + * bp : bio to read X509 from + * x : x509 to write to + * cb : password call back for reading PEM + * u : password + * _AUX is for working with a trusted X509 certificate + */ + WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509_AUX(WOLFSSL_BIO *bp, + WOLFSSL_X509 **x, wc_pem_password_cb *cb, + void *u) + { + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509"); + + /* AUX info is; trusted/rejected uses, friendly name, private key id, + * and potentially a stack of "other" info. wolfSSL does not store + * friendly name or private key id yet in WOLFSSL_X509 for human + * readability and does not support extra trusted/rejected uses for + * root CA. */ + return wolfSSL_PEM_read_bio_X509(bp, x, cb, u); + } + #ifdef WOLFSSL_CERT_REQ WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509_REQ(WOLFSSL_BIO *bp, WOLFSSL_X509 **x, wc_pem_password_cb *cb, void *u) diff --git a/tests/api.c b/tests/api.c index 0a72105b6..698afe2a2 100644 --- a/tests/api.c +++ b/tests/api.c @@ -348,9 +348,15 @@ #ifdef HAVE_PKCS7 #include #endif +#ifdef HAVE_CURVE25519 + #include +#endif #ifdef HAVE_ED25519 #include #endif +#ifdef HAVE_CURVE448 + #include +#endif #ifdef HAVE_ED448 #include #endif @@ -5004,6 +5010,90 @@ static int test_wolfSSL_SetMinVersion(void) #ifdef OPENSSL_EXTRA +static int test_EC25519(void) +{ + EXPECT_DECLS; +#if defined(HAVE_CURVE25519) && defined(WOLFSSL_KEY_GEN) + byte priv[CURVE25519_KEYSIZE]; + unsigned int privSz = CURVE25519_KEYSIZE; + byte pub[CURVE25519_KEYSIZE]; + unsigned int pubSz = CURVE25519_KEYSIZE; + byte priv2[CURVE25519_KEYSIZE]; + unsigned int priv2Sz = CURVE25519_KEYSIZE; + byte pub2[CURVE25519_KEYSIZE]; + unsigned int pub2Sz = CURVE25519_KEYSIZE; + byte shared[CURVE25519_KEYSIZE]; + unsigned int sharedSz = CURVE25519_KEYSIZE; + byte shared2[CURVE25519_KEYSIZE]; + unsigned int shared2Sz = CURVE25519_KEYSIZE; + + /* Bad parameter testing of key generation. */ + ExpectIntEQ(wolfSSL_EC25519_generate_key(NULL, NULL, NULL, NULL), 0); + ExpectIntEQ(wolfSSL_EC25519_generate_key(NULL, &privSz, NULL, &pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_generate_key(NULL, &privSz, pub, &pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_generate_key(priv, NULL, pub, &pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_generate_key(priv, &privSz, NULL, &pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_generate_key(priv, &privSz, pub, NULL), 0); + /* Bad length */ + privSz = 1; + ExpectIntEQ(wolfSSL_EC25519_generate_key(priv, &privSz, pub, &pubSz), 0); + privSz = CURVE25519_KEYSIZE; + pubSz = 1; + ExpectIntEQ(wolfSSL_EC25519_generate_key(priv, &privSz, pub, &pubSz), 0); + pubSz = CURVE25519_KEYSIZE; + + /* Good case of generating key. */ + ExpectIntEQ(wolfSSL_EC25519_generate_key(priv, &privSz, pub, &pubSz), 1); + ExpectIntEQ(wolfSSL_EC25519_generate_key(priv2, &priv2Sz, pub2, &pub2Sz), + 1); + ExpectIntEQ(privSz, CURVE25519_KEYSIZE); + ExpectIntEQ(pubSz, CURVE25519_KEYSIZE); + + /* Bad parameter testing of shared key. */ + ExpectIntEQ(wolfSSL_EC25519_shared_key( NULL, NULL, NULL, privSz, + NULL, pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_shared_key( NULL, &sharedSz, NULL, privSz, + NULL, pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_shared_key( NULL, &sharedSz, priv, privSz, + pub, pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_shared_key(shared, &sharedSz, NULL, privSz, + pub, pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_shared_key(shared, &sharedSz, priv, privSz, + NULL, pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_shared_key( NULL, &sharedSz, priv, privSz, + pub, pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_shared_key(shared, NULL, priv, privSz, + pub, pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_shared_key(shared, &sharedSz, NULL, privSz, + pub, pubSz), 0); + ExpectIntEQ(wolfSSL_EC25519_shared_key(shared, &sharedSz, priv, privSz, + NULL, pubSz), 0); + /* Bad length. */ + sharedSz = 1; + ExpectIntEQ(wolfSSL_EC25519_shared_key(shared, &sharedSz, priv, privSz, + pub, pubSz), 0); + sharedSz = CURVE25519_KEYSIZE; + privSz = 1; + ExpectIntEQ(wolfSSL_EC25519_shared_key(shared, &sharedSz, priv, privSz, + pub, pubSz), 0); + privSz = CURVE25519_KEYSIZE; + pubSz = 1; + ExpectIntEQ(wolfSSL_EC25519_shared_key(shared, &sharedSz, priv, privSz, + pub, pubSz), 0); + pubSz = CURVE25519_KEYSIZE; + + /* Good case of shared key. */ + ExpectIntEQ(wolfSSL_EC25519_shared_key(shared, &sharedSz, priv, privSz, + pub2, pub2Sz), 1); + ExpectIntEQ(wolfSSL_EC25519_shared_key(shared2, &shared2Sz, priv2, priv2Sz, + pub, pubSz), 1); + ExpectIntEQ(sharedSz, CURVE25519_KEYSIZE); + ExpectIntEQ(shared2Sz, CURVE25519_KEYSIZE); + ExpectIntEQ(XMEMCMP(shared, shared2, sharedSz), 0); +#endif /* HAVE_CURVE25519 && WOLFSSL_KEY_GEN */ + return EXPECT_RESULT(); +} + static int test_ED25519(void) { EXPECT_DECLS; @@ -5020,25 +5110,189 @@ static int test_ED25519(void) unsigned int sigSz = (unsigned int)sizeof(sig); #endif /* HAVE_ED25519_SIGN && HAVE_ED25519_KEY_IMPORT */ + /* Bad parameter testing of key generation. */ + ExpectIntEQ(wolfSSL_ED25519_generate_key(NULL, NULL, NULL, NULL), 0); + ExpectIntEQ(wolfSSL_ED25519_generate_key(priv, NULL, NULL, NULL), 0); + ExpectIntEQ(wolfSSL_ED25519_generate_key(NULL, &privSz, NULL, NULL), 0); + ExpectIntEQ(wolfSSL_ED25519_generate_key(NULL, NULL, pub, NULL), 0); + ExpectIntEQ(wolfSSL_ED25519_generate_key(NULL, NULL, NULL, &pubSz), 0); + ExpectIntEQ(wolfSSL_ED25519_generate_key(NULL, &privSz, pub, &pubSz), 0); + ExpectIntEQ(wolfSSL_ED25519_generate_key(priv, NULL, pub, &pubSz), 0); + ExpectIntEQ(wolfSSL_ED25519_generate_key(priv, &privSz, NULL, &pubSz), 0); + ExpectIntEQ(wolfSSL_ED25519_generate_key(priv, &privSz, pub, NULL), 0); + /* Bad length. */ + privSz = 1; + ExpectIntEQ(wolfSSL_ED25519_generate_key(priv, &privSz, pub, &pubSz), 0); + privSz = ED25519_PRV_KEY_SIZE; + pubSz = 1; + ExpectIntEQ(wolfSSL_ED25519_generate_key(priv, &privSz, pub, &pubSz), 0); + pubSz = ED25519_PUB_KEY_SIZE; + + /* Good case of generating key. */ ExpectIntEQ(wolfSSL_ED25519_generate_key(priv, &privSz, pub, &pubSz), - WOLFSSL_SUCCESS); + 1); ExpectIntEQ(privSz, ED25519_PRV_KEY_SIZE); ExpectIntEQ(pubSz, ED25519_PUB_KEY_SIZE); #if defined(HAVE_ED25519_SIGN) && defined(HAVE_ED25519_KEY_IMPORT) + /* Bad parameter testing of signing. */ + ExpectIntEQ(wolfSSL_ED25519_sign( NULL, msglen, NULL, privSz, NULL, + NULL), 0); + ExpectIntEQ(wolfSSL_ED25519_sign((byte*)msg, msglen, NULL, privSz, NULL, + NULL), 0); + ExpectIntEQ(wolfSSL_ED25519_sign( NULL, msglen, priv, privSz, NULL, + NULL), 0); + ExpectIntEQ(wolfSSL_ED25519_sign( NULL, msglen, NULL, privSz, sig, + NULL), 0); + ExpectIntEQ(wolfSSL_ED25519_sign( NULL, msglen, NULL, privSz, NULL, + &sigSz), 0); + ExpectIntEQ(wolfSSL_ED25519_sign( NULL, msglen, priv, privSz, sig, + &sigSz), 0); + ExpectIntEQ(wolfSSL_ED25519_sign((byte*)msg, msglen, NULL, privSz, sig, + &sigSz), 0); + ExpectIntEQ(wolfSSL_ED25519_sign((byte*)msg, msglen, priv, privSz, NULL, + &sigSz), 0); + ExpectIntEQ(wolfSSL_ED25519_sign((byte*)msg, msglen, priv, privSz, sig, + NULL), 0); + /* Bad length. */ + privSz = 1; ExpectIntEQ(wolfSSL_ED25519_sign((byte*)msg, msglen, priv, privSz, sig, - &sigSz), WOLFSSL_SUCCESS); + &sigSz), 0); + privSz = ED25519_PRV_KEY_SIZE; + sigSz = 1; + ExpectIntEQ(wolfSSL_ED25519_sign((byte*)msg, msglen, priv, privSz, sig, + &sigSz), 0); + sigSz = ED25519_SIG_SIZE; + + /* Good case of signing. */ + ExpectIntEQ(wolfSSL_ED25519_sign((byte*)msg, msglen, priv, privSz, sig, + &sigSz), 1); ExpectIntEQ(sigSz, ED25519_SIG_SIZE); #ifdef HAVE_ED25519_VERIFY + /* Bad parameter testing of verification. */ + ExpectIntEQ(wolfSSL_ED25519_verify( NULL, msglen, NULL, pubSz, NULL, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED25519_verify((byte*)msg, msglen, NULL, pubSz, NULL, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED25519_verify( NULL, msglen, pub, pubSz, NULL, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED25519_verify( NULL, msglen, NULL, pubSz, sig, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED25519_verify( NULL, msglen, pub, pubSz, sig, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED25519_verify((byte*)msg, msglen, NULL, pubSz, sig, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED25519_verify((byte*)msg, msglen, pub, pubSz, NULL, + sigSz), 0); + /* Bad length. */ + pubSz = 1; ExpectIntEQ(wolfSSL_ED25519_verify((byte*)msg, msglen, pub, pubSz, sig, - sigSz), WOLFSSL_SUCCESS); + sigSz), 0); + pubSz = ED25519_PUB_KEY_SIZE; + sigSz = 1; + ExpectIntEQ(wolfSSL_ED25519_verify((byte*)msg, msglen, pub, pubSz, sig, + sigSz), 0); + sigSz = ED25519_SIG_SIZE; + + /* Good case of verification. */ + ExpectIntEQ(wolfSSL_ED25519_verify((byte*)msg, msglen, pub, pubSz, sig, + sigSz), 1); + /* Bad signature. */ + if (EXPECT_SUCCESS()) { + sig[1] ^= 0x80; + } + ExpectIntEQ(wolfSSL_ED25519_verify((byte*)msg, msglen, pub, pubSz, sig, + sigSz), 0); #endif /* HAVE_ED25519_VERIFY */ #endif /* HAVE_ED25519_SIGN && HAVE_ED25519_KEY_IMPORT */ #endif /* HAVE_ED25519 && HAVE_ED25519_KEY_EXPORT && WOLFSSL_KEY_GEN */ return EXPECT_RESULT(); } +static int test_EC448(void) +{ + EXPECT_DECLS; +#if defined(HAVE_CURVE448) && defined(WOLFSSL_KEY_GEN) + byte priv[CURVE448_KEY_SIZE]; + unsigned int privSz = CURVE448_KEY_SIZE; + byte pub[CURVE448_KEY_SIZE]; + unsigned int pubSz = CURVE448_KEY_SIZE; + byte priv2[CURVE448_KEY_SIZE]; + unsigned int priv2Sz = CURVE448_KEY_SIZE; + byte pub2[CURVE448_KEY_SIZE]; + unsigned int pub2Sz = CURVE448_KEY_SIZE; + byte shared[CURVE448_KEY_SIZE]; + unsigned int sharedSz = CURVE448_KEY_SIZE; + byte shared2[CURVE448_KEY_SIZE]; + unsigned int shared2Sz = CURVE448_KEY_SIZE; + + /* Bad parameter testing of key generation. */ + ExpectIntEQ(wolfSSL_EC448_generate_key(NULL, NULL, NULL, NULL), 0); + ExpectIntEQ(wolfSSL_EC448_generate_key(NULL, &privSz, NULL, &pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_generate_key(NULL, &privSz, pub, &pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_generate_key(priv, NULL, pub, &pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_generate_key(priv, &privSz, NULL, &pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_generate_key(priv, &privSz, pub, NULL), 0); + /* Bad length. */ + privSz = 1; + ExpectIntEQ(wolfSSL_EC448_generate_key(priv, &privSz, pub, &pubSz), 0); + privSz = CURVE448_KEY_SIZE; + pubSz = 1; + ExpectIntEQ(wolfSSL_EC448_generate_key(priv, &privSz, pub, &pubSz), 0); + pubSz = CURVE448_KEY_SIZE; + + /* Good case of generating key. */ + ExpectIntEQ(wolfSSL_EC448_generate_key(priv, &privSz, pub, &pubSz), 1); + ExpectIntEQ(wolfSSL_EC448_generate_key(priv2, &priv2Sz, pub2, &pub2Sz), 1); + ExpectIntEQ(privSz, CURVE448_KEY_SIZE); + ExpectIntEQ(pubSz, CURVE448_KEY_SIZE); + + /* Bad parameter testing of shared key. */ + ExpectIntEQ(wolfSSL_EC448_shared_key( NULL, NULL, NULL, privSz, + NULL, pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_shared_key( NULL, &sharedSz, NULL, privSz, + NULL, pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_shared_key( NULL, &sharedSz, priv, privSz, + pub, pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_shared_key(shared, &sharedSz, NULL, privSz, + pub, pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_shared_key(shared, &sharedSz, priv, privSz, + NULL, pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_shared_key( NULL, &sharedSz, priv, privSz, + pub, pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_shared_key(shared, NULL, priv, privSz, + pub, pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_shared_key(shared, &sharedSz, NULL, privSz, + pub, pubSz), 0); + ExpectIntEQ(wolfSSL_EC448_shared_key(shared, &sharedSz, priv, privSz, + NULL, pubSz), 0); + /* Bad length. */ + sharedSz = 1; + ExpectIntEQ(wolfSSL_EC448_shared_key(shared, &sharedSz, priv, privSz, + pub, pubSz), 0); + sharedSz = CURVE448_KEY_SIZE; + privSz = 1; + ExpectIntEQ(wolfSSL_EC448_shared_key(shared, &sharedSz, priv, privSz, + pub, pubSz), 0); + privSz = CURVE448_KEY_SIZE; + pubSz = 1; + ExpectIntEQ(wolfSSL_EC448_shared_key(shared, &sharedSz, priv, privSz, + pub, pubSz), 0); + pubSz = CURVE448_KEY_SIZE; + + /* Good case of shared key. */ + ExpectIntEQ(wolfSSL_EC448_shared_key(shared, &sharedSz, priv, privSz, + pub2, pub2Sz), 1); + ExpectIntEQ(wolfSSL_EC448_shared_key(shared2, &shared2Sz, priv2, priv2Sz, + pub, pubSz), 1); + ExpectIntEQ(sharedSz, CURVE448_KEY_SIZE); + ExpectIntEQ(shared2Sz, CURVE448_KEY_SIZE); + ExpectIntEQ(XMEMCMP(shared, shared2, sharedSz), 0); +#endif /* HAVE_CURVE448 && WOLFSSL_KEY_GEN */ + return EXPECT_RESULT(); +} + static int test_ED448(void) { EXPECT_DECLS; @@ -5055,19 +5309,99 @@ static int test_ED448(void) unsigned int sigSz = (unsigned int)sizeof(sig); #endif /* HAVE_ED448_SIGN && HAVE_ED448_KEY_IMPORT */ - ExpectIntEQ(wolfSSL_ED448_generate_key(priv, &privSz, pub, &pubSz), - WOLFSSL_SUCCESS); + /* Bad parameter testing of key generation. */ + ExpectIntEQ(wolfSSL_ED448_generate_key(NULL, NULL, NULL, NULL), 0); + ExpectIntEQ(wolfSSL_ED448_generate_key(priv, NULL, NULL, NULL), 0); + ExpectIntEQ(wolfSSL_ED448_generate_key(NULL, &privSz, NULL, NULL), 0); + ExpectIntEQ(wolfSSL_ED448_generate_key(NULL, NULL, pub, NULL), 0); + ExpectIntEQ(wolfSSL_ED448_generate_key(NULL, NULL, NULL, &pubSz), 0); + ExpectIntEQ(wolfSSL_ED448_generate_key(NULL, &privSz, pub, &pubSz), 0); + ExpectIntEQ(wolfSSL_ED448_generate_key(priv, NULL, pub, &pubSz), 0); + ExpectIntEQ(wolfSSL_ED448_generate_key(priv, &privSz, NULL, &pubSz), 0); + ExpectIntEQ(wolfSSL_ED448_generate_key(priv, &privSz, pub, NULL), 0); + /* Bad length. */ + privSz = 1; + ExpectIntEQ(wolfSSL_ED448_generate_key(priv, &privSz, pub, &pubSz), 0); + privSz = ED448_PRV_KEY_SIZE; + pubSz = 1; + ExpectIntEQ(wolfSSL_ED448_generate_key(priv, &privSz, pub, &pubSz), 0); + pubSz = ED448_PUB_KEY_SIZE; + + /* Good case of generating key. */ + ExpectIntEQ(wolfSSL_ED448_generate_key(priv, &privSz, pub, &pubSz), 1); ExpectIntEQ(privSz, ED448_PRV_KEY_SIZE); ExpectIntEQ(pubSz, ED448_PUB_KEY_SIZE); #if defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_KEY_IMPORT) + /* Bad parameter testing of signing. */ + ExpectIntEQ(wolfSSL_ED448_sign( NULL, msglen, NULL, privSz, NULL, + NULL), 0); + ExpectIntEQ(wolfSSL_ED448_sign((byte*)msg, msglen, NULL, privSz, NULL, + NULL), 0); + ExpectIntEQ(wolfSSL_ED448_sign( NULL, msglen, priv, privSz, NULL, + NULL), 0); + ExpectIntEQ(wolfSSL_ED448_sign( NULL, msglen, NULL, privSz, sig, + NULL), 0); + ExpectIntEQ(wolfSSL_ED448_sign( NULL, msglen, NULL, privSz, NULL, + &sigSz), 0); + ExpectIntEQ(wolfSSL_ED448_sign( NULL, msglen, priv, privSz, sig, + &sigSz), 0); + ExpectIntEQ(wolfSSL_ED448_sign((byte*)msg, msglen, NULL, privSz, sig, + &sigSz), 0); + ExpectIntEQ(wolfSSL_ED448_sign((byte*)msg, msglen, priv, privSz, NULL, + &sigSz), 0); + ExpectIntEQ(wolfSSL_ED448_sign((byte*)msg, msglen, priv, privSz, sig, + NULL), 0); + /* Bad length. */ + privSz = 1; ExpectIntEQ(wolfSSL_ED448_sign((byte*)msg, msglen, priv, privSz, sig, - &sigSz), WOLFSSL_SUCCESS); + &sigSz), 0); + privSz = ED448_PRV_KEY_SIZE; + sigSz = 1; + ExpectIntEQ(wolfSSL_ED448_sign((byte*)msg, msglen, priv, privSz, sig, + &sigSz), 0); + sigSz = ED448_SIG_SIZE; + + /* Good case of signing. */ + ExpectIntEQ(wolfSSL_ED448_sign((byte*)msg, msglen, priv, privSz, sig, + &sigSz), 1); ExpectIntEQ(sigSz, ED448_SIG_SIZE); #ifdef HAVE_ED448_VERIFY + /* Bad parameter testing of verification. */ + ExpectIntEQ(wolfSSL_ED448_verify( NULL, msglen, NULL, pubSz, NULL, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED448_verify((byte*)msg, msglen, NULL, pubSz, NULL, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED448_verify( NULL, msglen, pub, pubSz, NULL, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED448_verify( NULL, msglen, NULL, pubSz, sig, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED448_verify( NULL, msglen, pub, pubSz, sig, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED448_verify((byte*)msg, msglen, NULL, pubSz, sig, + sigSz), 0); + ExpectIntEQ(wolfSSL_ED448_verify((byte*)msg, msglen, pub, pubSz, NULL, + sigSz), 0); + /* Bad length. */ + pubSz = 1; ExpectIntEQ(wolfSSL_ED448_verify((byte*)msg, msglen, pub, pubSz, sig, - sigSz), WOLFSSL_SUCCESS); + sigSz), 0); + pubSz = ED448_PUB_KEY_SIZE; + sigSz = 1; + ExpectIntEQ(wolfSSL_ED448_verify((byte*)msg, msglen, pub, pubSz, sig, + sigSz), 0); + sigSz = ED448_SIG_SIZE; + + /* Good case of verification. */ + ExpectIntEQ(wolfSSL_ED448_verify((byte*)msg, msglen, pub, pubSz, sig, + sigSz), 1); + /* Bad signature. */ + if (EXPECT_SUCCESS()) { + sig[1] ^= 0x80; + } + ExpectIntEQ(wolfSSL_ED448_verify((byte*)msg, msglen, pub, pubSz, sig, + sigSz), 0); #endif /* HAVE_ED448_VERIFY */ #endif /* HAVE_ED448_SIGN && HAVE_ED448_KEY_IMPORT */ #endif /* HAVE_ED448 && HAVE_ED448_KEY_EXPORT && WOLFSSL_KEY_GEN */ @@ -27097,7 +27431,7 @@ static int test_wc_PKCS7_EncodeSignedData(void) /* reinitialize and test setting stream mode */ { - int signedSz; + int signedSz = 0; encodeSignedDataStream strm; ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); @@ -34345,29 +34679,79 @@ static int test_wolfSSL_private_keys(void) return EXPECT_RESULT(); } +static int test_wolfSSL_PEM_def_callback(void) +{ + EXPECT_DECLS; +#ifdef OPENSSL_EXTRA + char buf[10]; + const char* defpwd = "DEF PWD"; + int defpwdLen = (int)XSTRLEN(defpwd); + int smallLen = 1; + + /* Bad parameters. */ + ExpectIntEQ(wolfSSL_PEM_def_callback(NULL, sizeof(buf), 0, NULL), 0); + ExpectIntEQ(wolfSSL_PEM_def_callback(NULL, sizeof(buf), 0, (void*)defpwd), + 0); + ExpectIntEQ(wolfSSL_PEM_def_callback(buf, sizeof(buf), 0, NULL), 0); + + XMEMSET(buf, 0, sizeof(buf)); + ExpectIntEQ(wolfSSL_PEM_def_callback(buf, sizeof(buf), 0, (void*)defpwd), + defpwdLen); + ExpectIntEQ(XMEMCMP(buf, defpwd, defpwdLen), 0); + ExpectIntEQ(buf[defpwdLen], 0); + /* Size of buffer is smaller than default password. */ + XMEMSET(buf, 0, sizeof(buf)); + ExpectIntEQ(wolfSSL_PEM_def_callback(buf, smallLen, 0, (void*)defpwd), + smallLen); + ExpectIntEQ(XMEMCMP(buf, defpwd, smallLen), 0); + ExpectIntEQ(buf[smallLen], 0); +#endif /* OPENSSL_EXTRA */ + return EXPECT_RESULT(); +} + static int test_wolfSSL_PEM_read_PrivateKey(void) { EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) \ - && !defined(NO_FILESYSTEM) +#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && (!defined(NO_RSA) || \ + !defined(NO_DSA) || defined(HAVE_ECC) || !defined(NO_DH)) XFILE file = XBADFILE; - const char* fname = "./certs/server-key.pem"; - EVP_PKEY* pkey = NULL; +#if !defined(NO_RSA) + const char* fname_rsa = "./certs/server-key.pem"; RSA* rsa = NULL; WOLFSSL_EVP_PKEY_CTX* ctx = NULL; unsigned char* sig = NULL; size_t sigLen = 0; const unsigned char tbs[] = {0, 1, 2, 3, 4, 5, 6, 7}; size_t tbsLen = sizeof(tbs); +#endif +#if !defined(NO_DSA) + const char* fname_dsa = "./certs/dsa2048.pem"; +#endif +#if defined(HAVE_ECC) + const char* fname_ec = "./certs/ecc-key.pem"; +#endif +#if !defined(NO_DH) + const char* fname_dh = "./certs/dh-priv-2048.pem"; +#endif + EVP_PKEY* pkey = NULL; /* Check error case. */ ExpectNull(pkey = PEM_read_PrivateKey(NULL, NULL, NULL, NULL)); + /* not a PEM key. */ + ExpectTrue((file = XFOPEN("./certs/ecc-key.der", "rb")) != XBADFILE); + ExpectNull(PEM_read_PrivateKey(file, NULL, NULL, NULL)); + if (file != XBADFILE) + XFCLOSE(file); + file = XBADFILE; + +#ifndef NO_RSA /* Read in an RSA key. */ - ExpectTrue((file = XFOPEN(fname, "rb")) != XBADFILE); + ExpectTrue((file = XFOPEN(fname_rsa, "rb")) != XBADFILE); ExpectNotNull(pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL)); if (file != XBADFILE) XFCLOSE(file); + file = XBADFILE; /* Make sure the key is usable by signing some data with it. */ ExpectNotNull(rsa = EVP_PKEY_get0_RSA(pkey)); @@ -34382,6 +34766,52 @@ static int test_wolfSSL_PEM_read_PrivateKey(void) XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); + pkey = NULL; +#endif + +#ifndef NO_DSA + /* Read in a DSA key. */ + ExpectTrue((file = XFOPEN(fname_dsa, "rb")) != XBADFILE); +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) + ExpectNotNull(pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL)); + EVP_PKEY_free(pkey); + pkey = NULL; +#else + ExpectNull(PEM_read_PrivateKey(file, NULL, NULL, NULL)); +#endif + if (file != XBADFILE) + XFCLOSE(file); + file = XBADFILE; +#endif + +#ifdef HAVE_ECC + /* Read in an EC key. */ + ExpectTrue((file = XFOPEN(fname_ec, "rb")) != XBADFILE); + ExpectNotNull(pkey = EVP_PKEY_new()); + ExpectPtrEq(PEM_read_PrivateKey(file, &pkey, NULL, NULL), pkey); + if (file != XBADFILE) + XFCLOSE(file); + file = XBADFILE; + EVP_PKEY_free(pkey); + pkey = NULL; +#endif + +#ifndef NO_DH + /* Read in a DH key. */ + ExpectTrue((file = XFOPEN(fname_dh, "rb")) != XBADFILE); +#if (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || \ + defined(WOLFSSL_OPENSSH)) && (!defined(HAVE_FIPS) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) + ExpectNotNull(pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL)); + EVP_PKEY_free(pkey); + pkey = NULL; +#else + ExpectNull(PEM_read_PrivateKey(file, NULL, NULL, NULL)); +#endif + if (file != XBADFILE) + XFCLOSE(file); + file = XBADFILE; +#endif #endif return EXPECT_RESULT(); } @@ -34402,8 +34832,399 @@ static int test_wolfSSL_PEM_read_PUBKEY(void) ExpectTrue((file = XFOPEN(fname, "rb")) != XBADFILE); ExpectNotNull(pkey = PEM_read_PUBKEY(file, NULL, NULL, NULL)); EVP_PKEY_free(pkey); + pkey = NULL; if (file != XBADFILE) XFCLOSE(file); + file = XBADFILE; + ExpectTrue((file = XFOPEN(fname, "rb")) != XBADFILE); + ExpectNotNull(pkey = EVP_PKEY_new()); + ExpectPtrEq(PEM_read_PUBKEY(file, &pkey, NULL, NULL), pkey); + EVP_PKEY_free(pkey); + if (file != XBADFILE) + XFCLOSE(file); +#endif + return EXPECT_RESULT(); +} + +/* test loading RSA key using BIO */ +static int test_wolfSSL_PEM_PrivateKey_rsa(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_RSA) && \ + defined(USE_CERT_BUFFERS_2048) && !defined(NO_FILESYSTEM) && \ + !defined(NO_BIO) + BIO* bio = NULL; + XFILE file = XBADFILE; + const char* fname = "./certs/server-key.pem"; + const char* fname_rsa_p8 = "./certs/server-keyPkcs8.pem"; + EVP_PKEY* pkey = NULL; + size_t sz = 0; + byte* buf = NULL; + EVP_PKEY* pkey2 = NULL; + EVP_PKEY* pkey3 = NULL; + RSA* rsa_key = NULL; +#if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) + unsigned char extra[10]; + int i; + BIO* pub_bio = NULL; + const unsigned char* server_key = (const unsigned char*)server_key_der_2048; +#endif + + ExpectTrue((file = XFOPEN(fname, "rb")) != XBADFILE); + ExpectTrue(XFSEEK(file, 0, XSEEK_END) == 0); + ExpectIntGT(sz = XFTELL(file), 0); + ExpectTrue(XFSEEK(file, 0, XSEEK_SET) == 0); + ExpectNotNull(buf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)); + if (buf != NULL) { + ExpectIntEQ(XFREAD(buf, 1, sz, file), sz); + } + if (file != XBADFILE) { + XFCLOSE(file); + file = XBADFILE; + } + + /* Test using BIO new mem and loading PEM private key */ + ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz)); + ExpectNotNull((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); + XFREE(buf, NULL, DYNAMIC_TYPE_FILE); + buf = NULL; + BIO_free(bio); + bio = NULL; + + /* New empty EVP_PKEY */ + ExpectNotNull(pkey2 = EVP_PKEY_new()); + if (pkey2 != NULL) { + pkey2->type = EVP_PKEY_RSA; + } + /* Test parameter copy */ + ExpectIntEQ(EVP_PKEY_copy_parameters(pkey2, pkey), 0); + EVP_PKEY_free(pkey2); + EVP_PKEY_free(pkey); + pkey = NULL; + + /* Qt unit test case : rsa pkcs8 key */ + ExpectTrue((file = XFOPEN(fname_rsa_p8, "rb")) != XBADFILE); + ExpectTrue(XFSEEK(file, 0, XSEEK_END) == 0); + ExpectIntGT(sz = XFTELL(file), 0); + ExpectTrue(XFSEEK(file, 0, XSEEK_SET) == 0); + ExpectNotNull(buf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)); + if (buf) { + ExpectIntEQ(XFREAD(buf, 1, sz, file), sz); + } + if (file != XBADFILE) { + XFCLOSE(file); + file = XBADFILE; + } + + ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz)); + ExpectNotNull((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); + XFREE(buf, NULL, DYNAMIC_TYPE_FILE); + buf = NULL; + BIO_free(bio); + bio = NULL; + ExpectNotNull(pkey3 = EVP_PKEY_new()); + + ExpectNotNull(rsa_key = EVP_PKEY_get1_RSA(pkey)); + ExpectIntEQ(EVP_PKEY_set1_RSA(pkey3, rsa_key), WOLFSSL_SUCCESS); + +#ifdef WOLFSSL_ERROR_CODE_OPENSSL + ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 1/* match */); +#else + ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 0); +#endif + + RSA_free(rsa_key); + EVP_PKEY_free(pkey3); + EVP_PKEY_free(pkey); + pkey = NULL; + pkey2 = NULL; + +#if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) + #define BIO_PEM_TEST_CHAR 'a' + XMEMSET(extra, BIO_PEM_TEST_CHAR, sizeof(extra)); + + ExpectNotNull(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())); + ExpectIntEQ(BIO_set_write_buf_size(bio, 4096), SSL_FAILURE); + ExpectNotNull(pub_bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())); + ExpectIntEQ(BIO_set_write_buf_size(pub_bio, 4096), SSL_FAILURE); + + ExpectNull(d2i_PrivateKey(EVP_PKEY_EC, &pkey, &server_key, + (long)sizeof_server_key_der_2048)); + ExpectNull(pkey); + + ExpectNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, &server_key, + (long)sizeof_server_key_der_2048)); + ExpectIntEQ(PEM_write_bio_PrivateKey(NULL, pkey, NULL, NULL, 0, NULL, NULL), + WOLFSSL_FAILURE); + ExpectIntEQ(PEM_write_bio_PrivateKey(bio, NULL, NULL, NULL, 0, NULL, NULL), + WOLFSSL_FAILURE); + ExpectIntEQ(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), + WOLFSSL_SUCCESS); + ExpectIntGT(BIO_pending(bio), 0); + ExpectIntEQ(BIO_pending(bio), 1679); + /* Check if the pubkey API writes only the public key */ +#ifdef WOLFSSL_KEY_GEN + ExpectIntEQ(PEM_write_bio_PUBKEY(NULL, pkey), WOLFSSL_FAILURE); + ExpectIntEQ(PEM_write_bio_PUBKEY(pub_bio, NULL), WOLFSSL_FAILURE); + ExpectIntEQ(PEM_write_bio_PUBKEY(pub_bio, pkey), WOLFSSL_SUCCESS); + ExpectIntGT(BIO_pending(pub_bio), 0); + /* Previously both the private key and the pubkey calls would write + * out the private key and the PEM header was the only difference. + * The public PEM should be significantly shorter than the + * private key versison. */ + ExpectIntEQ(BIO_pending(pub_bio), 451); +#else + /* Not supported. */ + ExpectIntEQ(PEM_write_bio_PUBKEY(pub_bio, pkey), 0); +#endif + + /* test creating new EVP_PKEY with good args */ + ExpectNotNull((pkey2 = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); + if (pkey && pkey->pkey.ptr && pkey2 && pkey2->pkey.ptr) { + ExpectIntEQ((int)XMEMCMP(pkey->pkey.ptr, pkey2->pkey.ptr, + pkey->pkey_sz), 0); + } + + /* test of reuse of EVP_PKEY */ + ExpectNull(PEM_read_bio_PrivateKey(bio, &pkey, NULL, NULL)); + ExpectIntEQ(BIO_pending(bio), 0); + ExpectIntEQ(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), + SSL_SUCCESS); + /* add 10 extra bytes after PEM */ + ExpectIntEQ(BIO_write(bio, extra, 10), 10); + ExpectNotNull(PEM_read_bio_PrivateKey(bio, &pkey, NULL, NULL)); + ExpectNotNull(pkey); + if (pkey && pkey->pkey.ptr && pkey2 && pkey2->pkey.ptr) { + ExpectIntEQ((int)XMEMCMP(pkey->pkey.ptr, pkey2->pkey.ptr, + pkey->pkey_sz), 0); + } + /* check 10 extra bytes still there */ + ExpectIntEQ(BIO_pending(bio), 10); + ExpectIntEQ(BIO_read(bio, extra, 10), 10); + for (i = 0; i < 10; i++) { + ExpectIntEQ(extra[i], BIO_PEM_TEST_CHAR); + } + + BIO_free(pub_bio); + BIO_free(bio); + bio = NULL; + EVP_PKEY_free(pkey); + pkey = NULL; + EVP_PKEY_free(pkey2); +#endif /* WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN */ +#endif /* OPENSSL_EXTRA && !NO_CERTS && !NO_RSA && USE_CERT_BUFFERS_2048 && + * !NO_FILESYSTEM && !NO_BIO */ + return EXPECT_RESULT(); +} + +/* test loading ECC key using BIO */ +static int test_wolfSSL_PEM_PrivateKey_ecc(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && defined(HAVE_ECC) && \ + !defined(NO_FILESYSTEM) && !defined(NO_BIO) + BIO* bio = NULL; + EVP_PKEY* pkey = NULL; + XFILE file = XBADFILE; + const char* fname = "./certs/ecc-key.pem"; + const char* fname_ecc_p8 = "./certs/ecc-keyPkcs8.pem"; + + size_t sz = 0; + byte* buf = NULL; + EVP_PKEY* pkey2 = NULL; + EVP_PKEY* pkey3 = NULL; + EC_KEY* ec_key = NULL; + int nid = 0; + BIO* pub_bio = NULL; + + ExpectTrue((file = XFOPEN(fname, "rb")) != XBADFILE); + ExpectTrue(XFSEEK(file, 0, XSEEK_END) == 0); + ExpectIntGT(sz = XFTELL(file), 0); + ExpectTrue(XFSEEK(file, 0, XSEEK_SET) == 0); + ExpectNotNull(buf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)); + if (buf) { + ExpectIntEQ(XFREAD(buf, 1, sz, file), sz); + } + if (file != XBADFILE) { + XFCLOSE(file); + file = XBADFILE; + } + + /* Test using BIO new mem and loading PEM private key */ + ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz)); + ExpectNotNull((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); + BIO_free(bio); + bio = NULL; + XFREE(buf, NULL, DYNAMIC_TYPE_FILE); + buf = NULL; + ExpectNotNull(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())); + ExpectNotNull(pub_bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())); + ExpectIntEQ(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), + WOLFSSL_SUCCESS); + ExpectIntGT(BIO_pending(bio), 0); + /* No parmeters. */ + ExpectIntEQ(BIO_pending(bio), 227); + /* Check if the pubkey API writes only the public key */ +#ifdef WOLFSSL_KEY_GEN + ExpectIntEQ(PEM_write_bio_PUBKEY(pub_bio, pkey), WOLFSSL_SUCCESS); + ExpectIntGT(BIO_pending(pub_bio), 0); + /* Previously both the private key and the pubkey calls would write + * out the private key and the PEM header was the only difference. + * The public PEM should be significantly shorter than the + * private key versison. */ + ExpectIntEQ(BIO_pending(pub_bio), 178); +#endif + BIO_free(pub_bio); + BIO_free(bio); + bio = NULL; + ExpectNotNull(pkey2 = EVP_PKEY_new()); + ExpectNotNull(pkey3 = EVP_PKEY_new()); + if (pkey2 != NULL) { + pkey2->type = EVP_PKEY_EC; + } + /* Test parameter copy */ + ExpectIntEQ(EVP_PKEY_copy_parameters(pkey2, pkey), 1); + + + /* Qt unit test case 1*/ + ExpectNotNull(ec_key = EVP_PKEY_get1_EC_KEY(pkey)); + ExpectIntEQ(EVP_PKEY_set1_EC_KEY(pkey3, ec_key), WOLFSSL_SUCCESS); + #ifdef WOLFSSL_ERROR_CODE_OPENSSL + ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 1/* match */); + #else + ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 0); + #endif + /* Test default digest */ + ExpectIntEQ(EVP_PKEY_get_default_digest_nid(pkey, &nid), 1); + ExpectIntEQ(nid, NID_sha256); + EC_KEY_free(ec_key); + ec_key = NULL; + EVP_PKEY_free(pkey3); + pkey3 = NULL; + EVP_PKEY_free(pkey2); + pkey2 = NULL; + EVP_PKEY_free(pkey); + pkey = NULL; + + /* Qt unit test case ec pkcs8 key */ + ExpectTrue((file = XFOPEN(fname_ecc_p8, "rb")) != XBADFILE); + ExpectTrue(XFSEEK(file, 0, XSEEK_END) == 0); + ExpectIntGT(sz = XFTELL(file), 0); + ExpectTrue(XFSEEK(file, 0, XSEEK_SET) == 0); + ExpectNotNull(buf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)); + if (buf) { + ExpectIntEQ(XFREAD(buf, 1, sz, file), sz); + } + if (file != XBADFILE) { + XFCLOSE(file); + file = XBADFILE; + } + + ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz)); + ExpectNotNull((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); + XFREE(buf, NULL, DYNAMIC_TYPE_FILE); + buf = NULL; + BIO_free(bio); + bio = NULL; + ExpectNotNull(pkey3 = EVP_PKEY_new()); + /* Qt unit test case */ + ExpectNotNull(ec_key = EVP_PKEY_get1_EC_KEY(pkey)); + ExpectIntEQ(EVP_PKEY_set1_EC_KEY(pkey3, ec_key), WOLFSSL_SUCCESS); +#ifdef WOLFSSL_ERROR_CODE_OPENSSL + ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 1/* match */); +#else + ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 0); +#endif + EC_KEY_free(ec_key); + EVP_PKEY_free(pkey3); + EVP_PKEY_free(pkey); + pkey = NULL; +#endif + return EXPECT_RESULT(); +} + +/* test loading DSA key using BIO */ +static int test_wolfSSL_PEM_PrivateKey_dsa(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_DSA) && \ + !defined(NO_FILESYSTEM) && !defined(NO_BIO) +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + BIO* bio = NULL; + EVP_PKEY* pkey = NULL; + + ExpectNotNull(bio = BIO_new_file("./certs/dsa2048.pem", "rb")); + /* Private DSA EVP_PKEY */ + ExpectNotNull(pkey = wolfSSL_PEM_read_bio_PrivateKey(bio, NULL, NULL, + NULL)); + BIO_free(bio); + bio = NULL; + + ExpectNotNull(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())); +#if defined(OPENSSL_ALL) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) + ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, NULL, NULL, 0, NULL, + NULL), 0); +#endif + +#ifdef WOLFSSL_KEY_GEN + ExpectIntEQ(PEM_write_bio_PUBKEY(bio, pkey), 1); + ExpectIntEQ(BIO_pending(bio), 1178); + BIO_reset(bio); +#endif + + ExpectIntEQ(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), + 1); + ExpectIntEQ(BIO_pending(bio), 1196); + + BIO_free(bio); + bio = NULL; + + EVP_PKEY_free(pkey); + pkey = NULL; +#endif +#endif + return EXPECT_RESULT(); +} + +/* test loading DH key using BIO */ +static int test_wolfSSL_PEM_PrivateKey_dh(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_DH) && \ + !defined(NO_FILESYSTEM) && !defined(NO_BIO) +#if (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || \ + defined(WOLFSSL_OPENSSH)) && (!defined(HAVE_FIPS) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) + BIO* bio = NULL; + EVP_PKEY* pkey = NULL; + + ExpectNotNull(bio = BIO_new_file("./certs/dh-priv-2048.pem", "rb")); + /* Private DH EVP_PKEY */ + ExpectNotNull(pkey = wolfSSL_PEM_read_bio_PrivateKey(bio, NULL, NULL, + NULL)); + BIO_free(bio); + bio = NULL; + + ExpectNotNull(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())); + +#if defined(OPENSSL_ALL) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) + ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, NULL, NULL, 0, NULL, + NULL), 0); +#endif +#ifdef WOLFSSL_KEY_GEN + ExpectIntEQ(PEM_write_bio_PUBKEY(bio, pkey), 0); +#endif + + ExpectIntEQ(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), + 1); + ExpectIntEQ(BIO_pending(bio), 806); + + BIO_free(bio); + bio = NULL; + + EVP_PKEY_free(pkey); + pkey = NULL; +#endif #endif return EXPECT_RESULT(); } @@ -34424,259 +35245,28 @@ static int test_wolfSSL_PEM_PrivateKey(void) /* test creating new EVP_PKEY with bad arg */ ExpectNull((pkey = PEM_read_bio_PrivateKey(NULL, NULL, NULL, NULL))); - /* test loading RSA key using BIO */ -#if !defined(NO_RSA) && !defined(NO_FILESYSTEM) - { - XFILE file = XBADFILE; - const char* fname = "./certs/server-key.pem"; - const char* fname_rsa_p8 = "./certs/server-keyPkcs8.pem"; - - size_t sz = 0; - byte* buf = NULL; - EVP_PKEY* pkey2 = NULL; - EVP_PKEY* pkey3 = NULL; - RSA* rsa_key = NULL; - - ExpectTrue((file = XFOPEN(fname, "rb")) != XBADFILE); - ExpectTrue(XFSEEK(file, 0, XSEEK_END) == 0); - ExpectIntGT(sz = XFTELL(file), 0); - ExpectTrue(XFSEEK(file, 0, XSEEK_SET) == 0); - ExpectNotNull(buf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)); - if (buf != NULL) { - ExpectIntEQ(XFREAD(buf, 1, sz, file), sz); - } - if (file != XBADFILE) { - XFCLOSE(file); - file = XBADFILE; - } - - /* Test using BIO new mem and loading PEM private key */ - ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz)); - ExpectNotNull((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); - XFREE(buf, NULL, DYNAMIC_TYPE_FILE); - buf = NULL; - BIO_free(bio); - bio = NULL; - ExpectNotNull(pkey2 = EVP_PKEY_new()); - if (pkey2 != NULL) { - pkey2->type = EVP_PKEY_RSA; - } - /* Test parameter copy */ - ExpectIntEQ(EVP_PKEY_copy_parameters(pkey2, pkey), 0); - EVP_PKEY_free(pkey2); - EVP_PKEY_free(pkey); - pkey = NULL; - - /* Qt unit test case : rsa pkcs8 key */ - ExpectTrue((file = XFOPEN(fname_rsa_p8, "rb")) != XBADFILE); - ExpectTrue(XFSEEK(file, 0, XSEEK_END) == 0); - ExpectIntGT(sz = XFTELL(file), 0); - ExpectTrue(XFSEEK(file, 0, XSEEK_SET) == 0); - ExpectNotNull(buf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)); - if (buf) { - ExpectIntEQ(XFREAD(buf, 1, sz, file), sz); - } - if (file != XBADFILE) { - XFCLOSE(file); - file = XBADFILE; - } - - ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz)); - ExpectNotNull((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); - XFREE(buf, NULL, DYNAMIC_TYPE_FILE); - buf = NULL; - BIO_free(bio); - bio = NULL; - ExpectNotNull(pkey3 = EVP_PKEY_new()); - - ExpectNotNull(rsa_key = EVP_PKEY_get1_RSA(pkey)); - ExpectIntEQ(EVP_PKEY_set1_RSA(pkey3, rsa_key), WOLFSSL_SUCCESS); - - #ifdef WOLFSSL_ERROR_CODE_OPENSSL - ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 1/* match */); - #else - ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 0); - #endif - - RSA_free(rsa_key); - EVP_PKEY_free(pkey3); - EVP_PKEY_free(pkey); - pkey = NULL; + /* Test bad EVP_PKEY type. */ + /* New HMAC EVP_PKEY */ + ExpectNotNull(bio = BIO_new_mem_buf("", 1)); + ExpectNotNull(pkey = EVP_PKEY_new()); + if (pkey != NULL) { + pkey->type = EVP_PKEY_HMAC; } + ExpectIntEQ(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), + 0); +#if defined(OPENSSL_ALL) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) + ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, NULL, NULL, 0, NULL, + NULL), 0); #endif - - /* test loading ECC key using BIO */ -#if defined(HAVE_ECC) && !defined(NO_FILESYSTEM) - { - XFILE file = XBADFILE; - const char* fname = "./certs/ecc-key.pem"; - const char* fname_ecc_p8 = "./certs/ecc-keyPkcs8.pem"; - - size_t sz = 0; - byte* buf = NULL; - EVP_PKEY* pkey2 = NULL; - EVP_PKEY* pkey3 = NULL; - EC_KEY* ec_key = NULL; - int nid = 0; - - ExpectTrue((file = XFOPEN(fname, "rb")) != XBADFILE); - ExpectTrue(XFSEEK(file, 0, XSEEK_END) == 0); - ExpectIntGT(sz = XFTELL(file), 0); - ExpectTrue(XFSEEK(file, 0, XSEEK_SET) == 0); - ExpectNotNull(buf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)); - if (buf) { - ExpectIntEQ(XFREAD(buf, 1, sz, file), sz); - } - if (file != XBADFILE) { - XFCLOSE(file); - file = XBADFILE; - } - - /* Test using BIO new mem and loading PEM private key */ - ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz)); - ExpectNotNull((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); - XFREE(buf, NULL, DYNAMIC_TYPE_FILE); - buf = NULL; - BIO_free(bio); - bio = NULL; - ExpectNotNull(pkey2 = EVP_PKEY_new()); - ExpectNotNull(pkey3 = EVP_PKEY_new()); - if (pkey2 != NULL) { - pkey2->type = EVP_PKEY_EC; - } - /* Test parameter copy */ - ExpectIntEQ(EVP_PKEY_copy_parameters(pkey2, pkey), 1); - /* Qt unit test case 1*/ - ExpectNotNull(ec_key = EVP_PKEY_get1_EC_KEY(pkey)); - ExpectIntEQ(EVP_PKEY_set1_EC_KEY(pkey3, ec_key), WOLFSSL_SUCCESS); - #ifdef WOLFSSL_ERROR_CODE_OPENSSL - ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 1/* match */); - #else - ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 0); - #endif - /* Test default digest */ - ExpectIntEQ(EVP_PKEY_get_default_digest_nid(pkey, &nid), 1); - ExpectIntEQ(nid, NID_sha256); - EC_KEY_free(ec_key); - ec_key = NULL; - EVP_PKEY_free(pkey3); - pkey3 = NULL; - EVP_PKEY_free(pkey2); - pkey2 = NULL; - EVP_PKEY_free(pkey); - pkey = NULL; - - /* Qt unit test case ec pkcs8 key */ - ExpectTrue((file = XFOPEN(fname_ecc_p8, "rb")) != XBADFILE); - ExpectTrue(XFSEEK(file, 0, XSEEK_END) == 0); - ExpectIntGT(sz = XFTELL(file), 0); - ExpectTrue(XFSEEK(file, 0, XSEEK_SET) == 0); - ExpectNotNull(buf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)); - if (buf) { - ExpectIntEQ(XFREAD(buf, 1, sz, file), sz); - } - if (file != XBADFILE) { - XFCLOSE(file); - file = XBADFILE; - } - - ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz)); - ExpectNotNull((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); - XFREE(buf, NULL, DYNAMIC_TYPE_FILE); - buf = NULL; - BIO_free(bio); - bio = NULL; - ExpectNotNull(pkey3 = EVP_PKEY_new()); - /* Qt unit test case */ - ExpectNotNull(ec_key = EVP_PKEY_get1_EC_KEY(pkey)); - ExpectIntEQ(EVP_PKEY_set1_EC_KEY(pkey3, ec_key), WOLFSSL_SUCCESS); - #ifdef WOLFSSL_ERROR_CODE_OPENSSL - ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 1/* match */); - #else - ExpectIntEQ(EVP_PKEY_cmp(pkey, pkey3), 0); - #endif - EC_KEY_free(ec_key); - EVP_PKEY_free(pkey3); - EVP_PKEY_free(pkey); - pkey = NULL; - } -#endif - -#if !defined(NO_BIO) && !defined(NO_RSA) && (defined(WOLFSSL_KEY_GEN) || \ - defined(WOLFSSL_CERT_GEN)) - { - #define BIO_PEM_TEST_CHAR 'a' - EVP_PKEY* pkey2 = NULL; - unsigned char extra[10]; - int i; - BIO* pub_bio = NULL; - - XMEMSET(extra, BIO_PEM_TEST_CHAR, sizeof(extra)); - - ExpectNotNull(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())); - ExpectIntEQ(BIO_set_write_buf_size(bio, 4096), SSL_FAILURE); - ExpectNotNull(pub_bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())); - ExpectIntEQ(BIO_set_write_buf_size(pub_bio, 4096), SSL_FAILURE); - - ExpectNull(d2i_PrivateKey(EVP_PKEY_EC, &pkey, - &server_key, (long)sizeof_server_key_der_2048)); - ExpectNull(pkey); - - ExpectNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, - &server_key, (long)sizeof_server_key_der_2048)); - ExpectIntEQ(PEM_write_bio_PrivateKey(NULL, pkey, NULL, NULL, 0, NULL, - NULL), WOLFSSL_FAILURE); - ExpectIntEQ(PEM_write_bio_PrivateKey(bio, NULL, NULL, NULL, 0, NULL, - NULL), WOLFSSL_FAILURE); - ExpectIntEQ(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, - NULL), WOLFSSL_SUCCESS); - ExpectIntGT(BIO_pending(bio), 0); - ExpectIntEQ(BIO_pending(bio), 1679); - /* Check if the pubkey API writes only the public key */ #ifdef WOLFSSL_KEY_GEN - ExpectIntEQ(PEM_write_bio_PUBKEY(NULL, pkey), WOLFSSL_FAILURE); - ExpectIntEQ(PEM_write_bio_PUBKEY(pub_bio, NULL), WOLFSSL_FAILURE); - ExpectIntEQ(PEM_write_bio_PUBKEY(pub_bio, pkey), WOLFSSL_SUCCESS); - ExpectIntGT(BIO_pending(pub_bio), 0); - /* Previously both the private key and the pubkey calls would write - * out the private key and the PEM header was the only difference. - * The public PEM should be significantly shorter than the - * private key versison. */ - ExpectIntEQ(BIO_pending(pub_bio), 451); + ExpectIntEQ(PEM_write_bio_PUBKEY(bio, pkey), WOLFSSL_FAILURE); #endif + EVP_PKEY_free(pkey); + pkey = NULL; + BIO_free(bio); + bio = NULL; - /* test creating new EVP_PKEY with good args */ - ExpectNotNull((pkey2 = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); - if (pkey && pkey->pkey.ptr && pkey2 && pkey2->pkey.ptr) - ExpectIntEQ((int)XMEMCMP(pkey->pkey.ptr, pkey2->pkey.ptr, pkey->pkey_sz), 0); - - /* test of reuse of EVP_PKEY */ - ExpectNull(PEM_read_bio_PrivateKey(bio, &pkey, NULL, NULL)); - ExpectIntEQ(BIO_pending(bio), 0); - ExpectIntEQ(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), - SSL_SUCCESS); - ExpectIntEQ(BIO_write(bio, extra, 10), 10); /* add 10 extra bytes after PEM */ - ExpectNotNull(PEM_read_bio_PrivateKey(bio, &pkey, NULL, NULL)); - ExpectNotNull(pkey); - if (pkey && pkey->pkey.ptr && pkey2 && pkey2->pkey.ptr) { - ExpectIntEQ((int)XMEMCMP(pkey->pkey.ptr, pkey2->pkey.ptr, pkey->pkey_sz),0); - } - ExpectIntEQ(BIO_pending(bio), 10); /* check 10 extra bytes still there */ - ExpectIntEQ(BIO_read(bio, extra, 10), 10); - for (i = 0; i < 10; i++) { - ExpectIntEQ(extra[i], BIO_PEM_TEST_CHAR); - } - - BIO_free(pub_bio); - BIO_free(bio); - bio = NULL; - EVP_PKEY_free(pkey); - pkey = NULL; - EVP_PKEY_free(pkey2); - } - #endif - /* key is DES encrypted */ #if !defined(NO_DES3) && defined(WOLFSSL_ENCRYPTED_KEYS) && \ !defined(NO_RSA) && !defined(NO_BIO) && !defined(NO_FILESYSTEM) && \ @@ -35195,7 +35785,7 @@ static int test_wolfSSL_PEM_PUBKEY(void) { XFILE file = XBADFILE; const char* fname = "./certs/ecc-client-keyPub.pem"; - size_t sz; + size_t sz = 0; byte* buf = NULL; EVP_PKEY* pkey2 = NULL; @@ -35216,6 +35806,13 @@ static int test_wolfSSL_PEM_PUBKEY(void) /* Test using BIO new mem and loading PEM private key */ ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz)); ExpectNotNull((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL))); + BIO_free(bio); + bio = NULL; + EVP_PKEY_free(pkey); + pkey = NULL; + ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz)); + ExpectNotNull(pkey = EVP_PKEY_new()); + ExpectPtrEq(PEM_read_bio_PUBKEY(bio, &pkey, NULL, NULL), pkey); XFREE(buf, NULL, DYNAMIC_TYPE_FILE); BIO_free(bio); bio = NULL; @@ -35233,7 +35830,7 @@ static int test_wolfSSL_PEM_PUBKEY(void) EC_KEY_free(ec_key); EVP_PKEY_free(pkey2); EVP_PKEY_free(pkey); - pkey = NULL; + pkey = NULL; } #endif @@ -41491,6 +42088,18 @@ static int test_wolfSSL_PKCS8_Compat(void) return EXPECT_RESULT(); } +#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_BIO) +static int NoPasswordCallBack(char* passwd, int sz, int rw, void* userdata) +{ + (void)passwd; + (void)sz; + (void)rw; + (void)userdata; + + return -1; +} +#endif + static int test_wolfSSL_PKCS8_d2i(void) { EXPECT_DECLS; @@ -41573,6 +42182,13 @@ static int test_wolfSSL_PKCS8_d2i(void) #endif /* OPENSSL_ALL */ #ifndef NO_FILESYSTEM +#if defined(OPENSSL_ALL) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) + ExpectIntEQ(PEM_write_PKCS8PrivateKey(XBADFILE, pkey, NULL, NULL, 0, NULL, + NULL), 0); + ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, NULL, NULL, NULL, 0, NULL, + NULL), 0); +#endif + #ifndef NO_RSA /* Get DER encoded RSA PKCS#8 data. */ ExpectTrue((file = XFOPEN(rsaDerPkcs8File, "rb")) != XBADFILE); @@ -41603,20 +42219,33 @@ static int test_wolfSSL_PKCS8_d2i(void) #if defined(OPENSSL_ALL) && \ !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) ExpectNotNull(bio = BIO_new(BIO_s_mem())); + ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(NULL, pkey, NULL, NULL, 0, NULL, + NULL), 0); + ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, NULL, NULL, NULL, 0, NULL, + NULL), 0); /* Write PKCS#8 PEM to BIO. */ ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), bytes); + /* Write PKCS#8 PEM to stderr. */ + ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, NULL, NULL, 0, NULL, + NULL), bytes); /* Compare file and written data */ ExpectIntEQ(BIO_get_mem_data(bio, &p), bytes); ExpectIntEQ(XMEMCMP(p, pkcs8_buffer, bytes), 0); BIO_free(bio); bio = NULL; +#if !defined(NO_AES) && defined(HAVE_AESGCM) + ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_aes_128_gcm(), + NULL, 0, PasswordCallBack, (void*)"yassl123"), 0); +#endif #if !defined(NO_DES3) && !defined(NO_SHA) ExpectNotNull(bio = BIO_new(BIO_s_mem())); /* Write Encrypted PKCS#8 PEM to BIO. */ bytes = 1834; ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, EVP_des_ede3_cbc(), NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes); + ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_des_ede3_cbc(), + NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes); ExpectNotNull(evpPkey = PEM_read_bio_PrivateKey(bio, NULL, PasswordCallBack, (void*)"yassl123")); EVP_PKEY_free(evpPkey); @@ -41686,6 +42315,8 @@ static int test_wolfSSL_PKCS8_d2i(void) /* Write PKCS#8 PEM to BIO. */ ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), bytes); + ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, NULL, NULL, 0, NULL, + NULL), bytes); /* Compare file and written data */ ExpectIntEQ(BIO_get_mem_data(bio, &p), bytes); ExpectIntEQ(XMEMCMP(p, pkcs8_buffer, bytes), 0); @@ -41695,6 +42326,14 @@ static int test_wolfSSL_PKCS8_d2i(void) /* Write Encrypted PKCS#8 PEM to BIO. */ bytes = 379; ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, EVP_aes_256_cbc(), + NULL, 0, NoPasswordCallBack, (void*)"yassl123"), 0); + ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, EVP_aes_256_cbc(), + NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes); + ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_aes_128_cbc(), + NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes); + ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_aes_128_cbc(), + (char*)"yassl123", 8, PasswordCallBack, NULL), bytes); + ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_aes_256_cbc(), NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes); ExpectNotNull(evpPkey = PEM_read_bio_PrivateKey(bio, NULL, PasswordCallBack, (void*)"yassl123")); @@ -55949,6 +56588,25 @@ static int test_wolfSSL_PEM_read(void) size_t fileDataSz = 0; byte* out; + ExpectNotNull(bio = BIO_new_file(filename, "rb")); + ExpectIntEQ(PEM_read_bio(bio, NULL, &header, &data, &len), 0); + ExpectIntEQ(PEM_read_bio(bio, &name, NULL, &data, &len), 0); + ExpectIntEQ(PEM_read_bio(bio, &name, &header, NULL, &len), 0); + ExpectIntEQ(PEM_read_bio(bio, &name, &header, &data, NULL), 0); + + ExpectIntEQ(PEM_read_bio(bio, &name, &header, &data, &len), 1); + ExpectIntEQ(XSTRNCMP(name, "RSA PRIVATE KEY", 15), 0); + ExpectIntGT(XSTRLEN(header), 0); + ExpectIntGT(len, 0); + XFREE(name, NULL, DYNAMIC_TYPE_TMP_BUFFER); + name = NULL; + XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER); + header = NULL; + XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + data = NULL; + BIO_free(bio); + bio = NULL; + ExpectTrue((fp = XFOPEN(filename, "rb")) != XBADFILE); /* Fail cases. */ @@ -55986,6 +56644,26 @@ static int test_wolfSSL_PEM_read(void) ExpectIntEQ(wolfSSL_BIO_get_mem_data(bio, &out), fileDataSz); ExpectIntEQ(XMEMCMP(out, fileData, fileDataSz), 0); + /* Fail cases. */ + ExpectIntEQ(PEM_write(XBADFILE, name, header, data, len), 0); + ExpectIntEQ(PEM_write(stderr, NULL, header, data, len), 0); + ExpectIntEQ(PEM_write(stderr, name, NULL, data, len), 0); + ExpectIntEQ(PEM_write(stderr, name, header, NULL, len), 0); + /* Pass case */ + ExpectIntEQ(PEM_write(stderr, name, header, data, len), fileDataSz); + + XFREE(name, NULL, DYNAMIC_TYPE_TMP_BUFFER); + name = NULL; + XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER); + header = NULL; + XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + data = NULL; + /* Read out of a fixed buffer BIO - forces malloc in PEM_read_bio. */ + ExpectIntEQ(PEM_read_bio(bio, &name, &header, &data, &len), 1); + ExpectIntEQ(XSTRNCMP(name, "RSA PRIVATE KEY", 15), 0); + ExpectIntGT(XSTRLEN(header), 0); + ExpectIntGT(len, 0); + /* Fail cases. */ ExpectIntEQ(PEM_get_EVP_CIPHER_INFO(NULL, &cipher), WOLFSSL_FAILURE); ExpectIntEQ(PEM_get_EVP_CIPHER_INFO(header, NULL), WOLFSSL_FAILURE); @@ -55996,6 +56674,8 @@ static int test_wolfSSL_PEM_read(void) #endif /* Fail cases. */ + ExpectIntEQ(PEM_do_header(NULL, data, &len, PasswordCallBack, + (void*)"yassl123"), WOLFSSL_FAILURE); ExpectIntEQ(PEM_do_header(&cipher, NULL, &len, PasswordCallBack, (void*)"yassl123"), WOLFSSL_FAILURE); ExpectIntEQ(PEM_do_header(&cipher, data, NULL, PasswordCallBack, @@ -56003,9 +56683,14 @@ static int test_wolfSSL_PEM_read(void) ExpectIntEQ(PEM_do_header(&cipher, data, &len, NULL, (void*)"yassl123"), WOLFSSL_FAILURE); + ExpectIntEQ(PEM_do_header(&cipher, data, &len, NoPasswordCallBack, + (void*)"yassl123"), WOLFSSL_FAILURE); #if !defined(NO_DES3) && !defined(NO_MD5) ExpectIntEQ(PEM_do_header(&cipher, data, &len, PasswordCallBack, (void*)"yassl123"), WOLFSSL_SUCCESS); +#else + ExpectIntEQ(PEM_do_header(&cipher, data, &len, PasswordCallBack, + (void*)"yassl123"), WOLFSSL_FAILURE); #endif BIO_free(bio); @@ -66862,7 +67547,7 @@ static int test_extra_alerts_bad_psk(void) WOLFSSL_ERROR_WANT_READ); ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); - ExpectIntEQ( wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), WOLFSSL_ERROR_WANT_READ); ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); @@ -71326,9 +72011,14 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_certs), TEST_DECL(test_wolfSSL_private_keys), + TEST_DECL(test_wolfSSL_PEM_def_callback), TEST_DECL(test_wolfSSL_PEM_read_PrivateKey), TEST_DECL(test_wolfSSL_PEM_read_RSA_PUBKEY), TEST_DECL(test_wolfSSL_PEM_read_PUBKEY), + TEST_DECL(test_wolfSSL_PEM_PrivateKey_rsa), + TEST_DECL(test_wolfSSL_PEM_PrivateKey_ecc), + TEST_DECL(test_wolfSSL_PEM_PrivateKey_dsa), + TEST_DECL(test_wolfSSL_PEM_PrivateKey_dh), TEST_DECL(test_wolfSSL_PEM_PrivateKey), TEST_DECL(test_wolfSSL_PEM_file_RSAKey), TEST_DECL(test_wolfSSL_PEM_file_RSAPrivateKey), @@ -71824,7 +72514,9 @@ TEST_CASE testCases[] = { #endif #ifdef OPENSSL_EXTRA + TEST_DECL(test_EC25519), TEST_DECL(test_ED25519), + TEST_DECL(test_EC448), TEST_DECL(test_ED448), #endif diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 43d1d1db9..6bb8edc12 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -24214,14 +24214,25 @@ int AllocDer(DerBuffer** pDer, word32 length, int type, void* heap) return ret; } +int AllocCopyDer(DerBuffer** pDer, const unsigned char* buff, word32 length, + int type, void* heap) +{ + int ret = AllocDer(pDer, length, type, heap); + if (ret == 0) { + XMEMCPY((*pDer)->buffer, buff, length); + } + + return ret; +} + void FreeDer(DerBuffer** pDer) { - if (pDer && *pDer) - { + if (pDer && *pDer) { DerBuffer* der = (DerBuffer*)*pDer; /* ForceZero private keys */ - if (der->type == PRIVATEKEY_TYPE && der->buffer != NULL) { + if (((der->type == PRIVATEKEY_TYPE) || + (der->type == ALT_PRIVATEKEY_TYPE)) && der->buffer != NULL) { ForceZero(der->buffer, der->length); } der->buffer = NULL; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 89a300e92..4f1f43a6d 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3577,7 +3577,7 @@ struct WOLFSSL_CTX { int certChainCnt; #endif DerBuffer* privateKey; - byte privateKeyType:6; + byte privateKeyType; byte privateKeyId:1; byte privateKeyLabel:1; int privateKeySz; @@ -4553,7 +4553,7 @@ typedef struct Buffers { #ifndef NO_CERTS DerBuffer* certificate; /* WOLFSSL_CTX owns, unless we own */ DerBuffer* key; /* WOLFSSL_CTX owns, unless we own */ - byte keyType:6; /* Type of key */ + byte keyType; /* Type of key */ byte keyId:1; /* Key data is an id not data */ byte keyLabel:1; /* Key data is a label not data */ int keySz; /* Size of RSA key */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index cb36864cd..7f8b27264 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -793,9 +793,9 @@ enum SNICbReturn { * functions should use this macro to fill this gap. Users who want them * to return the same return value as OpenSSL can define * WOLFSSL_ERR_CODE_OPENSSL. - * Give item1 a variable that contains the potentially negative + * Give rc a variable that contains the potentially negative * wolfSSL-defined return value or the return value itself, and - * give item2 the openSSL-defined return value. + * give fail_rc the openSSL-defined return value. * Note that this macro replaces only negative return values with the * specified value. * Since wolfSSL 4.7.0, the following functions use this macro: @@ -804,11 +804,15 @@ enum SNICbReturn { * - wolfSSL_EVP_PKEY_cmp */ #if defined(WOLFSSL_ERROR_CODE_OPENSSL) - #define WS_RETURN_CODE(item1,item2) \ - (((item1) < 0) ? (int)(item2) : (int)(item1)) + #define WS_RETURN_CODE(rc, fail_rc) \ + (((rc) < 0) ? (int)(fail_rc) : (int)(rc)) #else - #define WS_RETURN_CODE(item1,item2) (item1) + #define WS_RETURN_CODE(rc, fail_rc) (rc) #endif +#define WS_RC(rc) \ + (((rc) == 1) ? 1 : 0) +#define WC_TO_WS_RC(ret) \ + (((ret) == 0) ? 1 : (ret)) /* Maximum master key length (SECRET_LEN) */ #define WOLFSSL_MAX_MASTER_KEY_LENGTH 48 @@ -4553,7 +4557,7 @@ WOLFSSL_API WOLFSSL_X509_NAME_ENTRY *wolfSSL_X509_NAME_get_entry(WOLFSSL_X509_NA WOLFSSL_API void wolfSSL_X509_NAME_ENTRY_free(WOLFSSL_X509_NAME_ENTRY* ne); WOLFSSL_API WOLFSSL_X509_NAME_ENTRY* wolfSSL_X509_NAME_ENTRY_new(void); WOLFSSL_API void wolfSSL_X509_NAME_free(WOLFSSL_X509_NAME* name); -WOLFSSL_API char wolfSSL_CTX_use_certificate(WOLFSSL_CTX* ctx, WOLFSSL_X509* x); +WOLFSSL_API int wolfSSL_CTX_use_certificate(WOLFSSL_CTX* ctx, WOLFSSL_X509* x); WOLFSSL_API int wolfSSL_CTX_add0_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509); WOLFSSL_API int wolfSSL_CTX_add1_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509); WOLFSSL_API int wolfSSL_add0_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509); diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index e8a6f99dd..77ce5680c 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2365,7 +2365,10 @@ WOLFSSL_LOCAL int wc_EncryptedInfoParse(EncryptedInfo* info, WOLFSSL_LOCAL int PemToDer(const unsigned char* buff, long sz, int type, DerBuffer** pDer, void* heap, EncryptedInfo* info, int* eccKey); -WOLFSSL_LOCAL int AllocDer(DerBuffer** der, word32 length, int type, void* heap); +WOLFSSL_LOCAL int AllocDer(DerBuffer** der, word32 length, int type, + void* heap); +WOLFSSL_LOCAL int AllocCopyDer(DerBuffer** der, const unsigned char* buff, + word32 length, int type, void* heap); WOLFSSL_LOCAL void FreeDer(DerBuffer** der); #if (defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT)) || \ diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index daa5f45b1..21e25fcbd 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -139,6 +139,10 @@ #define WC_ECC_FIPS_GEN_MIN (WC_ECC_FIPS_SIG_MIN/8) #endif +#ifdef WOLFSSL_SM2 + #define WOLFSSL_SM2_KEY_BITS 256 +#endif + /* calculate max ECC bytes */ #if ((MAX_ECC_BITS * 2) % 8) == 0 #define MAX_ECC_BYTES (MAX_ECC_BITS / 8)