diff --git a/.github/workflows/cmake-autoconf.yml b/.github/workflows/cmake-autoconf.yml new file mode 100644 index 0000000000..a29636ea75 --- /dev/null +++ b/.github/workflows/cmake-autoconf.yml @@ -0,0 +1,41 @@ +name: WolfSSL CMake Autoconf Interworking Test + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +jobs: + build: + if: github.repository_owner == 'wolfssl' + runs-on: ubuntu-latest + + steps: +# pull wolfSSL + - uses: actions/checkout@v4 + +# install cmake and autotools + - name: Install cmake + run: | + sudo apt-get update + sudo apt-get install -y cmake autoconf automake libtool + +# build and install wolfssl via autotools for CMake consumer test + - name: Build wolfssl with autotools + run: | + ./autogen.sh + ./configure --prefix="$GITHUB_WORKSPACE/install-autoconf" --enable-all + make -j $(nproc) + make install + +# CMake consumer test using the autotools install + - name: CMake consumer test (autotools install) + run: | + mkdir -p cmake/consumer/build + cd cmake/consumer/build + cmake -DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/install-autoconf" .. + cmake --build . + ./wolfssl_consumer + cd .. + rm -rf build diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 0e9b800acc..9639a7a6e9 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -13,7 +13,7 @@ jobs: steps: # pull wolfSSL - - uses: actions/checkout@master + - uses: actions/checkout@v4 # install cmake - name: Install cmake @@ -21,24 +21,16 @@ jobs: sudo apt-get update sudo apt-get install -y cmake -# pull wolfssl - - name: Checkout wolfssl - uses: actions/checkout@master - with: - repository: wolfssl/wolfssl - path: wolfssl - # build wolfssl - name: Build wolfssl - working-directory: ./wolfssl run: | mkdir build cd build cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DWOLFSSL_INSTALL=yes -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install" \ -DWOLFSSL_16BIT:BOOL=no -DWOLFSSL_32BIT:BOOL=no -DWOLFSSL_AES:BOOL=yes \ - -DWOLFSSL_AESCBC:BOOL=yes -DWOLFSSL_AESCCM:BOOL=yes -DWOLFSSL_AESCFB:BOOL=yes \ + -DWOLFSSL_AESCBC:BOOL=yes -DWOLFSSL_AESCCM:BOOL=yes -DWOLFSSL_AESCFB:BOOL=yes -DWOLFSSL_AESECB:BOOL=yes \ -DWOLFSSL_AESCTR:BOOL=yes -DWOLFSSL_AESGCM:STRING=yes -DWOLFSSL_AESKEYWRAP:BOOL=yes \ - -DWOLFSSL_AESOFB:BOOL=yes -DWOLFSSL_AESSIV:BOOL=yes -DWOLFSSL_ALIGN_DATA:BOOL=yes \ + -DWOLFSSL_AESOFB:BOOL=yes -DWOLFSSL_AESCTS:BOOL=yes -DWOLFSSL_AESSIV:BOOL=yes -DWOLFSSL_ALIGN_DATA:BOOL=yes \ -DWOLFSSL_ALPN:BOOL=ON -DWOLFSSL_ALT_CERT_CHAINS:BOOL=ON -DWOLFSSL_ARC4:BOOL=yes \ -DWOLFSSL_ARIA:BOOL=no -DWOLFSSL_ASIO:BOOL=no -DWOLFSSL_ASM:BOOL=yes -DWOLFSSL_ASN:BOOL=yes \ -DWOLFSSL_ASYNC_THREADS:BOOL=no -DWOLFSSL_BASE64_ENCODE:BOOL=yes -DWOLFSSL_CAAM:BOOL=no \ @@ -51,7 +43,7 @@ jobs: -DWOLFSSL_CURVE448:STRING=yes -DWOLFSSL_DEBUG:BOOL=yes -DWOLFSSL_DES3:BOOL=ON \ -DWOLFSSL_DES3_TLS_SUITES:BOOL=no -DWOLFSSL_DH:STRING=yes -DWOLFSSL_DH_DEFAULT_PARAMS:BOOL=yes \ -DWOLFSSL_DSA:BOOL=yes -DWOLFSSL_DTLS:BOOL=ON -DWOLFSSL_DTLS13:BOOL=yes \ - -DWOLFSSL_DTLS_CID:BOOL=yes -DWOLFSSL_ECC:STRING=yes \ + -DWOLFSSL_DTLS_CID:BOOL=yes -DWOLFSSL_DTLS_CH_FRAG:BOOL=yes -DWOLFSSL_ECC:STRING=yes \ -DWOLFSSL_ECCCUSTCURVES:STRING=all -DWOLFSSL_ECCSHAMIR:BOOL=yes \ -DWOLFSSL_ECH:BOOL=yes -DWOLFSSL_ED25519:BOOL=yes -DWOLFSSL_ED448:STRING=yes \ -DWOLFSSL_ENCKEYS:BOOL=yes -DWOLFSSL_ENC_THEN_MAC:BOOL=yes -DWOLFSSL_ERROR_QUEUE:BOOL=yes \ @@ -80,7 +72,7 @@ jobs: -DWOLFSSL_MLKEM=1 -DWOLFSSL_LMS=1 -DWOLFSSL_LMSSHA256192=1 -DWOLFSSL_EXPERIMENTAL=1 \ -DWOLFSSL_X963KDF:BOOL=yes -DWOLFSSL_DILITHIUM:BOOL=yes -DWOLFSSL_PKCS11:BOOL=yes \ -DWOLFSSL_ECCSI:BOOL=yes -DWOLFSSL_SAKKE:BOOL=yes -DWOLFSSL_SIPHASH:BOOL=yes \ - -DCMAKE_C_FLAGS="-DWOLFSSL_DTLS_CH_FRAG" \ + -DWOLFSSL_WC_RSA_DIRECT:BOOL=yes -DWOLFSSL_PUBLIC_MP:BOOL=yes \ .. cmake --build . ctest -j $(nproc) @@ -92,7 +84,6 @@ jobs: # build "lean-tls" wolfssl - name: Build wolfssl with lean-tls - working-directory: ./wolfssl run: | mkdir build cd build @@ -108,7 +99,6 @@ jobs: # CMake build with user_settings.h - name: Build wolfssl with user_settings.h - working-directory: ./wolfssl run: | mkdir build cp examples/configs/user_settings_all.h ./build/user_settings.h diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 2c35f6da5d..2e6c32d04f 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -70,6 +70,9 @@ jobs: '--enable-all --enable-certgencache', '--enable-sessionexport --enable-dtls --enable-dtls13', '--enable-sessionexport', + '--enable-cryptocb --enable-aesgcm CPPFLAGS="-DWOLF_CRYPTO_CB_AES_SETKEY -DWOLF_CRYPTO_CB_FREE"', + '--disable-tls --enable-cryptocb --enable-aesgcm CPPFLAGS="-DWOLF_CRYPTO_CB_AES_SETKEY -DWOLF_CRYPTO_CB_FREE"', + '--enable-cryptocb --enable-aesgcm CPPFLAGS="-DWOLF_CRYPTO_CB_AES_SETKEY"', '--disable-examples CPPFLAGS=-DWOLFSSL_NO_MALLOC', 'CPPFLAGS=-DNO_WOLFSSL_CLIENT', 'CPPFLAGS=-DNO_WOLFSSL_SERVER', diff --git a/.gitignore b/.gitignore index 0ef9644175..2d8bcc1cf9 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,9 @@ tags .tags* cyassl-config wolfssl-config +cmake/wolfssl-config.cmake +cmake/wolfssl-config-version.cmake +cmake/wolfssl-targets.cmake cyassl.sublime* fips.h fips.c @@ -239,12 +242,17 @@ linuxkm/linuxkm linuxkm/src linuxkm/patches/src *.nds + +# Generated during FreeBSD kernel module build. bsdkm/export_syms bsdkm/i386 bsdkm/libwolfssl.ko bsdkm/machine bsdkm/opt_global.h bsdkm/x86 +bsdkm/bus_if.h +bsdkm/cryptodev_if.h +bsdkm/device_if.h # autotools generated scripts/unit.test @@ -386,6 +394,7 @@ IDE/**/DerivedData CMakeFiles/ CMakeCache.txt cmake_install.cmake +!cmake/Config.cmake.in # GDB Settings \.gdbinit @@ -470,3 +479,6 @@ wolfssl/debug-trace-error-codes.h wolfssl/debug-untrace-error-codes.h AGENTS.md + +# Code navigation files +compile_commands.json diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index af5a97f080..a56621e980 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -36,6 +36,7 @@ BLAKE2B_SELFTEST BLAKE2S_SELFTEST BLOCKING BSDKM_EXPORT_SYMS +ENABLED_BSDKM_REGISTER BSP_DEFAULT_IO_CHANNEL_DEFINED BSP_LED_0 BSP_LED_1 @@ -280,7 +281,10 @@ HAVE_INTEL_QAT_SYNC HAVE_INTEL_SPEEDUP HAVE_MDK_RTX HAVE_NETX_BSD +HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK +HAVE_PKCS11_STATIC +HAVE_PKCS11_V3_STATIC HAVE_POCO_LIB HAVE_RTP_SYS HAVE_SECURE_GETENV @@ -637,7 +641,6 @@ WC_RSA_NONBLOCK WC_RSA_NONBLOCK_TIME WC_RSA_NO_FERMAT_CHECK WC_RWLOCK_OPS_INLINE -WC_SHA3_HARDEN WC_SHA384 WC_SHA384_DIGEST_SIZE WC_SHA512 diff --git a/CMakeLists.txt b/CMakeLists.txt index f6c41c410e..c915843737 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -427,6 +427,18 @@ if(WOLFSSL_DTLS_CID) list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_DTLS_CID") endif() +# DTLS 1.3 Fragment ClientHello +add_option("WOLFSSL_DTLS_CH_FRAG" + "Enable wolfSSL DTLS 1.3 Fragment ClientHello (default: disabled)" + "no" "yes;no") + +if(WOLFSSL_DTLS_CH_FRAG) + if(NOT WOLFSSL_DTLS13) + message(FATAL_ERROR "DTLS 1.3 Fragment ClientHello is supported only for DTLSv1.3") + endif() + list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_DTLS_CH_FRAG") +endif() + # RNG add_option("WOLFSSL_RNG" "Enable compiling and using RNG (default: enabled)" @@ -511,9 +523,6 @@ if(WOLFSSL_WOLFSSH) list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_WOLFSSH") endif() -if(WOLFSSL_WOLFSSH OR WOLFSSL_WPAS) - list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_PUBLIC_MP") -endif() # TODO: - DTLS-SCTP # - DTLS multicast @@ -881,6 +890,27 @@ add_option("WOLFSSL_AESOFB" "Enable wolfSSL AES-OFB support (default: disabled)" "no" "yes;no") +# AES-ECB +add_option("WOLFSSL_AESECB" + "Enable wolfSSL AES-ECB support (default: disabled)" + "no" "yes;no") + +if(WOLFSSL_AESECB) + list(APPEND WOLFSSL_DEFINITIONS "-DHAVE_AES_ECB") +endif() + +# AES-CTS +add_option("WOLFSSL_AESCTS" + "Enable wolfSSL AES-CTS support (default: disabled)" + "no" "yes;no") + +if(WOLFSSL_AESCTS) + if(NOT WOLFSSL_AESCBC) + message(FATAL_ERROR "AES-CTS requires AES-CBC.") + endif() + list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_AES_CTS") +endif() + # TODO: - AES-GCM stream # - AES-ARM # - Xilinx hardened crypto @@ -1080,7 +1110,7 @@ if(WOLFSSL_ECCSI) message(FATAL_ERROR "cannot enable ECCSI without enabling ECC.") endif() - list(APPEND WOLFSSL_DEFINITIONS "-DWOLFCRYPT_HAVE_ECCSI -DWOLFSSL_PUBLIC_MP") + list(APPEND WOLFSSL_DEFINITIONS "-DWOLFCRYPT_HAVE_ECCSI") endif() # SAKKE @@ -1105,6 +1135,18 @@ if(WOLFSSL_SIPHASH) list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SIPHASH") endif() +add_option("WOLFSSL_PUBLIC_MP" + "Enable public MP API (default: disabled)" + "no" "yes;no") + +if(WOLFSSL_WOLFSSH OR WOLFSSL_WPAS OR WOLFSSL_ECCSI) + override_cache(WOLFSSL_PUBLIC_MP "yes") +endif() + +if(WOLFSSL_PUBLIC_MP) + list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_PUBLIC_MP") +endif() + # TODO: - Compressed key # - FP ECC, fixed point cache ECC # - ECC encrypt @@ -1310,6 +1352,15 @@ else() endif() endif() +# RSA Direct +add_option("WOLFSSL_WC_RSA_DIRECT" + "Enable RSA Direct (default: disabled)" + "no" "yes;no") + +if(WOLFSSL_RSA AND WOLFSSL_WC_RSA_DIRECT) + list(APPEND WOLFSSL_DEFINITIONS "-DWC_RSA_DIRECT") +endif() + # OAEP add_option("WOLFSSL_OAEP" "Enable RSA OAEP (default: enabled)" @@ -1435,6 +1486,12 @@ if(NOT WOLFSSL_AES) if(WOLFSSL_AESCTR) message(FATAL_ERROR "AESCTR requires AES.") endif() + if(WOLFSSL_AESECB) + message(FATAL_ERROR "AES-ECB requires AES.") + endif() + if(WOLFSSL_AESCTS) + message(FATAL_ERROR "AES-CTS requires AES.") + endif() else() if(WOLFSSL_LEAN_PSK) list(APPEND WOLFSSL_DEFINITIONS "-DNO_AES") @@ -2196,13 +2253,14 @@ if(WOLFSSL_AESOFB) endif() if(WOLFSSL_TPM) - override_cache(WOLFSSL_KEYGEN "yes") - override_cache(WOLFSSL_CERTGEN "yes") - override_cache(WOLFSSL_CRYPTOCB "yes") - override_cache(WOLFSSL_CERTREQ "yes") - override_cache(WOLFSSL_CERTEXT "yes") - override_cache(WOLFSSL_PKCS7 "yes") - override_cache(WOLFSSL_AESCFB "yes") + override_cache(WOLFSSL_KEYGEN "yes") + override_cache(WOLFSSL_CERTGEN "yes") + override_cache(WOLFSSL_CRYPTOCB "yes") + override_cache(WOLFSSL_CERTREQ "yes") + override_cache(WOLFSSL_CERTEXT "yes") + override_cache(WOLFSSL_PKCS7 "yes") + override_cache(WOLFSSL_AESCFB "yes") + override_cache(WOLFSSL_PUBLIC_MP "yes") list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_ALLOW_ENCODING_CA_FALSE") endif() @@ -2600,7 +2658,7 @@ target_compile_definitions(wolfssl PRIVATE "BUILDING_WOLFSSL") if(${BUILD_SHARED_LIBS}) target_compile_definitions(wolfssl PUBLIC "WOLFSSL_DLL") endif() -target_compile_definitions(wolfssl PUBLIC ${WOLFSSL_DEFINITIONS}) +target_compile_definitions(wolfssl PRIVATE ${WOLFSSL_DEFINITIONS}) #################################################### # Include Directories @@ -2663,6 +2721,7 @@ if(WOLFSSL_EXAMPLES) add_executable(client ${CMAKE_CURRENT_SOURCE_DIR}/examples/client/client.c) target_link_libraries(client wolfssl) + target_compile_definitions(client PRIVATE ${WOLFSSL_DEFINITIONS}) set_property(TARGET client PROPERTY RUNTIME_OUTPUT_DIRECTORY ${WOLFSSL_OUTPUT_BASE}/examples/client) @@ -2671,6 +2730,7 @@ if(WOLFSSL_EXAMPLES) add_executable(server ${CMAKE_CURRENT_SOURCE_DIR}/examples/server/server.c) target_link_libraries(server wolfssl) + target_compile_definitions(server PRIVATE ${WOLFSSL_DEFINITIONS}) set_property(TARGET server PROPERTY RUNTIME_OUTPUT_DIRECTORY ${WOLFSSL_OUTPUT_BASE}/examples/server) @@ -2681,6 +2741,7 @@ if(WOLFSSL_EXAMPLES) target_include_directories(echoclient PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(echoclient wolfssl) + target_compile_definitions(echoclient PRIVATE ${WOLFSSL_DEFINITIONS}) set_property(TARGET echoclient PROPERTY RUNTIME_OUTPUT_DIRECTORY ${WOLFSSL_OUTPUT_BASE}/examples/echoclient) @@ -2691,6 +2752,7 @@ if(WOLFSSL_EXAMPLES) target_include_directories(echoserver PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(echoserver wolfssl) + target_compile_definitions(echoserver PRIVATE ${WOLFSSL_DEFINITIONS}) set_property(TARGET echoserver PROPERTY RUNTIME_OUTPUT_DIRECTORY ${WOLFSSL_OUTPUT_BASE}/examples/echoserver) @@ -2700,6 +2762,7 @@ if(WOLFSSL_EXAMPLES) add_executable(tls_bench ${CMAKE_CURRENT_SOURCE_DIR}/examples/benchmark/tls_bench.c) target_link_libraries(tls_bench wolfssl) + target_compile_definitions(tls_bench PRIVATE ${WOLFSSL_DEFINITIONS}) if(CMAKE_USE_PTHREADS_INIT) target_link_libraries(tls_bench Threads::Threads) endif() @@ -2804,6 +2867,7 @@ if(WOLFSSL_EXAMPLES) ${CMAKE_CURRENT_BINARY_DIR}) target_compile_options(unit_test PUBLIC "-DNO_MAIN_DRIVER") target_link_libraries(unit_test wolfssl) + target_compile_definitions(unit_test PRIVATE ${WOLFSSL_DEFINITIONS}) if(CMAKE_USE_PTHREADS_INIT) target_link_libraries(unit_test Threads::Threads) endif() @@ -2829,6 +2893,7 @@ if(WOLFSSL_CRYPT_TESTS) ${CMAKE_CURRENT_SOURCE_DIR}/wolfcrypt/test/test.c) set_target_properties(wolfcrypttest_lib PROPERTIES OUTPUT_NAME "wolfcrypttest") target_link_libraries(wolfcrypttest_lib wolfssl) + target_compile_definitions(wolfcrypttest_lib PRIVATE ${WOLFSSL_DEFINITIONS}) target_compile_options(wolfcrypttest_lib PRIVATE "-DNO_MAIN_DRIVER") if(WOLFSSL_CRYPT_TESTS_HELP) target_compile_options(wolfcrypttest_lib PRIVATE "-DHAVE_WOLFCRYPT_TEST_OPTIONS") @@ -2839,6 +2904,7 @@ if(WOLFSSL_CRYPT_TESTS) ${CMAKE_CURRENT_SOURCE_DIR}/wolfcrypt/benchmark/benchmark.c) set_target_properties(wolfcryptbench_lib PROPERTIES OUTPUT_NAME "wolfcryptbench") target_link_libraries(wolfcryptbench_lib wolfssl) + target_compile_definitions(wolfcryptbench_lib PRIVATE ${WOLFSSL_DEFINITIONS}) target_compile_options(wolfcryptbench_lib PRIVATE "-DNO_MAIN_DRIVER") endif() @@ -2846,6 +2912,7 @@ if(WOLFSSL_CRYPT_TESTS) add_executable(wolfcrypttest ${CMAKE_CURRENT_SOURCE_DIR}/wolfcrypt/test/test.c) target_link_libraries(wolfcrypttest wolfssl) + target_compile_definitions(wolfcrypttest PRIVATE ${WOLFSSL_DEFINITIONS}) set_property(TARGET wolfcrypttest PROPERTY RUNTIME_OUTPUT_DIRECTORY ${WOLFSSL_OUTPUT_BASE}/wolfcrypt/test) @@ -2865,6 +2932,7 @@ if(WOLFSSL_CRYPT_TESTS) target_include_directories(wolfcryptbench PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(wolfcryptbench wolfssl) + target_compile_definitions(wolfcryptbench PRIVATE ${WOLFSSL_DEFINITIONS}) set_property(TARGET wolfcryptbench PROPERTY RUNTIME_OUTPUT_DIRECTORY ${WOLFSSL_OUTPUT_BASE}/wolfcrypt/benchmark) @@ -3019,9 +3087,9 @@ if(WOLFSSL_INSTALL) # Install the library install(TARGETS wolfssl EXPORT wolfssl-targets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) # Install the headers install(DIRECTORY ${WOLFSSL_OUTPUT_BASE}/wolfssl/ diff --git a/IDE/Renesas/e2studio/RX72N/EnvisionKit/Simple/test/.cproject b/IDE/Renesas/e2studio/RX72N/EnvisionKit/Simple/test/.cproject index 9638725c01..84f642eef5 100644 --- a/IDE/Renesas/e2studio/RX72N/EnvisionKit/Simple/test/.cproject +++ b/IDE/Renesas/e2studio/RX72N/EnvisionKit/Simple/test/.cproject @@ -14,7 +14,7 @@ @@ -24,13 +24,13 @@ - - - - - - - - - - - - - - - - - - - - @@ -246,13 +503,13 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/IDE/Renesas/e2studio/RX72N/EnvisionKit/Simple/wolfssl/.cproject b/IDE/Renesas/e2studio/RX72N/EnvisionKit/Simple/wolfssl/.cproject index 03765b97e8..d76e8ab22b 100644 --- a/IDE/Renesas/e2studio/RX72N/EnvisionKit/Simple/wolfssl/.cproject +++ b/IDE/Renesas/e2studio/RX72N/EnvisionKit/Simple/wolfssl/.cproject @@ -24,10 +24,10 @@ - - - - - @@ -63,14 +64,14 @@ - - - - @@ -162,6 +163,7 @@ + diff --git a/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/key_data.c b/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/key_data.c index c49bd62ae3..8b69c2e3db 100644 --- a/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/key_data.c +++ b/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/key_data.c @@ -186,64 +186,64 @@ const uint32_t encrypted_user_key_type = const unsigned char ca_ecc_cert_der_sig[] = { - 0x58, 0x3F, 0x3C, 0x27, 0x4A, 0xC0, 0xA8, 0x35, 0x31, 0xAA, - 0xB6, 0x49, 0x4C, 0x69, 0x48, 0xF6, 0x63, 0xA5, 0x2E, 0x8C, - 0xA4, 0x1E, 0xAF, 0x18, 0x14, 0x11, 0x6A, 0xF7, 0x25, 0xF2, - 0xE1, 0x82, 0x6E, 0xAA, 0x3C, 0xE2, 0x75, 0x6E, 0x81, 0x59, - 0x2E, 0xF1, 0xED, 0xDD, 0xD1, 0x1C, 0xA3, 0xE7, 0xEC, 0x89, - 0xD3, 0x19, 0x1A, 0x59, 0xEB, 0xBA, 0x1D, 0x65, 0xFD, 0x53, - 0x4A, 0x90, 0x6F, 0xA1, 0x06, 0xB3, 0x08, 0xE4, 0x00, 0xF4, - 0x91, 0x45, 0xD8, 0xC9, 0xD8, 0x30, 0x8A, 0x94, 0x9B, 0x48, - 0x60, 0x68, 0xD1, 0x09, 0x84, 0xAE, 0x51, 0xD8, 0xD8, 0x67, - 0x58, 0x58, 0x9B, 0x57, 0x9E, 0x09, 0x9D, 0x1B, 0x3B, 0x22, - 0x67, 0x6A, 0x50, 0x91, 0xF2, 0x60, 0x5E, 0x78, 0x86, 0xF9, - 0x2F, 0xF4, 0xB4, 0xAE, 0x6A, 0xF6, 0x0D, 0xAB, 0x8B, 0xF6, - 0x60, 0x47, 0x8D, 0xD4, 0xEC, 0xE6, 0x9E, 0x57, 0x6C, 0xCC, - 0x4F, 0xF5, 0xCD, 0x20, 0xD7, 0x15, 0x70, 0x50, 0x53, 0x96, - 0x84, 0x6B, 0x9A, 0x07, 0x90, 0x41, 0x14, 0x08, 0x62, 0x87, - 0xF5, 0x20, 0x0E, 0x82, 0xE2, 0x12, 0x5C, 0x1E, 0x72, 0x73, - 0xB8, 0x18, 0x90, 0xCF, 0x98, 0x14, 0xC3, 0xE6, 0xED, 0x89, - 0xA3, 0x7C, 0x67, 0x50, 0x01, 0xCC, 0x48, 0xD2, 0x6A, 0x9C, - 0x9E, 0x4D, 0x44, 0x49, 0x82, 0x5F, 0xC1, 0x2E, 0x18, 0xBE, - 0x23, 0x53, 0xCD, 0x09, 0x85, 0x16, 0x9D, 0x5F, 0x99, 0x78, - 0xA1, 0x78, 0x51, 0xC9, 0x5A, 0x3E, 0x04, 0xBE, 0xE2, 0xF5, - 0x74, 0x7E, 0x6F, 0x89, 0xD9, 0x05, 0x29, 0xC1, 0x5B, 0x57, - 0x3D, 0xE3, 0x5E, 0xB8, 0x4B, 0x93, 0x7D, 0x68, 0x78, 0xF9, - 0x88, 0x1B, 0x8E, 0x78, 0x04, 0x00, 0x54, 0x20, 0x3F, 0x0C, - 0x99, 0x11, 0x1D, 0x90, 0x2C, 0x10, 0x4C, 0xCE, 0xA3, 0x17, - 0xA7, 0xF8, 0xB4, 0xC6, 0xF8, 0x12 + 0x0B, 0x1D, 0x49, 0x40, 0xE8, 0xDA, 0x46, 0xAE, 0x1C, 0x50, + 0xC8, 0x76, 0xF3, 0x57, 0x05, 0x95, 0x89, 0xE1, 0x8B, 0x13, + 0x6B, 0x0F, 0xEB, 0x47, 0x0E, 0x1E, 0x9C, 0x87, 0xBB, 0x07, + 0x6E, 0xE4, 0x6B, 0xDF, 0x5B, 0xEF, 0xA3, 0x2C, 0xD8, 0x07, + 0x91, 0x5B, 0x4E, 0x5B, 0xA1, 0xD0, 0x3E, 0x07, 0x22, 0xAF, + 0x12, 0xF3, 0x0F, 0x62, 0x35, 0x45, 0x82, 0xFC, 0x26, 0x2B, + 0xD1, 0x03, 0x51, 0xAB, 0x35, 0xFE, 0x48, 0x80, 0xC9, 0x68, + 0xA0, 0xE0, 0x54, 0x4A, 0x8F, 0xA7, 0x59, 0xA1, 0xED, 0x57, + 0x3D, 0x9D, 0xC0, 0x6B, 0x22, 0x20, 0xDA, 0x1A, 0xFF, 0xDB, + 0x01, 0x60, 0x59, 0x21, 0x88, 0xD5, 0x5A, 0x40, 0x25, 0x82, + 0xB0, 0x27, 0x54, 0xDC, 0x37, 0x79, 0x70, 0xD1, 0x6C, 0x63, + 0x63, 0xC6, 0x98, 0x63, 0xA9, 0xE6, 0xB7, 0x6C, 0x50, 0xC1, + 0x40, 0xCF, 0xE9, 0x84, 0xC7, 0xB9, 0x8F, 0x7C, 0xC3, 0xE1, + 0xE2, 0x96, 0x67, 0xC6, 0x48, 0x25, 0xD8, 0xB3, 0x40, 0x94, + 0x13, 0xF3, 0x55, 0xF8, 0xC3, 0xEA, 0x39, 0xE1, 0xE9, 0x36, + 0xD1, 0xBE, 0xB2, 0x9C, 0x86, 0xD1, 0x78, 0xE1, 0xC7, 0x67, + 0x3B, 0xD0, 0x10, 0x57, 0x7B, 0x09, 0x33, 0x03, 0x01, 0x8A, + 0xDA, 0x30, 0x1F, 0x74, 0xED, 0x99, 0x8F, 0x93, 0xA2, 0x73, + 0x7B, 0xA6, 0x3A, 0x44, 0x74, 0x9C, 0x5E, 0x19, 0x1B, 0x0B, + 0x63, 0x3A, 0xAF, 0x5C, 0xD5, 0xB4, 0x1C, 0xF0, 0x0B, 0x3F, + 0x15, 0xB3, 0x6B, 0x10, 0x88, 0x93, 0x6C, 0xAB, 0xB4, 0x65, + 0x35, 0xCC, 0x91, 0x9A, 0x19, 0x5D, 0xDF, 0xE0, 0xAC, 0x75, + 0xC3, 0x14, 0x46, 0x2E, 0x7B, 0xF8, 0x73, 0xEB, 0x75, 0xD8, + 0x47, 0xAF, 0x1E, 0x7B, 0x5B, 0xE5, 0x09, 0x01, 0x42, 0x5C, + 0xB3, 0xC6, 0xEB, 0x92, 0xC5, 0x85, 0x6B, 0xD4, 0x22, 0x39, + 0x77, 0x92, 0x13, 0x8A, 0x42, 0x2C }; const int sizeof_ca_ecc_cert_sig = sizeof(ca_ecc_cert_der_sig); /* ./ca-cert.der.sign, */ const unsigned char ca_cert_der_sig[] = { - 0x55, 0x93, 0xCF, 0x28, 0xF7, 0x38, 0x1E, 0xF1, 0x29, 0x5A, - 0xDE, 0x41, 0xCD, 0x83, 0x00, 0x06, 0x79, 0xB3, 0x12, 0x56, - 0xBD, 0x04, 0xCB, 0x97, 0xCC, 0xD2, 0x39, 0x3C, 0x36, 0x94, - 0x8D, 0x66, 0xB0, 0x41, 0xF4, 0xBD, 0x82, 0x8F, 0x03, 0x24, - 0x25, 0x65, 0xA1, 0x85, 0x87, 0xCE, 0x58, 0x0A, 0x45, 0xC6, - 0xB6, 0x38, 0x27, 0x44, 0x2A, 0x7A, 0x9B, 0xA2, 0x71, 0x67, - 0x92, 0xDA, 0xFD, 0x71, 0x88, 0x52, 0xF2, 0xFE, 0x61, 0x33, - 0xCB, 0x7F, 0xB4, 0x47, 0x3D, 0x60, 0xC6, 0x3A, 0x48, 0x44, - 0x6F, 0xA2, 0x16, 0x07, 0xA2, 0x94, 0x50, 0x99, 0x09, 0x7B, - 0x43, 0x04, 0xAD, 0xCA, 0x9C, 0x34, 0xD4, 0x72, 0x4B, 0x79, - 0x31, 0xE1, 0xC5, 0x6C, 0xA7, 0xB4, 0xD8, 0xED, 0x80, 0x79, - 0xBB, 0x69, 0xA0, 0xA6, 0x7A, 0x63, 0x99, 0x02, 0xF7, 0x64, - 0xF0, 0x6D, 0xBB, 0xC5, 0xDA, 0x55, 0x0D, 0x43, 0x7C, 0x30, - 0x74, 0x21, 0x05, 0x35, 0x63, 0xAD, 0x32, 0x76, 0x11, 0xA5, - 0x75, 0xF3, 0x83, 0xEE, 0x05, 0xFB, 0x91, 0x18, 0x5E, 0xCC, - 0x71, 0x49, 0x26, 0x0D, 0xE2, 0xE3, 0xB3, 0xAD, 0xFF, 0x65, - 0xA9, 0x9B, 0xF0, 0x81, 0xE1, 0x5D, 0xC3, 0x4C, 0x82, 0x83, - 0x33, 0xDA, 0xF6, 0x29, 0xC7, 0xC2, 0xA0, 0x23, 0x5D, 0xB1, - 0xCE, 0x82, 0x94, 0x49, 0xC5, 0xC0, 0xE5, 0xED, 0x3B, 0xF6, - 0x79, 0x21, 0x3B, 0xFC, 0x6D, 0xB5, 0x2A, 0xF6, 0x6D, 0xD9, - 0x4C, 0x3E, 0xBF, 0x2E, 0x13, 0xA2, 0x75, 0x93, 0x5A, 0xB4, - 0x2B, 0xF5, 0x74, 0xEF, 0xAE, 0x48, 0xFE, 0x06, 0x2D, 0x3F, - 0xA3, 0xFE, 0x1A, 0xC9, 0x45, 0x1D, 0x15, 0xC8, 0xEF, 0x95, - 0xE2, 0x6F, 0x7D, 0x1E, 0x96, 0xCD, 0x4D, 0xC5, 0x5F, 0xEB, - 0x57, 0x85, 0x54, 0xE4, 0x7F, 0xE0, 0x0F, 0xAD, 0xC3, 0xEE, - 0xBF, 0xFB, 0x43, 0xA6, 0xAB, 0x92 + 0x67, 0xBD, 0x28, 0x1E, 0x1A, 0x17, 0xFD, 0x88, 0x03, 0x8B, + 0xA2, 0x5A, 0x65, 0xB3, 0xF2, 0x17, 0x61, 0xE1, 0x7F, 0x9B, + 0xC3, 0x50, 0xEC, 0x55, 0x61, 0x46, 0x0C, 0xC1, 0x2B, 0x9D, + 0x02, 0xDB, 0x0A, 0x36, 0xA1, 0x49, 0x95, 0x42, 0xD1, 0x1A, + 0x75, 0xEC, 0x39, 0xC2, 0x10, 0xC5, 0x9F, 0xDC, 0x8C, 0xBC, + 0x4E, 0x04, 0xC9, 0x5E, 0x52, 0x6B, 0x42, 0xF0, 0x4E, 0x8D, + 0x0D, 0xDD, 0x01, 0x05, 0x14, 0x77, 0x28, 0x75, 0xB6, 0x36, + 0xA8, 0xD1, 0xA9, 0xB4, 0x46, 0xB5, 0xED, 0xD9, 0x10, 0x62, + 0xEC, 0x3B, 0xA5, 0x5B, 0x10, 0xB7, 0xE2, 0xC7, 0x67, 0x4F, + 0x1A, 0x48, 0x9B, 0xAF, 0x31, 0x9D, 0x21, 0xDC, 0x3B, 0x06, + 0xAC, 0x95, 0x78, 0xE6, 0x2D, 0x5F, 0xA8, 0xAD, 0xCC, 0xD2, + 0x4E, 0xF3, 0x4A, 0xC9, 0x7E, 0x4A, 0x28, 0x51, 0x6D, 0xBC, + 0x8D, 0xA5, 0x57, 0x49, 0x32, 0xC0, 0xE2, 0x48, 0x57, 0x8B, + 0x7D, 0x4D, 0x9B, 0x43, 0x99, 0xF0, 0xC0, 0x21, 0xD0, 0xAF, + 0x3D, 0x5B, 0xE0, 0x4F, 0xC2, 0x7C, 0xCF, 0xCC, 0xDB, 0x9A, + 0x79, 0xB6, 0x7E, 0xA0, 0x53, 0xAA, 0x4D, 0x5B, 0xD0, 0x3A, + 0xBA, 0x7F, 0xCC, 0x99, 0xD6, 0x68, 0xD7, 0x14, 0x85, 0xD7, + 0x8E, 0xE0, 0x1A, 0x6E, 0xE7, 0xC1, 0xD5, 0x2B, 0x35, 0x94, + 0x8E, 0xC1, 0x59, 0xC5, 0xAE, 0x48, 0x22, 0x87, 0x36, 0xC1, + 0xA4, 0xD9, 0x58, 0xC1, 0x2A, 0xD6, 0xFE, 0x45, 0x63, 0xCA, + 0x8F, 0x93, 0x86, 0xEC, 0x8D, 0xC2, 0xFD, 0xE3, 0x62, 0xD6, + 0x4C, 0x43, 0xFE, 0x82, 0x4F, 0xC9, 0x9D, 0xA9, 0xD8, 0xE4, + 0x5C, 0x15, 0x6D, 0xDE, 0xF9, 0x3D, 0x76, 0xB7, 0xBA, 0xF7, + 0x1C, 0xFB, 0x90, 0x74, 0xBB, 0x60, 0x93, 0xA4, 0x0C, 0xA4, + 0xFF, 0x41, 0x1C, 0x18, 0x7E, 0xE8, 0xE3, 0x78, 0xF5, 0x52, + 0x98, 0x50, 0xFD, 0xA8, 0x07, 0xAD }; const int sizeof_ca_cert_sig = sizeof(ca_cert_der_sig); /* ./client-cert.der.sign, */ diff --git a/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/user_settings.h b/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/user_settings.h index 99c6b485cb..bf8a3a335f 100644 --- a/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/user_settings.h +++ b/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/user_settings.h @@ -294,5 +294,3 @@ /*-- strcasecmp */ #define XSTRCASECMP(s1,s2) strcmp((s1),(s2)) -/* use original ASN parsing */ -#define WOLFSSL_ASN_ORIGINAL diff --git a/INSTALL b/INSTALL index a0f649a563..dc6e2908c1 100644 --- a/INSTALL +++ b/INSTALL @@ -16,6 +16,9 @@ all the generated build options. This file needs to be included in your application before any other wolfSSL headers. Optionally your application can define WOLFSSL_USE_OPTIONS_H to do this automatically. + Note: Building with configure also installs CMake package files under + $(libdir)/cmake/wolfssl to support find_package(wolfssl). You can disable this + with ./configure --disable-cmake-install. 2. Building on iOS diff --git a/Makefile.am b/Makefile.am index b7fc4db2fb..721e471eff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -78,6 +78,9 @@ CLEANFILES+= ecc-key.der \ pkcs7encryptedDataDES3.der \ pkcs7encryptedDataDES.der \ pkcs7envelopedDataAES256CBC_ECDH.der \ + cmake/wolfssl-config.cmake \ + cmake/wolfssl-config-version.cmake \ + cmake/wolfssl-targets.cmake \ pkcs7envelopedDataAES128CBC_ECDH_SHA1KDF.der \ pkcs7envelopedDataAES256CBC_ECDH_SHA256KDF.der \ pkcs7envelopedDataAES256CBC_ECDH_SHA512KDF.der \ @@ -247,8 +250,9 @@ if BUILD_BSDKM EXTRA_CFLAGS EXTRA_CPPFLAGS EXTRA_CCASFLAGS EXTRA_LDFLAGS \ AM_CPPFLAGS CPPFLAGS AM_CFLAGS CFLAGS \ AM_CCASFLAGS CCASFLAGS \ - src_libwolfssl_la_OBJECTS ENABLED_CRYPT_TESTS - + src_libwolfssl_la_OBJECTS ENABLED_CRYPT_TESTS ENABLED_BSDKM_REGISTER \ + ENABLED_ASM ENABLED_INTELASM ENABLED_AESNI ENABLED_AESNI_WITH_AVX \ + ENABLED_KERNEL_BENCHMARKS endif diff --git a/README.md b/README.md index 94b71b812d..1cd6bb1522 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,29 @@ suites are available. You can remove this error by defining `WOLFSSL_ALLOW_NO_SUITES` in the event that you desire that, i.e., you're not using TLS cipher suites. +### AES CryptoCB Key Import Support + +wolfSSL supports hardware-accelerated AES operations via CryptoCB. + +When `WOLF_CRYPTO_CB_AES_SETKEY` is defined, wolfSSL invokes a CryptoCB +callback during AES key setup. The callback behavior determines the mode: + +**If callback returns 0 (success):** +- Key is imported to Secure Element/HSM +- Key is NOT copied to wolfSSL RAM (true key isolation) +- GCM tables are NOT generated (full hardware offload) +- All subsequent AES operations route through CryptoCB + +**If callback returns CRYPTOCB_UNAVAILABLE:** +- SE doesn't support key import +- Normal software AES path is used +- Key is copied to devKey for CryptoCB encrypt/decrypt acceleration + +This feature enables TLS 1.3 traffic key protection on embedded platforms +where symmetric keys must never exist in main RAM. + +Enable with: `CPPFLAGS="-DWOLF_CRYPTO_CB_AES_SETKEY -DWOLF_CRYPTO_CB_FREE"` + ### Note 2 wolfSSL takes a different approach to certificate verification than OpenSSL does. The default policy for the client is to verify the server, this means diff --git a/bsdkm/Makefile b/bsdkm/Makefile index dd6bbcbd77..5a191080f7 100644 --- a/bsdkm/Makefile +++ b/bsdkm/Makefile @@ -1,19 +1,27 @@ -# wolfssl kernel module name and source, and root dir. -KMOD=libwolfssl -SRCS=wolfkmod.c -WOLFSSL_DIR=../ +# wolfssl kernel module name and main source, and wolfssl root dir. +KMOD = libwolfssl +SRCS = wolfkmod.c +WOLFSSL_DIR = ../ -CFLAGS+=-I${WOLFSSL_DIR} -CFLAGS+=-DWOLFSSL_IGNORE_FILE_WARN -DHAVE_CONFIG_H -DNO_MAIN_DRIVER +CFLAGS += -I${WOLFSSL_DIR} +CFLAGS += -DWOLFSSL_IGNORE_FILE_WARN -DHAVE_CONFIG_H -DNO_MAIN_DRIVER # # debug options # verbose printing: -# CFLAGS+=-DWOLFSSL_BSDKM_VERBOSE_DEBUG +# CFLAGS += -DWOLFSSL_BSDKM_VERBOSE_DEBUG # # print memory mallocs / frees: -# CFLAGS+=-DWOLFSSL_BSDKM_MEMORY_DEBUG +# CFLAGS += -DWOLFSSL_BSDKM_MEMORY_DEBUG # -CFLAGS+=$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) +# print fpu_kern_enter / leave: +# CFLAGS += WOLFSSL_BSDKM_FPU_DEBUG +# +CFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) + +.if defined(ENABLED_BSDKM_REGISTER) + # These device header files are generated during build. + SRCS += bus_if.h cryptodev_if.h device_if.h +.endif # FreeBSD make does not support GNU make's patsubst and related. Filter # through sed instead. @@ -21,19 +29,26 @@ WOLFSSL_OBJS != echo ${src_libwolfssl_la_OBJECTS} | \ sed 's|src_libwolfssl_la-||g' | sed 's|\.lo|.o|g' | \ sed 's|wolfcrypt/src/|${WOLFSSL_DIR}/wolfcrypt/src/|g' +# wolfcrypt test .if ${ENABLED_CRYPT_TESTS} == "yes" WOLFSSL_OBJS += ${WOLFSSL_DIR}/wolfcrypt/test/test.o .else - CFLAGS+=-DNO_CRYPT_TEST + CFLAGS += -DNO_CRYPT_TEST +.endif + +# wolfcrypt benchmark +.if ${ENABLED_KERNEL_BENCHMARKS} == "yes" + WOLFSSL_OBJS += ${WOLFSSL_DIR}/wolfcrypt/benchmark/benchmark.o + CFLAGS += -DWOLFSSL_NO_FLOAT_FMT .endif OBJS += ${WOLFSSL_OBJS} # Export no public symbols by default. .if !defined(BSDKM_EXPORT_SYMS) - EXPORT_SYMS=NO + EXPORT_SYMS = NO .else - EXPORT_SYMS=${BSDKM_EXPORT_SYMS} + EXPORT_SYMS = ${BSDKM_EXPORT_SYMS} .endif # Default to live kernel src tree makefile at @@ -45,12 +60,52 @@ OBJS += ${WOLFSSL_OBJS} .endif .include "${SYSDIR}/conf/kmod.mk" +# +# To use aesni and friends in FreeBSD kernel we need to adjust build flags. +# See these kernel makefiles for reference: +# - /usr/src/sys/modules/aesni/Makefile +# - /usr/src/sys/conf/kern.mk +# +WOLFKMOD_SIMD_BASE = -msse -msse2 -msse4.1 +WOLFKMOD_SIMD_AES = -maes -mpclmul +WOLFKMOD_SIMD_AVX = -mavx -mavx2 + +.if ${ENABLED_AESNI} == "yes" + CFLAGS.aes.c += ${WOLFKMOD_SIMD_BASE} + CFLAGS.aes.c += ${WOLFKMOD_SIMD_AES} +.if ${ENABLED_AESNI_WITH_AVX} == "yes" + CFLAGS.aes.c += ${WOLFKMOD_SIMD_AVX} +.endif # ENABLED_AESNI_WITH_AVX # + CFLAGS.aes.c := ${CFLAGS.aes.c:N-nostdinc} + CFLAGS.aes.c += -I${SYSDIR}/../contrib/llvm-project/clang/lib/Headers +.PATH: ${SYSDIR}/../contrib/llvm-project/clang/lib/Headers +.endif # ENABLED_AESNI + +.if ${ENABLED_ASM} == "yes" +.for f in chacha dilithium poly1305 sha sha256 sha3 sha512 + CFLAGS.${f}.c += ${WOLFKMOD_SIMD_BASE} + CFLAGS.${f}.c += ${WOLFKMOD_SIMD_AVX} + CFLAGS.${f}.c := ${CFLAGS.${f}.c:N-nostdinc} + CFLAGS.${f}.c += -I${SYSDIR}/../contrib/llvm-project/clang/lib/Headers +.endfor + +.PATH: ${SYSDIR}/../contrib/llvm-project/clang/lib/Headers +.endif # ENABLED_ASM == "yes" + +# wolfcrypt benchmark always needs simd for the floating point timings. +.if ${ENABLED_KERNEL_BENCHMARKS} == "yes" + CFLAGS.benchmark.c += ${WOLFKMOD_SIMD_BASE} + CFLAGS.benchmark.c := ${CFLAGS.benchmark.c:N-nostdinc} + CFLAGS.benchmark.c += -I${SYSDIR}/../contrib/llvm-project/clang/lib/Headers + .PATH: ${SYSDIR}/../contrib/llvm-project/clang/lib/Headers +.endif + # Smooth out a few inconsistencies between FreeBSD default compiler flags # in /usr/src/sys/conf/kern.mk, vs wolfssl harden flags in # m4/ax_harden_compiler_flags.m4. E.g. some FreeBSD header files shorten # 64 to 32 bit, and some wolfcrypt functions cast away const. -CFLAGS+= -Wno-unused-function -CFLAGS+= -Wno-cast-qual -CFLAGS+= -Wno-error=cast-qual -CFLAGS+= -Wno-shorten-64-to-32 -CFLAGS+= -DLIBWOLFSSL_GLOBAL_EXTRA_CFLAGS="\" $(KERNEL_EXTRA_CFLAGS)\"" +CFLAGS += -Wno-unused-function +CFLAGS += -Wno-cast-qual +CFLAGS += -Wno-error=cast-qual +CFLAGS += -Wno-shorten-64-to-32 +CFLAGS += -DLIBWOLFSSL_GLOBAL_EXTRA_CFLAGS="\" $(KERNEL_EXTRA_CFLAGS)\"" diff --git a/bsdkm/README.md b/bsdkm/README.md index b84c2588ff..0c23ceb251 100644 --- a/bsdkm/README.md +++ b/bsdkm/README.md @@ -7,10 +7,10 @@ other loadable modules to link to wolfCrypt. Supported features: - wolfCrypt in kernel. - FIPS-wolfcrypt. +- crypto acceleration: AES-NI, AVX, etc. Planned features: -- crypto acceleration: AES-NI, AVX, etc. -- kernel opencrypto driver registration. +- kernel opencrypto driver registration (supported for internal testing presently). - full wolfSSL in kernel (kernel TLS). ## Building and Installing @@ -44,10 +44,12 @@ sudo kldunload libwolfssl ### options -| freebsdkm option | description | -| :------------------------------- | :--------------------------------------- | -| --with-bsd-export-syms=LIST | Export list of symbols as global.
. Options are 'all', 'none', or
comma separated list of symbols. | -| --with-kernel-source=PATH | Path to kernel tree root (default `/usr/src/sys`) | +| freebsdkm option | description | +| :--------------------------------- | :--------------------------------------- | +| --with-bsd-export-syms=LIST | Export list of symbols as global.
. Options are 'all', 'none', or
comma separated list of symbols. | +| --with-kernel-source=PATH | Path to kernel tree root (default `/usr/src/sys`) | +| --enable-kernel-benchmarks | Run wolfcrypt benchmark at module load | +| --enable-freebsdkm-crypto-register | Register with the FreeBSD kernel opencrypto
framework (preliminary, for testing) | ### FIPS diff --git a/bsdkm/bsdkm_wc_port.h b/bsdkm/bsdkm_wc_port.h index 2a5524d5f5..0bd80f092b 100644 --- a/bsdkm/bsdkm_wc_port.h +++ b/bsdkm/bsdkm_wc_port.h @@ -61,13 +61,13 @@ static inline time_t wolfkmod_time(time_t * tloc) { #define WOLFSSL_DEBUG_PRINTF_FN printf /* str and char utility functions */ -#define XATOI(s) ({ \ - char * endptr = NULL; \ - long _xatoi_ret = strtol(s, &endptr, 10); \ - if ((s) == endptr || *endptr != '\0') { \ - _xatoi_ret = 0; \ - } \ - (int)_xatoi_ret; \ +#define XATOI(s) ({ \ + char * endptr = NULL; \ + long _xatoi_ret = strtol(s, &endptr, 10); \ + if ((s) == endptr || *endptr != '\0') { \ + _xatoi_ret = 0; \ + } \ + (int)_xatoi_ret; \ }) #if !defined(XMALLOC_OVERRIDE) @@ -103,6 +103,33 @@ extern struct malloc_type M_WOLFSSL[1]; }) #endif /* WOLFSSL_BSDKM_DEBUG_MEMORY */ + +#if defined(WOLFSSL_AESNI) || defined(WOLFSSL_KERNEL_BENCHMARKS) + int wolfkmod_vecreg_init(void); + void wolfkmod_vecreg_exit(void); + int wolfkmod_vecreg_save(int flags_unused); + void wolfkmod_vecreg_restore(void); + /* wrapper defines for FPU_KERN(9). + * /usr/src/sys/amd64/amd64/fpu.c + * /usr/src/sys/amd64/include/pcb.h + * */ + #ifndef WOLFSSL_USE_SAVE_VECTOR_REGISTERS + #define WOLFSSL_USE_SAVE_VECTOR_REGISTERS + #endif + + #define SAVE_VECTOR_REGISTERS(fail_clause) { \ + int _svr_ret = wolfkmod_vecreg_save(0); \ + if (_svr_ret != 0) { \ + fail_clause \ + } \ + } + + #define SAVE_VECTOR_REGISTERS2() wolfkmod_vecreg_save(0) + + #define RESTORE_VECTOR_REGISTERS() wolfkmod_vecreg_restore() + +#endif /* WOLFSSL_AESNI || WOLFSSL_KERNEL_BENCHMARKS */ + #if !defined(SINGLE_THREADED) #define WC_MUTEX_OPS_INLINE @@ -149,7 +176,8 @@ extern struct malloc_type M_WOLFSSL[1]; typedef volatile int wolfSSL_Atomic_Int; typedef volatile unsigned int wolfSSL_Atomic_Uint; #define WOLFSSL_ATOMIC_INITIALIZER(x) (x) - #define WOLFSSL_ATOMIC_LOAD(x) (int)atomic_load_acq_int(&(x)) + #define WOLFSSL_ATOMIC_LOAD(x) (int)atomic_load_acq_int(&(x)) + #define WOLFSSL_ATOMIC_LOAD_UINT(x) atomic_load_acq_int(&(x)) #define WOLFSSL_ATOMIC_STORE(x, v) atomic_store_rel_int(&(x), (v)) #define WOLFSSL_ATOMIC_OPS diff --git a/bsdkm/include.am b/bsdkm/include.am index 896a5447c9..44666b6c08 100644 --- a/bsdkm/include.am +++ b/bsdkm/include.am @@ -2,8 +2,10 @@ # included from Top Level Makefile.am # All paths should be given relative to the root -EXTRA_DIST += m4/ax_bsdkm.m4 \ - bsdkm/Makefile \ - bsdkm/README.md \ - bsdkm/wolfkmod.c \ +EXTRA_DIST += m4/ax_bsdkm.m4 \ + bsdkm/Makefile \ + bsdkm/README.md \ + bsdkm/wolfkmod.c \ + bsdkm/wolfkmod_aes.c \ + bsdkm/x86_vecreg.c \ bsdkm/bsdkm_wc_port.h diff --git a/bsdkm/wolfkmod.c b/bsdkm/wolfkmod.c index bb03e8ebbc..38454d125a 100644 --- a/bsdkm/wolfkmod.c +++ b/bsdkm/wolfkmod.c @@ -26,6 +26,12 @@ #include #include +#if defined(BSDKM_CRYPTO_REGISTER) + #include + #include + #include "cryptodev_if.h" +#endif + /* wolf includes */ #include #ifdef WOLFCRYPT_ONLY @@ -44,15 +50,42 @@ #if !defined(NO_CRYPT_TEST) #include #endif +#if defined(WOLFSSL_KERNEL_BENCHMARKS) + #include +#endif #include MALLOC_DEFINE(M_WOLFSSL, "libwolfssl", "wolfSSL kernel memory"); -static int wolfkmod_init(void); -static int wolfkmod_cleanup(void); -static int wolfkmod_load(void); -static int wolfkmod_unload(void); +#if defined(BSDKM_CRYPTO_REGISTER) + #include "bsdkm/wolfkmod_aes.c" +#endif + +/* common functions. */ +static int wolfkmod_init(void); +static int wolfkmod_cleanup(void); +#if !defined(BSDKM_CRYPTO_REGISTER) +/* functions specific to a pure kernel module library build. */ +static int wolfkmod_load(void); +static int wolfkmod_unload(void); +#else +/* functions specific to a kernel crypto driver module build. */ +static void wolfkdriv_identify(driver_t * driver, device_t parent); +static int wolfkdriv_probe(device_t dev); +static int wolfkdriv_attach(device_t dev); +static int wolfkdriv_detach(device_t dev); +static int wolfkdriv_probesession(device_t dev, + const struct crypto_session_params *csp); +static int wolfkdriv_newsession(device_t dev, crypto_session_t cses, + const struct crypto_session_params *csp); +static void wolfkdriv_freesession(device_t dev, crypto_session_t cses); +static int wolfkdriv_process(device_t dev, struct cryptop *crp, int hint); +#endif /* !BSDKM_CRYPTO_REGISTER */ + +#if defined(WOLFSSL_AESNI) || defined(WOLFSSL_KERNEL_BENCHMARKS) + #include "bsdkm/x86_vecreg.c" +#endif /* WOLFSSL_AESNI || WOLFSSL_KERNEL_BENCHMARKS*/ #ifdef HAVE_FIPS #define WOLFKMOD_FIPS_ERR_MSG(hash) ({ \ @@ -82,6 +115,14 @@ static int wolfkmod_init(void) { int error = 0; + #if defined(WOLFSSL_AESNI) || defined(WOLFSSL_KERNEL_BENCHMARKS) + error = wolfkmod_vecreg_init(); + if (error != 0) { + printf("error: wolfkmod_vecreg_init: %d\n", error); + return (ECANCELED); + } + #endif /* WOLFSSL_AESNI || WOLFSSL_KERNEL_BENCHMARKS*/ + #ifdef HAVE_FIPS error = wolfCrypt_SetCb_fips(wolfkmod_fips_cb); if (error != 0) { @@ -174,14 +215,16 @@ static int wolfkmod_cleanup(void) if (error != 0) { printf("error: wolfCrypt_Cleanup failed: %s\n", wc_GetErrorString(error)); - return (ECANCELED); + error = ECANCELED; + goto wolfkmod_cleanup_out; } #else error = wolfSSL_Cleanup(); if (error != WOLFSSL_SUCCESS) { printf("error: wolfSSL_Cleanup failed: %s\n", wc_GetErrorString(error)); - return (ECANCELED); + error = ECANCELED; + goto wolfkmod_cleanup_out; } #endif /* WOLFCRYPT_ONLY */ @@ -189,10 +232,17 @@ static int wolfkmod_cleanup(void) printf("info: libwolfssl " LIBWOLFSSL_VERSION_STRING " cleanup complete.\n"); #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + error = 0; - return (0); +wolfkmod_cleanup_out: + #if defined(WOLFSSL_AESNI) || defined(WOLFSSL_KERNEL_BENCHMARKS) + wolfkmod_vecreg_exit(); + #endif /* WOLFSSL_AESNI || WOLFSSL_KERNEL_BENCHMARKS*/ + + return (error); } +#if !defined(BSDKM_CRYPTO_REGISTER) static int wolfkmod_load(void) { int error = 0; @@ -212,10 +262,15 @@ static int wolfkmod_load(void) printf("info: wolfCrypt self-test passed.\n"); #endif /* NO_CRYPT_TEST */ - /** - * todo: register wolfcrypt algs here with crypto_get_driverid - * and related. - * */ + #ifdef WOLFSSL_KERNEL_BENCHMARKS + error = benchmark_test(NULL); + if (error != 0) { + printf("error: wolfcrypt benchmark failed: %d\n", error); + (void)wolfkmod_cleanup(); + return (ECANCELED); + } + printf("info: wolfCrypt benchmark passed.\n"); + #endif /* WOLFSSL_KERNEL_BENCHMARKS */ printf("info: libwolfssl loaded\n"); @@ -239,11 +294,6 @@ static int wolfkmod_unload(void) error = wolfkmod_cleanup(); - /** - * todo: unregister wolfcrypt algs here with crypto_unregister_all - * and related. - * */ - if (error == 0) { printf("info: libwolfssl unloaded\n"); } @@ -294,7 +344,718 @@ wolfkmod_event(struct module * m, int what, void * arg) return (error); } +#endif /* !BSDKM_CRYPTO_REGISTER */ +#if defined(BSDKM_CRYPTO_REGISTER) +/* wolfkdriv device driver software context. */ +struct wolfkdriv_softc { + int32_t crid; + device_t dev; +}; + +struct km_aes_ctx { + Aes aes_encrypt; + Aes aes_decrypt; +}; + +typedef struct km_aes_ctx km_aes_ctx; + +struct wolfkdriv_session { + km_aes_ctx aes_ctx; + int32_t crid; + int type; + int ivlen; + int klen; +}; + +typedef struct wolfkdriv_session wolfkdriv_session_t; + +static void km_AesFree(Aes * aes) { + if (aes == NULL) { + return; + } + wc_AesFree(aes); + #if defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0) + ForceZero(aes, sizeof(*aes)); + #endif +} + +static void wolfkdriv_aes_ctx_clear(km_aes_ctx * ctx) +{ + if (ctx != NULL) { + km_AesFree(&ctx->aes_encrypt); + km_AesFree(&ctx->aes_decrypt); + } + + #ifdef WOLFKM_DEBUG_AES + printf("info: exiting km_AesExitCommon\n"); + #endif /* WOLFKM_DEBUG_AES */ +} + +static void wolfkdriv_identify(driver_t * driver, device_t parent) +{ + (void)driver; + + /* don't double add wolfkdriv child. */ + if (device_find_child(parent, "libwolf", -1) != NULL) { + return; + } + + BUS_ADD_CHILD(parent, 10, "libwolf", -1); +} + +static int wolfkdriv_probe(device_t dev) +{ + device_set_desc(dev, "wolfSSL crypto"); + return (BUS_PROBE_DEFAULT); +} + +/* + * unregister libwolfssl crypto driver + */ +static void wolfkdriv_unregister(struct wolfkdriv_softc * softc) +{ + if (softc && softc->crid >= 0) { + crypto_unregister_all(softc->crid); + device_printf(softc->dev, "info: crid unregistered: %d\n", softc->crid); + softc->crid = -1; + } + + return; +} + +static int wolfkdriv_attach(device_t dev) +{ + struct wolfkdriv_softc * softc = NULL; + int flags = CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC | + CRYPTOCAP_F_ACCEL_SOFTWARE | CRYPTOCAP_F_HARDWARE; + int ret = 0; + int crid = 0; + int error = 0; + + ret = wolfkmod_init(); + if (ret != 0) { + return (ECANCELED); + } + + /** + * register wolfcrypt algs here with crypto_get_driverid. + * + * The crid is the literal index into the kernel crypto_drivers array: + * - crid >= 0 is valid. + * - crid < 0 is error. + * */ + softc = device_get_softc(dev); + softc->dev = dev; + + softc->crid = crypto_get_driverid(dev, sizeof(wolfkdriv_session_t), flags); + if (softc->crid < 0) { + device_printf(dev, "error: crypto_get_driverid failed: %d\n", + softc->crid); + return (ENXIO); + } + + /* + * various sanity checks + */ + + /* 1. we should find ourself by name */ + crid = crypto_find_driver("libwolf"); + + if (crid != softc->crid) { + device_printf(dev, "error: attach: got crid %d, expected %d\n", crid, + softc->crid); + error = ENXIO; + goto attach_out; + } + + /* 2. test various algs */ + error = wolfkdriv_test_aes(dev, crid); + + if (error) { + device_printf(dev, "error: attach: test_aes: %d\n", error); + error = ENXIO; + goto attach_out; + } + + device_printf(dev, "info: driver loaded: %d\n", crid); + + #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) + device_printf(dev, "info: exiting attach\n"); + #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + +attach_out: + if (error) { + wolfkdriv_unregister(softc); + error = ENXIO; + } + + return (error); +} + +static int wolfkdriv_detach(device_t dev) +{ + struct wolfkdriv_softc * softc = NULL; + int ret = 0; + + ret = wolfkmod_cleanup(); + + if (ret == 0) { + /* unregister wolfcrypt algs */ + softc = device_get_softc(dev); + wolfkdriv_unregister(softc); + } + + #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) + device_printf(dev, "info: exiting detach\n"); + #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + + return (0); +} + +static int wolfkdriv_probesession(device_t dev, + const struct crypto_session_params *csp) +{ + struct wolfkdriv_softc * softc = NULL; + int error = CRYPTODEV_PROBE_ACCEL_SOFTWARE; + + softc = device_get_softc(dev); + + switch (csp->csp_mode) { + case CSP_MODE_CIPHER: + switch (csp->csp_cipher_alg) { + case CRYPTO_AES_CBC: + break; + default: + error = EINVAL; + break; + } + break; + + case CSP_MODE_AEAD: + switch (csp->csp_cipher_alg) { + case CRYPTO_AES_NIST_GCM_16: + break; + default: + error = EINVAL; + break; + } + break; + case CSP_MODE_DIGEST: + case CSP_MODE_ETA: + default: + error = EINVAL; + break; + } + + (void)softc; + (void)csp; + + #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) + device_printf(dev, "info: probesession: mode=%d, cipher_alg=%d, error=%d\n", + csp->csp_mode, csp->csp_cipher_alg, error); + #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + return (error); +} + +static int wolfkdriv_newsession_aes(device_t dev, + wolfkdriv_session_t * session, + const struct crypto_session_params *csp) +{ + int error = 0; + int klen = csp->csp_cipher_klen; /* key len in bytes */ + + switch (csp->csp_cipher_alg) { + case CRYPTO_AES_NIST_GCM_16: + session->type = CRYPTO_AES_NIST_GCM_16; + break; + case CRYPTO_AES_CBC: + session->type = CRYPTO_AES_CBC; + break; + default: + return (EOPNOTSUPP); + } + + if (klen != 16 && klen != 24 && klen != 32) { + device_printf(dev, "info: newsession_cipher: invalid klen: %d\n", klen); + return (EINVAL); + } + + session->klen = klen; + session->ivlen = csp->csp_ivlen; + + /* encrypt */ + error = wc_AesInit(&session->aes_ctx.aes_encrypt, NULL, INVALID_DEVID); + if (error) { + device_printf(dev, "error: newsession_cipher: aes init: %d\n", error); + goto newsession_cipher_out; + } + + if (session->type == CRYPTO_AES_CBC) { + /* Need a separate decrypt structure for aes-cbc. */ + error = wc_AesInit(&session->aes_ctx.aes_decrypt, NULL, INVALID_DEVID); + if (error) { + device_printf(dev, "error: newsession_cipher: aes init: %d\n", + error); + goto newsession_cipher_out; + } + } + +newsession_cipher_out: + + if (error != 0) { + wolfkdriv_aes_ctx_clear(&session->aes_ctx); + return (EINVAL); + } + + return (error); +} + +static int wolfkdriv_newsession(device_t dev, crypto_session_t cses, + const struct crypto_session_params *csp) +{ + wolfkdriv_session_t * session = NULL; + int error = 0; + + /* get the wolfkdriv_session_t context */ + session = crypto_get_driver_session(cses); + + switch (csp->csp_mode) { + case CSP_MODE_DIGEST: + case CSP_MODE_ETA: + device_printf(dev, "info: not supported: %d\n", csp->csp_mode); + error = EOPNOTSUPP; + break; + case CSP_MODE_CIPHER: + case CSP_MODE_AEAD: + error = wolfkdriv_newsession_aes(dev, session, csp); + break; + default: + __assert_unreachable(); + } + + #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) + device_printf(dev, "info: newsession: mode=%d, cipher_alg=%d, error=%d\n", + csp->csp_mode, csp->csp_cipher_alg, error); + #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + + return (error); +} + +static void +wolfkdriv_freesession(device_t dev, crypto_session_t cses) +{ + wolfkdriv_session_t * session = NULL; + (void)dev; + + /* get the wolfkdriv_session_t context */ + session = crypto_get_driver_session(cses); + + /* clean it up */ + wolfkdriv_aes_ctx_clear(&session->aes_ctx); + + #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) + device_printf(dev, "info: exiting freesession\n"); + #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + return; +} + +static int wolfkdriv_cbc_work(device_t dev, wolfkdriv_session_t * session, + struct cryptop * crp, + const struct crypto_session_params * csp) +{ + struct crypto_buffer_cursor cc_in; + struct crypto_buffer_cursor cc_out; + const unsigned char * in_block = NULL; + const unsigned char * in_seg = NULL; + unsigned char * out_block = NULL; + unsigned char * out_seg = NULL; + Aes aes; + uint8_t iv[WC_AES_BLOCK_SIZE]; + uint8_t block[EALG_MAX_BLOCK_LEN]; + size_t data_len = 0; + size_t seg_len = 0; + size_t in_len = 0; + size_t out_len = 0; + int error = 0; + int is_encrypt = 0; + int type = AES_ENCRYPTION; + + if (csp->csp_cipher_alg != CRYPTO_AES_CBC) { + error = EINVAL; + goto cbc_work_out; + } + + data_len = crp->crp_payload_length; + if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) { + is_encrypt = 1; + type = AES_ENCRYPTION; + memcpy(&aes, &session->aes_ctx.aes_encrypt, sizeof(aes)); + } + else { + is_encrypt = 0; + type = AES_DECRYPTION; + memcpy(&aes, &session->aes_ctx.aes_decrypt, sizeof(aes)); + } + + /* must be multiple of block size */ + if (data_len % WC_AES_BLOCK_SIZE) { + error = EINVAL; + goto cbc_work_out; + } + + crypto_read_iv(crp, iv); + error = wc_AesSetKey(&aes, csp->csp_cipher_key, + csp->csp_cipher_klen, iv, type); + if (error) { + device_printf(dev, "error: wc_AesSetKey: %d\n", error); + goto cbc_work_out; + } + + /* set up the crypto buffers */ + crypto_cursor_init(&cc_in, &crp->crp_buf); + crypto_cursor_advance(&cc_in, crp->crp_payload_start); + + in_seg = crypto_cursor_segment(&cc_in, &in_len); + + /* handle if the user supplied a separate out buffer. */ + if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { + crypto_cursor_init(&cc_out, &crp->crp_obuf); + crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); + } + else { + cc_out = cc_in; + } + + out_seg = crypto_cursor_segment(&cc_out, &out_len); + + while (data_len) { + /* set up input buffers */ + if (in_len < WC_AES_BLOCK_SIZE) { + /* less than a block in segment */ + crypto_cursor_copydata(&cc_in, WC_AES_BLOCK_SIZE, block); + in_block = block; + in_len = WC_AES_BLOCK_SIZE; + } + else { + in_block = in_seg; + } + + /* set up output buffers */ + if (out_len < WC_AES_BLOCK_SIZE) { + out_block = block; + out_len = WC_AES_BLOCK_SIZE; + } + else { + out_block = out_seg; + } + + /* choose which of data_len, in_len, out_len, is shorter. + * round down to multiple of aes block size. */ + seg_len = rounddown(MIN(data_len, MIN(in_len, out_len)), + WC_AES_BLOCK_SIZE); + + if (is_encrypt) { + error = wc_AesCbcEncrypt(&aes, out_block, in_block, seg_len); + if (error) { + device_printf(dev, "error: wc_AesCbcEncrypt: %d\n", error); + goto cbc_work_out; + } + } + else { + error = wc_AesCbcDecrypt(&aes, out_block, in_block, seg_len); + if (error) { + device_printf(dev, "error: wc_AesCbcEncrypt: %d\n", error); + goto cbc_work_out; + } + } + + if (out_block == block) { + /* we used the block as local output buffer. copy to cc_out, + * and grab the next out cursor segment. */ + crypto_cursor_copyback(&cc_out, WC_AES_BLOCK_SIZE, block); + out_seg = crypto_cursor_segment(&cc_out, &out_len); + } else { + /* we worked directly in cc_out. advance the cursor. */ + crypto_cursor_advance(&cc_out, seg_len); + out_seg += seg_len; + out_len -= seg_len; + } + + if (in_block == block) { + /* grab a new in cursor segment. */ + in_seg = crypto_cursor_segment(&cc_in, &in_len); + } else { + /* else advance existing in cursor. */ + crypto_cursor_advance(&cc_in, seg_len); + in_seg += seg_len; + in_len -= seg_len; + } + + data_len -= seg_len; + } + +cbc_work_out: + /* cleanup. */ + wc_ForceZero(iv, sizeof(iv)); + wc_ForceZero(block, sizeof(block)); + + #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) + device_printf(dev, "info: cbc_work: mode=%d, cipher_alg=%d, " + "payload_length=%d, error=%d\n", + csp->csp_mode, csp->csp_cipher_alg, crp->crp_payload_length, + error); + #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + + return (error); +} + +static int wolfkdriv_gcm_work(device_t dev, wolfkdriv_session_t * session, + struct cryptop * crp, + const struct crypto_session_params * csp) +{ + struct crypto_buffer_cursor cc_in; + struct crypto_buffer_cursor cc_out; + const unsigned char * in_seg = NULL; + unsigned char * out_seg = NULL; + Aes aes; + uint8_t iv[WC_AES_BLOCK_SIZE]; + uint8_t auth_tag[WC_AES_BLOCK_SIZE]; + size_t data_len = 0; + size_t seg_len = 0; + size_t in_len = 0; + size_t out_len = 0; + int error = 0; + int is_encrypt = 0; + + memcpy(&aes, &session->aes_ctx.aes_encrypt, sizeof(aes)); + + if (csp->csp_cipher_alg != CRYPTO_AES_NIST_GCM_16) { + error = EINVAL; + goto gcm_work_out; + } + + data_len = crp->crp_payload_length; + if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) { + is_encrypt = 1; + } + else { + is_encrypt = 0; + } + + error = wc_AesGcmSetKey(&aes, csp->csp_cipher_key, + csp->csp_cipher_klen); + if (error) { + device_printf(dev, "error: wc_AesGcmSetKey: %d\n", error); + goto gcm_work_out; + } + + crypto_read_iv(crp, iv); + error = wc_AesGcmInit(&aes, NULL /* key */, 0 /* keylen */, + iv, csp->csp_ivlen); + if (error) { + device_printf(dev, "error: wc_AesGcmInit: %d\n", error); + goto gcm_work_out; + } + + /* process aad first */ + if (crp->crp_aad != NULL) { + /* they passed aad in separate buffer. */ + if (is_encrypt) { + error = wc_AesGcmEncryptUpdate(&aes, NULL, NULL, 0, + crp->crp_aad, crp->crp_aad_length); + } + else { + error = wc_AesGcmDecryptUpdate(&aes, NULL, NULL, 0, + crp->crp_aad, crp->crp_aad_length); + } + + if (error) { + error = EINVAL; + } + } + else { + /* we need to pull aad out of crp->crp_buf from crp_aad_start. */ + size_t aad_len = 0; + + crypto_cursor_init(&cc_in, &crp->crp_buf); + crypto_cursor_advance(&cc_in, crp->crp_aad_start); + + for (aad_len = crp->crp_aad_length; aad_len > 0; aad_len -= seg_len) { + in_seg = crypto_cursor_segment(&cc_in, &in_len); + seg_len = MIN(aad_len, in_len); + + if (is_encrypt) { + error = wc_AesGcmEncryptUpdate(&aes, NULL, NULL, 0, + in_seg, seg_len); + } + else { + error = wc_AesGcmDecryptUpdate(&aes, NULL, NULL, 0, + in_seg, seg_len); + } + + if (error) { + error = EINVAL; + goto gcm_work_out; + } + + crypto_cursor_advance(&cc_in, seg_len); + } + } + + /* + * process cipher/plaintext next + */ + + /* set up the crypto buffers */ + crypto_cursor_init(&cc_in, &crp->crp_buf); + crypto_cursor_advance(&cc_in, crp->crp_payload_start); + + in_seg = crypto_cursor_segment(&cc_in, &in_len); + + /* handle if the user supplied a separate out buffer. */ + if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { + crypto_cursor_init(&cc_out, &crp->crp_obuf); + crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); + } + else { + cc_out = cc_in; + } + + out_seg = crypto_cursor_segment(&cc_out, &out_len); + + while (data_len) { + /* process through the available segments. */ + in_seg = crypto_cursor_segment(&cc_in, &in_len); + out_seg = crypto_cursor_segment(&cc_out, &out_len); + seg_len = MIN(data_len, MIN(in_len, out_len)); + + if (is_encrypt) { + error = wc_AesGcmEncryptUpdate(&aes, out_seg, in_seg, seg_len, + NULL, 0); + if (error) { + device_printf(dev, "error: wc_AesGcmEncrypt: %d\n", error); + goto gcm_work_out; + } + } + else { + error = wc_AesGcmDecryptUpdate(&aes, out_seg, in_seg, seg_len, + NULL, 0); + if (error) { + device_printf(dev, "error: wc_AesGcmDecrypt: %d\n", error); + goto gcm_work_out; + } + } + + /* advance the cursors by amount processed */ + crypto_cursor_advance(&cc_in, seg_len); + crypto_cursor_advance(&cc_out, seg_len); + + data_len -= seg_len; + } + + /* process auth tag finally */ + if (is_encrypt) { + error = wc_AesGcmEncryptFinal(&aes, auth_tag, WC_AES_BLOCK_SIZE); + if (error == 0) { + crypto_copyback(crp, crp->crp_digest_start, WC_AES_BLOCK_SIZE, + auth_tag); + } + } + else { + crypto_copydata(crp, crp->crp_digest_start, WC_AES_BLOCK_SIZE, + auth_tag); + error = wc_AesGcmDecryptFinal(&aes, auth_tag, WC_AES_BLOCK_SIZE); + if (error) { + error = EBADMSG; + } + } + +gcm_work_out: + /* cleanup. */ + wc_ForceZero(iv, sizeof(iv)); + wc_ForceZero(auth_tag, sizeof(auth_tag)); + + #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) + device_printf(dev, "info: gcm_work: mode=%d, cipher_alg=%d, " + "payload_length=%d, error=%d\n", + csp->csp_mode, csp->csp_cipher_alg, crp->crp_payload_length, + error); + #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + + return (error); +} + +static int wolfkdriv_process(device_t dev, struct cryptop * crp, int hint) +{ + const struct crypto_session_params * csp = NULL; + wolfkdriv_session_t * session = NULL; + int error = 0; + (void)hint; + + session = crypto_get_driver_session(crp->crp_session); + csp = crypto_get_params(crp->crp_session); + + switch (csp->csp_mode) { + case CSP_MODE_CIPHER: + error = wolfkdriv_cbc_work(dev, session, crp, csp); + break; + case CSP_MODE_DIGEST: + case CSP_MODE_ETA: + error = EINVAL; + break; + case CSP_MODE_AEAD: + error = wolfkdriv_gcm_work(dev, session, crp, csp); + break; + default: + __assert_unreachable(); + } + + crp->crp_etype = error; + crypto_done(crp); + + #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) + device_printf(dev, "info: process: mode=%d, cipher_alg=%d, error=%d\n", + csp->csp_mode, csp->csp_cipher_alg, error); + #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + + return (error); +} + +/* + * wolfkmod as a crypto device driver. + */ +static device_method_t wolfkdriv_methods[] = { + /* device interface methods: called during device setup, etc. */ + DEVMETHOD(device_identify, wolfkdriv_identify), + DEVMETHOD(device_probe, wolfkdriv_probe), + DEVMETHOD(device_attach, wolfkdriv_attach), + DEVMETHOD(device_detach, wolfkdriv_detach), + + /* crypto device session methods: called during crypto session setup, + * work, etc. */ + DEVMETHOD(cryptodev_probesession, wolfkdriv_probesession), + DEVMETHOD(cryptodev_newsession, wolfkdriv_newsession), + DEVMETHOD(cryptodev_freesession, wolfkdriv_freesession), + DEVMETHOD(cryptodev_process, wolfkdriv_process), + + DEVMETHOD_END +}; + +static driver_t wolfkdriv_driver = { + .name = "libwolf", + .methods = wolfkdriv_methods, + .size = sizeof(struct wolfkdriv_softc), +}; + +/* on x86, software-only drivers usually attach to nexus bus. */ +DRIVER_MODULE(libwolfssl, nexus, wolfkdriv_driver, NULL, NULL); +#endif /* BSDKM_CRYPTO_REGISTER */ + +#if !defined(BSDKM_CRYPTO_REGISTER) +/* + * wolfkmod as a pure kernel module. + */ static moduledata_t libwolfmod = { #ifdef HAVE_FIPS "libwolfssl_fips", /* module name */ @@ -305,6 +1066,8 @@ static moduledata_t libwolfmod = { NULL /* extra data, unused */ }; -MODULE_VERSION(libwolfssl, 1); DECLARE_MODULE(libwolfssl, libwolfmod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); +#endif /* !BSDKM_CRYPTO_REGISTER */ + +MODULE_VERSION(libwolfssl, 1); #endif /* WOLFSSL_BSDKM */ diff --git a/bsdkm/wolfkmod_aes.c b/bsdkm/wolfkmod_aes.c new file mode 100644 index 0000000000..9fb776e988 --- /dev/null +++ b/bsdkm/wolfkmod_aes.c @@ -0,0 +1,347 @@ +#if !defined(WC_SKIP_INCLUDED_C_FILES) && defined(BSDKM_CRYPTO_REGISTER) +#include + +/* + * the cryptodev framework always calls a callback, even when CRYPTOCAP_F_SYNC. + */ +static int +wolfkdriv_test_crp_callback(struct cryptop * crp) +{ + (void)crp; + return (0); +} + +/* Test aes-cbc with a buffer larger than aes block size. + * Verify direct wolfcrypt API and opencrypto framework return + * same result. */ +static int wolfkdriv_test_aes_cbc_big(device_t dev, int crid) +{ + crypto_session_t session = NULL; + struct crypto_session_params csp; + struct cryptop * crp = NULL; + Aes * aes_encrypt = NULL; + int error = 0; + byte msg[] = { + 0x6e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x6e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x6e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20 + }; + byte work1[WC_AES_BLOCK_SIZE * 3]; /* wolfcrypt buffer */ + byte work2[WC_AES_BLOCK_SIZE * 3]; /* opencrypto buffer */ + /* padded to 16-bytes */ + const byte key[] = "0123456789abcdef "; + /* padded to 16-bytes */ + const byte iv[] = "1234567890abcdef "; + + memset(&csp, 0, sizeof(csp)); + memcpy(work1, msg, sizeof(msg)); /* wolfcrypt work buffer */ + memcpy(work2, msg, sizeof(msg)); /* opencrypto work buffer */ + + /* wolfcrypt encrypt */ + aes_encrypt = (Aes *)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_AES); + if (aes_encrypt == NULL) { + error = ENOMEM; + device_printf(dev, "error: malloc failed\n"); + goto test_aes_cbc_big_out; + } + + error = wc_AesInit(aes_encrypt, NULL, INVALID_DEVID); + if (error) { + device_printf(dev, "error: newsession_cipher: aes init: %d\n", error); + goto test_aes_cbc_big_out; + } + + error = wc_AesSetKey(aes_encrypt, key, 16, iv, AES_ENCRYPTION); + if (error) { + device_printf(dev, "error: wc_AesSetKey: %d\n", error); + goto test_aes_cbc_big_out; + } + + error = wc_AesCbcEncrypt(aes_encrypt, work1, work1, sizeof(work1)); + if (error) { + device_printf(dev, "error: wc_AesCbcEncrypt: %d\n", error); + goto test_aes_cbc_big_out; + } + + /* opencrypto encrypt */ + csp.csp_mode = CSP_MODE_CIPHER; + csp.csp_cipher_alg = CRYPTO_AES_CBC; + csp.csp_ivlen = WC_AES_BLOCK_SIZE; + csp.csp_cipher_key = key; + csp.csp_cipher_klen = WC_AES_BLOCK_SIZE; + error = crypto_newsession(&session, &csp, crid); + if (error || session == NULL) { + goto test_aes_cbc_big_out; + } + + crp = crypto_getreq(session, M_WAITOK); + if (crp == NULL) { + device_printf(dev, "error: test_aes: crypto_getreq failed\n"); + goto test_aes_cbc_big_out; + } + + crp->crp_callback = wolfkdriv_test_crp_callback; + crp->crp_op = CRYPTO_OP_ENCRYPT; + crp->crp_flags = CRYPTO_F_IV_SEPARATE; + + memcpy(crp->crp_iv, iv, WC_AES_BLOCK_SIZE); + + crypto_use_buf(crp, work2, sizeof(work2)); + crp->crp_payload_start = 0; + crp->crp_payload_length = sizeof(work2); + + error = crypto_dispatch(crp); + if (error) { + goto test_aes_cbc_big_out; + } + + error = XMEMCMP(work1, work2, sizeof(work2)); + if (error) { + device_printf(dev, "error: test_aes: enc vectors diff: %d\n", error); + goto test_aes_cbc_big_out; + } + + /* opencrypto decrypt */ + crp->crp_op = CRYPTO_OP_DECRYPT; + + error = crypto_dispatch(crp); + if (error) { + goto test_aes_cbc_big_out; + } + + error = XMEMCMP(work2, msg, sizeof(msg)); + if (error) { + device_printf(dev, "error: test_aes: dec vectors diff: %d\n", error); + goto test_aes_cbc_big_out; + } + +test_aes_cbc_big_out: + #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) + device_printf(dev, "info: test_aes_cbc_big: error=%d, session=%p, crp=%p\n", + error, (void *)session, (void*)crp); + #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + + if (crp != NULL) { + crypto_freereq(crp); + crp = NULL; + } + + if (session != NULL) { + crypto_freesession(session); + session = NULL; + } + + if (aes_encrypt != NULL) { + wc_AesFree(aes_encrypt); + XFREE(aes_encrypt, NULL, DYNAMIC_TYPE_AES); + aes_encrypt = NULL; + } + + return (error); +} + +/* Test aes-gcm encrypt and decrypt a small buffer with opencrypto + * framework and wolfcrypt. + */ +static int wolfkdriv_test_aes_gcm(device_t dev, int crid) +{ + crypto_session_t session = NULL; + struct crypto_session_params csp; + struct cryptop * crp = NULL; + Aes * enc = NULL; + int error = 0; + + WOLFSSL_SMALL_STACK_STATIC const byte p[] = + { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 + }; + + WOLFSSL_SMALL_STACK_STATIC const byte c1[] = + { + 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62 + }; + + WOLFSSL_SMALL_STACK_STATIC byte a[] = + { + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 + }; + + WOLFSSL_SMALL_STACK_STATIC const byte k1[] = + { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 + }; + + WOLFSSL_SMALL_STACK_STATIC const byte iv1[] = + { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 + }; + + WOLFSSL_SMALL_STACK_STATIC const byte t1[] = + { + 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, + 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b + }; + + byte resultT[sizeof(t1) + WC_AES_BLOCK_SIZE]; + byte resultC[sizeof(p) + WC_AES_BLOCK_SIZE]; + byte resultC2[sizeof(p) + WC_AES_BLOCK_SIZE]; + + XMEMSET(resultT, 0, sizeof(resultT)); + XMEMSET(resultC, 0, sizeof(resultC)); + + XMEMSET(resultC2, 0, sizeof(resultC)); + XMEMCPY(resultC2, p, sizeof(p)); + + /* wolfcrypt encrypt */ + enc = (Aes *)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_AES); + if (enc == NULL) { + error = ENOMEM; + device_printf(dev, "error: malloc failed\n"); + goto test_aes_gcm_out; + } + + error = wc_AesGcmEncryptInit(enc, k1, sizeof(k1), iv1, sizeof(iv1)); + if (error) { goto test_aes_gcm_out; } + + error = wc_AesGcmEncryptUpdate(enc, resultC, p, sizeof(p), a, sizeof(a)); + if (error) { goto test_aes_gcm_out; } + + error = wc_AesGcmEncryptFinal(enc, resultT, sizeof(t1)); + if (error) { goto test_aes_gcm_out; } + + error = XMEMCMP(resultC, c1, sizeof(c1)); + if (error) { goto test_aes_gcm_out; } + + error = XMEMCMP(resultT, t1, sizeof(t1)); + if (error) { goto test_aes_gcm_out; } + + /* + * opencrypto encrypt + * */ + + /* set crypto session params */ + memset(&csp, 0, sizeof(csp)); + csp.csp_flags |= CSP_F_SEPARATE_AAD; + csp.csp_mode = CSP_MODE_AEAD; + csp.csp_cipher_alg = CRYPTO_AES_NIST_GCM_16; + csp.csp_ivlen = sizeof(iv1); + csp.csp_cipher_key = k1; + csp.csp_cipher_klen = sizeof(k1); + + /* get crypto session handle */ + error = crypto_newsession(&session, &csp, crid); + if (error || session == NULL) { + device_printf(dev, "error: test_aes: crypto_newsession: %d, %p\n", + error, (void *)session); + goto test_aes_gcm_out; + } + + /* get a crypto op handle */ + crp = crypto_getreq(session, M_WAITOK); + if (crp == NULL) { + device_printf(dev, "error: test_aes: crypto_getreq failed\n"); + goto test_aes_gcm_out; + } + + /* configure it */ + crp->crp_callback = wolfkdriv_test_crp_callback; + crp->crp_op = (CRYPTO_OP_ENCRYPT | CRYPTO_OP_COMPUTE_DIGEST); + crp->crp_flags = CRYPTO_F_IV_SEPARATE; + + memcpy(crp->crp_iv, iv1, sizeof(iv1)); + + crypto_use_buf(crp, resultC2, sizeof(resultC2)); + crp->crp_payload_start = 0; + crp->crp_payload_length = sizeof(p); + + crp->crp_aad = a; + crp->crp_aad_start = 0; + crp->crp_aad_length = sizeof(a); + crp->crp_digest_start = crp->crp_payload_start + sizeof(p); + + error = crypto_dispatch(crp); + if (error) { + goto test_aes_gcm_out; + } + + error = XMEMCMP(resultC2, c1, sizeof(c1)); + if (error) { goto test_aes_gcm_out; } + + error = XMEMCMP(resultC2 + sizeof(p), t1, sizeof(t1)); + if (error) { goto test_aes_gcm_out; } + + /* opencrypto decrypt */ + crp->crp_op = (CRYPTO_OP_DECRYPT | CRYPTO_OP_VERIFY_DIGEST); + + error = crypto_dispatch(crp); + if (error) { + goto test_aes_gcm_out; + } + + error = XMEMCMP(resultC2, p, sizeof(p)); + if (error) { goto test_aes_gcm_out; } + +test_aes_gcm_out: + #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) + device_printf(dev, "info: test_aes_gcm: error=%d, session=%p, crp=%p\n", + error, (void *)session, (void*)crp); + #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + + if (crp != NULL) { + crypto_freereq(crp); + crp = NULL; + } + + if (session != NULL) { + crypto_freesession(session); + session = NULL; + } + + if (enc != NULL) { + wc_AesFree(enc); + XFREE(enc, NULL, DYNAMIC_TYPE_AES); + enc = NULL; + } + + return (error); +} + + +static int wolfkdriv_test_aes(device_t dev, int crid) +{ + int error = 0; + + if (error == 0) { + error = wolfkdriv_test_aes_cbc_big(dev, crid); + } + + if (error == 0) { + error = wolfkdriv_test_aes_gcm(dev, crid); + } + + return (error); +} +#endif /* !WC_SKIP_INCLUDED_C_FILES && BSDKM_CRYPTO_REGISTER */ diff --git a/bsdkm/x86_vecreg.c b/bsdkm/x86_vecreg.c new file mode 100644 index 0000000000..7b58c84f65 --- /dev/null +++ b/bsdkm/x86_vecreg.c @@ -0,0 +1,225 @@ +/* x86_vecreg.c -- logic to save and restore vector registers + * on amd64 in FreeBSD kernel. + * + * Copyright (C) 2006-2025 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 3 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 + */ + +/* included by bsdkm/wolfkmod.c */ +#ifndef WC_SKIP_INCLUDED_C_FILES + +#include +#include +#include +#include + +struct wolfkmod_fpu_state_t { + volatile lwpid_t td_tid; + volatile u_int nest; +}; + +typedef struct wolfkmod_fpu_state_t wolfkmod_fpu_state_t; + +/* fpu_states array tracks thread id and nesting level of save/restore + * and push/pop vector registers macro calls. It is indexed by raw cpu id, + * and only accessed after the thread calls fpu_kern_enter(), and before + * calling fpu_kern_leave(), and only indexed by the thread's PCPU_GET(cpuid). + * + * after calling fpu_kern_enter(): + * - kernel fpu is enabled + * - migration is disabled + * - soft preempts are disabled + * Hard irq are still possible , but hard irq are forbidden from using FPU + * in FreeBSD kernel. + * */ +static wolfkmod_fpu_state_t * fpu_states = NULL; + +/* check for active td_tid with atomic before proceeding. + * technically not necessary because fpu_kern_enter() gives thread pinning + * to cpu, but just to be safe... + * */ +#define wolfkmod_fpu_get_tid() \ + atomic_load_acq_int(&fpu_states[PCPU_GET(cpuid)].td_tid) + +int wolfkmod_vecreg_init(void) +{ + if (mp_ncpus <= 0) { + printf("error: wolfkmod_vecreg_init: mp_ncpus = %d\n", mp_ncpus); + return (EINVAL); + } + + fpu_states = malloc(mp_ncpus * sizeof(wolfkmod_fpu_state_t), + M_WOLFSSL, M_WAITOK | M_ZERO); + if (fpu_states == NULL) { + printf("error: wolfkmod_vecreg_init: malloc(%lu) failed\n", + mp_ncpus * sizeof(wolfkmod_fpu_state_t)); + return (ENOMEM); + } + + return (0); +} + +void wolfkmod_vecreg_exit(void) +{ + int i = 0; + + if (fpu_states == NULL) { + return; + } + + for (i = 0; i < mp_ncpus; ++i) { + #if defined(WOLFSSL_BSDKM_FPU_DEBUG) + printf("info: wolfkmod_vecreg_exit: fpu_states[%d] = %d, %d\n", + i, fpu_states[i].nest, fpu_states[i].td_tid); + #endif /* WOLFSSL_BSDKM_FPU_DEBUG */ + + if (fpu_states[i].nest != 0 || fpu_states[i].td_tid != 0) { + /* Check for orphaned fpu state. There's nothing we can do + * but log the event and zero the nesting level. */ + printf("error: wolfkmod_vecreg_exit: fpu_states[%d] = %d, %d\n", + i, fpu_states[i].nest, fpu_states[i].td_tid); + fpu_states[i].nest = 0; + } + } + + free(fpu_states, M_WOLFSSL); + fpu_states = NULL; + + return; +} + +/* fpu_kern_enter() and fpu_kern_leave() wrapper defines. + * Build with WOLFSSL_BSDKM_FPU_DEBUG to see verbose FPU logging. + */ +#if defined(WOLFSSL_BSDKM_FPU_DEBUG) + #define wolfkmod_print_curthread(what) \ + printf("%s: cpuid = %d, curthread: td_tid = %d, pid = %d (%s), " \ + "td_critnest = %d, kernfpu = %02x\n", \ + (what), PCPU_GET(cpuid), curthread->td_tid, \ + curthread->td_proc ? curthread->td_proc->p_pid : -1, \ + curthread->td_proc ? curthread->td_proc->p_comm : "noproc", \ + curthread->td_critnest, \ + curthread->td_pcb->pcb_flags & PCB_KERNFPU); + + #define wolfkmod_fpu_kern_enter() \ + wolfkmod_print_curthread("fpu_kern_enter"); \ + fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); + + #define wolfkmod_fpu_kern_leave() \ + wolfkmod_print_curthread("fpu_kern_leave"); \ + fpu_kern_leave(curthread, NULL); +#else + #define wolfkmod_fpu_kern_enter() \ + fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); + + #define wolfkmod_fpu_kern_leave() \ + fpu_kern_leave(curthread, NULL); +#endif /* WOLFSSL_BSDKM_FPU_DEBUG */ + +int wolfkmod_vecreg_save(int flags_unused) +{ + (void)flags_unused; + + #if defined(WOLFSSL_BSDKM_FPU_DEBUG) + wolfkmod_print_curthread("wolfkmod_vecreg_save"); + #endif + + if (is_fpu_kern_thread(0)) { + /* kernel fpu threads are special, do nothing. They own a + * persistent, dedicated fpu context. */ + #if defined(WOLFSSL_BSDKM_FPU_DEBUG) + printf("info: wolfkmod_vecreg_save: is fpu kern thread\n"); + #endif + return (0); + } + + if (curthread->td_pcb->pcb_flags & PCB_KERNFPU) { + /* kern fpu is active for this thread. check td_tid and + * increment nesting level. */ + lwpid_t td_tid = wolfkmod_fpu_get_tid(); + if (td_tid != curthread->td_tid) { + printf("error: wolfkmod_vecreg_save: got tid = %d, expected %d\n", + td_tid, curthread->td_tid); + return (EINVAL); + } + fpu_states[PCPU_GET(cpuid)].nest++; + } + else { + /* kern fpu not active for this thread, call fpu_kern_enter(). + * after calling fpu_kern_enter(): + * - kernel fpu is enabled + * - migration is disabled + * - soft preempts are disabled */ + lwpid_t td_tid = 0; + wolfkmod_fpu_kern_enter(); + td_tid = wolfkmod_fpu_get_tid(); + + if (fpu_states[PCPU_GET(cpuid)].nest != 0 || td_tid != 0) { + printf("error: wolfkmod_fpu_kern_enter() with nest: %d, %d\n", + fpu_states[PCPU_GET(cpuid)].nest, td_tid); + return (EINVAL); + } + + /* increment nest and save td_tid. */ + fpu_states[PCPU_GET(cpuid)].nest++; + fpu_states[PCPU_GET(cpuid)].td_tid = curthread->td_tid; + } + + return (0); +} + +void wolfkmod_vecreg_restore(void) +{ + #if defined(WOLFSSL_BSDKM_FPU_DEBUG) + wolfkmod_print_curthread("wolfkmod_vecreg_restore"); + #endif + + if (is_fpu_kern_thread(0)) { + /* kernel fpu threads are special, do nothing. They own a + * persistent, dedicated fpu context. */ + #if defined(WOLFSSL_BSDKM_FPU_DEBUG) + printf("info: wolfkmod_vecreg_restore: is fpu kern thread\n"); + #endif + return; + } + + if (curthread->td_pcb->pcb_flags & PCB_KERNFPU) { + /* kern fpu is active for this thread. check tid and nesting level. */ + lwpid_t td_tid = wolfkmod_fpu_get_tid(); + if (td_tid != curthread->td_tid) { + printf("error: wolfkmod_vecreg_restore: got tid = %d, " + "expected %d\n", td_tid, curthread->td_tid); + return; + } + + /* decrement the nesting level. */ + if (fpu_states[PCPU_GET(cpuid)].nest > 0) { + fpu_states[PCPU_GET(cpuid)].nest--; + } + + /* if last level, zero the thread id then call fpu_kern_leave */ + if (fpu_states[PCPU_GET(cpuid)].nest == 0) { + fpu_states[PCPU_GET(cpuid)].td_tid = 0; + wolfkmod_fpu_kern_leave(); + } + } + + return; +} + +#endif /* !WC_SKIP_INCLUDED_C_FILES */ diff --git a/certs/aia/ca-issuers-cert.pem b/certs/aia/ca-issuers-cert.pem new file mode 100644 index 0000000000..22630fc366 --- /dev/null +++ b/certs/aia/ca-issuers-cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDUDCCAjigAwIBAgIUQy4lyOzJcvFVekNsQWuUegW0kGgwDQYJKoZIhvcNAQEL +BQAwGzEZMBcGA1UEAwwQd29sZnNzbC1haWEtdGVzdDAeFw0yNjAxMjYyMzE1NTZa +Fw0yNzAxMjYyMzE1NTZaMBsxGTAXBgNVBAMMEHdvbGZzc2wtYWlhLXRlc3QwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDM1vUyiX+qtPFhhEqZq3bCUKpd +6QtswO7YWj+us79yh99mIGE7EZlSfTv0n3rn2//m5bQ7a+TSYMkDyNjPEH6Z+ub2 +qW4EJyc4J9DfC+T9gJM4dvsij+F8TUne/o5iCwFdiZEycEj0vtyYh53du3oqlZTY +yt8q4k5INoTl+ELCX/L0YqR/+Fl2qaloK7YHUb3EdSqBEGoa/IEfnxHMreZWhVYd +pSdDnT9rfNqT5Kb2e+eZbZZSouEmebhx9ioRfIXDadSCCa1JNp4fO3YlcDmmEahx +6TcjEmhUt80+hjhJhqrh4vPlxI24qHmfOe+k2qSimpJse/AUuz7wGRjx6ktfAgMB +AAGjgYswgYgwHQYDVR0OBBYEFMvT3KE5dvI6t3KNrcuctkm6wvXMMB8GA1UdIwQY +MBaAFMvT3KE5dvI6t3KNrcuctkm6wvXMMA8GA1UdEwEB/wQFMAMBAf8wNQYIKwYB +BQUHAQEEKTAnMCUGCCsGAQUFBzAChhlodHRwOi8vZXhhbXBsZS5jb20vY2EucGVt +MA0GCSqGSIb3DQEBCwUAA4IBAQCjxEHOlxVfmE8xgcQCnr1b4IK5EBuIMUaS7lko +AHmHvj7z9rr2cxbJhGYQxcttZ4/SQldRqpmiB0cUmko4LbD9yos4FKlyGe3xWvKa +W17SdpJU2PREShGLLqP7bwiWV6wVyo6puwDHLYSjH5vYr+IcSNNc0GuMZg1OhTWt +2PYG2vGbHoNR0/UyNibGmaPBimg0nb2GTizY7yWm+N/yXnWa6Wc5yyiF1zExw/GO +8O/rF0Lg/Gy/v6LnnNmhSOr9ENPKgQEAHFmJRXBXqDYUNhcm2U3PzlfBa06SHFcr +b59n5jgJmcNSwYDJAYKEhMvjBL40DmiWaRfol2DPoIZ7YtRf +-----END CERTIFICATE----- diff --git a/certs/aia/multi-aia-cert.pem b/certs/aia/multi-aia-cert.pem new file mode 100644 index 0000000000..d0722788f1 --- /dev/null +++ b/certs/aia/multi-aia-cert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDwTCCAqmgAwIBAgIUEcNoHSMtIkVhW/MmkmUEsVoJVQEwDQYJKoZIhvcNAQEL +BQAwITEfMB0GA1UEAwwWd29sZnNzbC1haWEtbXVsdGktdGVzdDAeFw0yNjAxMjcw +MTUwNDRaFw0yNzAxMjcwMTUwNDRaMCExHzAdBgNVBAMMFndvbGZzc2wtYWlhLW11 +bHRpLXRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpVdogPQ2I +/nErbxSaNGoYhkwoj1qt+Be1/qWnvZzJ0EBOG4EdioMRIkJzP6W3HoAhkGBrueXf +riN07M3XLocRfE+9C1+jZQxBGRxysns9z7K+i0pBtPN/AXV2RCSz13FFyVyLhLks +2YAL9By36X9R0wsL+Nd4EAQ4ouf0GglmTmtb5rHf2GIno4xFg9tpWosiUTytwgDC +K9lQEQnTnPG6E43N2bszqBc4roOPrYDnd7raNTqcv9yTHM8zwffGJuCogE/Fbr2R +yVubLW28n5/O1Pb47hHuPJv6oHMZgct2SV5OB/mwVgI0eoFMSQZ35o6BpHD0C497 +L2IcoMi8A9rFAgMBAAGjgfAwge0wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAoQw +gbAGCCsGAQUFBwEBBIGjMIGgMCIGCCsGAQUFBzABhhZodHRwOi8vMTI3LjAuMC4x +OjIyMjIxMCIGCCsGAQUFBzABhhZodHRwOi8vMTI3LjAuMC4xOjIyMjIyMCkGCCsG +AQUFBzAChh1odHRwOi8vd3d3LndvbGZzc2wuY29tL2NhLnBlbTArBggrBgEFBQcw +AoYfaHR0cHM6Ly93d3cud29sZnNzbC5jb20vY2EyLnBlbTAdBgNVHQ4EFgQU1GNm +eP/LXQk0tFaTeWoNHyLhLZkwDQYJKoZIhvcNAQELBQADggEBACwuXdKYI2Q/Vhd7 +TJFvKdp7BuUopQGEQ+4vR+FoesYXc9MHjZJfMqEffv1MArTeY46At/zvcTeszagi +io+jjGBLOutsAf9WK3PnKMIkGGfro6btZ8QFyKiZ6unMMlqe6cGqrCrNKp8jLP3k +CKZltR5c+MIPhpjoOhNDMOcPMwZBGQJWubwOb4uOu3wv7UWJk/ovKP9WJCUn6wLH +soDs+MHMICkxOvDfPf+F4URVqTbzE8IvSMv38z4cAqsyEfWxr32Dg34S/NmeePFV +7sSDpksvyITGsxjnQulSuUFSmldumQ6GnA4ZUXvCNdJ0zbD/Iib9ud6K05VdWYZP +uyCRkjY= +-----END CERTIFICATE----- diff --git a/certs/aia/overflow-aia-cert.pem b/certs/aia/overflow-aia-cert.pem new file mode 100644 index 0000000000..1054df14ea --- /dev/null +++ b/certs/aia/overflow-aia-cert.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEcDCCA1igAwIBAgIUN5kIU1GLRP5bRKctP271p7IGFVowDQYJKoZIhvcNAQEL +BQAwJDEiMCAGA1UEAwwZd29sZnNzbC1haWEtb3ZlcmZsb3ctdGVzdDAeFw0yNjAx +MjcwMTU1NTBaFw0yNzAxMjcwMTU1NTBaMCQxIjAgBgNVBAMMGXdvbGZzc2wtYWlh +LW92ZXJmbG93LXRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS +eHeAzVuCe44SU8bcyIWLwkA2AABw/ctSBWKAFEd7DYHduRr3diblHERU1Fv5JzYx +JnZquj1IO/qsnSFJYDc9sQmYea89iW8KNPVXKDzdbzhpiQLZL7Yq71ICxxqVLfRr +91lyAj0+Syncrp96olSpMJochVnQ6PqLcc/Gq7CMtrKn5KAN7Mn3+LdAQYU8JjRa +zqEJ8fmkBKbS5watzgnkP2o5jWSpWzpDOxTdw85hju4H9m5Gmun3XVO9dEAN/dqK +vklkzgQGvAMMQMIcgOzw0HxAuvsSNtjgEpIlOir0M7YiC0pYqtMO+thSCmVCvsDR +/nG/iqe6YBSXh6oszGwTAgMBAAGjggGYMIIBlDAMBgNVHRMEBTADAQH/MAsGA1Ud +DwQEAwIChDCCAVYGCCsGAQUFBwEBBIIBSDCCAUQwIgYIKwYBBQUHMAGGFmh0dHA6 +Ly8xMjcuMC4wLjE6MjIyMjAwIgYIKwYBBQUHMAGGFmh0dHA6Ly8xMjcuMC4wLjE6 +MjIyMjEwIgYIKwYBBQUHMAGGFmh0dHA6Ly8xMjcuMC4wLjE6MjIyMjIwIgYIKwYB +BQUHMAGGFmh0dHA6Ly8xMjcuMC4wLjE6MjIyMjMwIgYIKwYBBQUHMAGGFmh0dHA6 +Ly8xMjcuMC4wLjE6MjIyMjQwIgYIKwYBBQUHMAGGFmh0dHA6Ly8xMjcuMC4wLjE6 +MjIyMjUwIgYIKwYBBQUHMAGGFmh0dHA6Ly8xMjcuMC4wLjE6MjIyMjYwIgYIKwYB +BQUHMAGGFmh0dHA6Ly8xMjcuMC4wLjE6MjIyMjcwIgYIKwYBBQUHMAGGFmh0dHA6 +Ly8xMjcuMC4wLjE6MjIyMjgwHQYDVR0OBBYEFJt6TNgqMFBebotXaauIYPpUJi1S +MA0GCSqGSIb3DQEBCwUAA4IBAQA5noHB343sKQqVmmLds0gC/k1UhVA5iftAGmes +uRdNOOCdo2i739DmRAXggetgtatcjDfjxkrvq0Qi+geozZra6uX9FT/hgfw6kDpU +HKzJFy4E0G0HTM8mtJi+aGDZL3Lts+h272eahkT1jVKGAPFugqfz7fKRsMce6eCE +UD5cvtQXX16fGhBxxmUCZPnxMKcj2oNl7RliHphK6ofXuNbKjqjVQfxsTUXSQDyS +ApH5w6iUnAvC5l19qYrBcCVOB6CNJ2CdmvFI//Ox8Jc56HRYYDIdVp2Q3FFA5Z4s +gTLvlumVgihAekD+0zVF9q+AJ4TSbE3cqsQgHF/+p84KxWid +-----END CERTIFICATE----- diff --git a/certs/crl/crlEccOut.der b/certs/crl/crlEccOut.der new file mode 100644 index 0000000000..b26615ca5a Binary files /dev/null and b/certs/crl/crlEccOut.der differ diff --git a/certs/crl/crlEccOut.pem b/certs/crl/crlEccOut.pem new file mode 100644 index 0000000000..b9d0146f89 --- /dev/null +++ b/certs/crl/crlEccOut.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBdDCCARkCAQEwCgYIKoZIzj0EAwIwgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQI +DApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRAwDgYDVQQKDAd3b2xmU1NM +MRQwEgYDVQQLDAtEZXZlbG9wbWVudDEYMBYGA1UEAwwPd3d3LndvbGZzc2wuY29t +MR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tFw0yNjAyMDQwMzU0Mjla +Fw0yNjAzMDYwMzU0MjlaMFAwEgIBAhcNMjYwMjA0MDM1NDI5WjASAgEDFw0yNjAy +MDQwMzU0MjlaMBICAQQXDTI2MDIwNDAzNTQyOVowEgIBAxcNMjYwMjA0MDM1NDI5 +WjAKBggqhkjOPQQDAgNJADBGAiEA6xz109x9tZwaxxs3iLvW65h9AGL8+e1gTnbr +GoEsXaQCIQDzxO4LU1d6seHETQDKjUEXivHuvC6f0Nq5uARmWX0DOA== +-----END X509 CRL----- diff --git a/certs/crl/crlRsaOut.der b/certs/crl/crlRsaOut.der new file mode 100644 index 0000000000..97d7a5485a Binary files /dev/null and b/certs/crl/crlRsaOut.der differ diff --git a/certs/crl/crlRsaOut.pem b/certs/crl/crlRsaOut.pem new file mode 100644 index 0000000000..e238f5b829 --- /dev/null +++ b/certs/crl/crlRsaOut.pem @@ -0,0 +1,14 @@ +-----BEGIN X509 CRL----- +MIICMTCCARkCAQEwDQYJKoZIhvcNAQELBQAwgZQxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMREwDwYDVQQKDAhTYXd0b290 +aDETMBEGA1UECwwKQ29uc3VsdGluZzEYMBYGA1UEAwwPd3d3LndvbGZzc2wuY29t +MR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tFw0yNjAyMDQwMzU0Mjla +Fw0yNjAzMDYwMzU0MjlaMFAwEgIBAhcNMjYwMjA0MDM1NDI5WjASAgEDFw0yNjAy +MDQwMzU0MjlaMBICAQQXDTI2MDIwNDAzNTQyOVowEgIBARcNMjYwMjA0MDM1NDI5 +WjANBgkqhkiG9w0BAQsFAAOCAQEAid2CDa/invAbnAJaeVVkS8mRjI/kR0aPHwt1 +/Sz6w+j163+KZnBwUNgrMmLSMbssm8oxQ8i8zNvBeYd6u1x2N/jw/cwH2rxhZ3zQ +bOkDQKKe2eRYXMykAl1uj2VwCeu8/ivqbimYReq7iloEHo8PUiizs1Pj6zJ59I1u +LRZDDlS9wiY+VVkKx28dxyClsqtJNCvz5ezNB8GeH+gekaJ1tJVbd3TujBajPPAx +R6FobbOOavCZPyGkeZlU/T9S5FwIi07qga5Zuq/9Dy7YwiVya3sAZ/nTYY++HKDQ +DL0Bs3/05Lf8BLaf2CX2vGvan4JCQv9CMdnlYBifwvQCeUToyQ== +-----END X509 CRL----- diff --git a/certs/crl/include.am b/certs/crl/include.am index 6f7f6f26bf..f3ca111ecf 100644 --- a/certs/crl/include.am +++ b/certs/crl/include.am @@ -22,7 +22,9 @@ EXTRA_DIST += \ EXTRA_DIST += \ certs/crl/crl.revoked \ certs/crl/extra-crls/ca-int-cert-revoked.pem \ - certs/crl/extra-crls/general-server-crl.pem + certs/crl/extra-crls/general-server-crl.pem \ + certs/crl/extra-crls/large_crlnum.pem \ + certs/crl/extra-crls/large_crlnum2.pem # Intermediate cert CRL's EXTRA_DIST += \ diff --git a/certs/include.am b/certs/include.am index 68fcd1e2ea..26c5f959d2 100644 --- a/certs/include.am +++ b/certs/include.am @@ -85,6 +85,11 @@ EXTRA_DIST += \ certs/dh-pub-2048.pem \ certs/dsa2048.pem +EXTRA_DIST += \ + certs/aia/ca-issuers-cert.pem \ + certs/aia/multi-aia-cert.pem \ + certs/aia/overflow-aia-cert.pem + EXTRA_DIST += \ certs/ca-key.der \ certs/ca-cert.der \ @@ -154,4 +159,3 @@ include certs/sphincs/include.am include certs/rpk/include.am include certs/acert/include.am include certs/mldsa/include.am - diff --git a/certs/renewcerts.sh b/certs/renewcerts.sh index 5aed648817..535ae8ff73 100755 --- a/certs/renewcerts.sh +++ b/certs/renewcerts.sh @@ -31,6 +31,9 @@ # fpki-cert.der # fpki-certpol-cert.der # rid-cert.der +# aia/ca-issuers-cert.pem +# aia/multi-aia-cert.pem +# aia/overflow-aia-cert.pem # updates the following crls: # crl/cliCrl.pem # crl/crl.pem @@ -292,6 +295,60 @@ run_renewcerts(){ echo "End of section" echo "---------------------------------------------------------------------" ############################################################ + ########## update AIA test certs ########################### + ############################################################ + echo "Updating AIA test certs" + echo "" + mkdir -p aia + + echo "Updating aia/ca-issuers-cert.pem" + echo "" + openssl req -new -newkey rsa:2048 -nodes -keyout aia/ca-issuers-key.pem -subj "/CN=wolfssl-aia-test" -out aia/ca-issuers-cert.csr + check_result $? "Step AIA-1" + + openssl x509 -req -in aia/ca-issuers-cert.csr -days 365 -extfile wolfssl.cnf -extensions aia_ca_issuers -signkey aia/ca-issuers-key.pem -out aia/ca-issuers-cert.pem + check_result $? "Step AIA-2" + rm aia/ca-issuers-cert.csr + + openssl x509 -in aia/ca-issuers-cert.pem -text > tmp.pem + check_result $? "Step AIA-3" + mv tmp.pem aia/ca-issuers-cert.pem + rm aia/ca-issuers-key.pem + echo "End of section" + echo "---------------------------------------------------------------------" + + echo "Updating aia/multi-aia-cert.pem" + echo "" + openssl req -new -newkey rsa:2048 -nodes -keyout aia/multi-aia-key.pem -subj "/CN=wolfssl-aia-multi-test" -out aia/multi-aia-cert.csr + check_result $? "Step AIA-4" + + openssl x509 -req -in aia/multi-aia-cert.csr -days 365 -extfile wolfssl.cnf -extensions aia_multi -signkey aia/multi-aia-key.pem -out aia/multi-aia-cert.pem + check_result $? "Step AIA-5" + rm aia/multi-aia-cert.csr + + openssl x509 -in aia/multi-aia-cert.pem -text > tmp.pem + check_result $? "Step AIA-6" + mv tmp.pem aia/multi-aia-cert.pem + rm aia/multi-aia-key.pem + echo "End of section" + echo "---------------------------------------------------------------------" + + echo "Updating aia/overflow-aia-cert.pem" + echo "" + openssl req -new -newkey rsa:2048 -nodes -keyout aia/overflow-aia-key.pem -subj "/CN=wolfssl-aia-overflow-test" -out aia/overflow-aia-cert.csr + check_result $? "Step AIA-7" + + openssl x509 -req -in aia/overflow-aia-cert.csr -days 365 -extfile wolfssl.cnf -extensions aia_overflow -signkey aia/overflow-aia-key.pem -out aia/overflow-aia-cert.pem + check_result $? "Step AIA-8" + rm aia/overflow-aia-cert.csr + + openssl x509 -in aia/overflow-aia-cert.pem -text > tmp.pem + check_result $? "Step AIA-9" + mv tmp.pem aia/overflow-aia-cert.pem + rm aia/overflow-aia-key.pem + echo "End of section" + echo "---------------------------------------------------------------------" + ############################################################ ########## update the self-signed ca-cert-chain.der ######## ############################################################ echo "Updating ca-cert-chain.der" diff --git a/certs/renewcerts/wolfssl.cnf b/certs/renewcerts/wolfssl.cnf index a4d5b27426..f02081d143 100644 --- a/certs/renewcerts/wolfssl.cnf +++ b/certs/renewcerts/wolfssl.cnf @@ -321,6 +321,45 @@ keyUsage=critical, digitalSignature, keyCertSign, cRLSign [ crl_dist_points ] crlDistributionPoints=URI:http://www.wolfssl.com/crl.pem +# AIA test certs +[ aia_ca_issuers ] +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always +basicConstraints=critical,CA:true +authorityInfoAccess=@aia_ca_issuers_info + +[ aia_ca_issuers_info ] +caIssuers;URI.0=http://example.com/ca.pem + +[ aia_multi ] +subjectKeyIdentifier=hash +basicConstraints=CA:true +keyUsage=digitalSignature, keyCertSign +authorityInfoAccess=@aia_multi_info + +[ aia_multi_info ] +OCSP;URI.0=http://127.0.0.1:22221 +OCSP;URI.1=http://127.0.0.1:22222 +caIssuers;URI.0=http://www.wolfssl.com/ca.pem +caIssuers;URI.1=https://www.wolfssl.com/ca2.pem + +[ aia_overflow ] +subjectKeyIdentifier=hash +basicConstraints=CA:true +keyUsage=digitalSignature, keyCertSign +authorityInfoAccess=@aia_overflow_info + +[ aia_overflow_info ] +OCSP;URI.0=http://127.0.0.1:22220 +OCSP;URI.1=http://127.0.0.1:22221 +OCSP;URI.2=http://127.0.0.1:22222 +OCSP;URI.3=http://127.0.0.1:22223 +OCSP;URI.4=http://127.0.0.1:22224 +OCSP;URI.5=http://127.0.0.1:22225 +OCSP;URI.6=http://127.0.0.1:22226 +OCSP;URI.7=http://127.0.0.1:22227 +OCSP;URI.8=http://127.0.0.1:22228 + #tsa default [ tsa ] default_tsa = tsa_config1 @@ -404,4 +443,3 @@ DNS.1 = www.example.org URI.1 = https://www.wolfssl.com/ otherName.2 = 2.16.840.1.101.3.6.6;FORMAT:HEX,OCT:D1:38:10:D8:28:AF:2C:10:84:35:15:A1:68:58:28:AF:02:10:86:A2:84:E7:39:C3:EB - diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in index 3b8098b6b3..6e115b0a9b 100644 --- a/cmake/Config.cmake.in +++ b/cmake/Config.cmake.in @@ -1,4 +1,9 @@ @PACKAGE_INIT@ +# Autoconf-generated configs won't define PACKAGE_PREFIX_DIR; fall back to the +# configured install prefix for non-relocatable packages. +if (NOT DEFINED PACKAGE_PREFIX_DIR) + set(PACKAGE_PREFIX_DIR "@WOLFSSL_PREFIX_ABS@") +endif() include(CMakeFindDependencyMacro) if (@HAVE_PTHREAD@) diff --git a/cmake/README.md b/cmake/README.md index bb4efb4e31..66b8f9403f 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -3,6 +3,9 @@ This directory contains some supplementary functions for the [CMakeLists.txt](../CMakeLists.txt) in the root. See also cmake notes in the [INSTALL](../INSTALL) documentation file. +When building with autoconf/automake, CMake package files are installed by default +under $(libdir)/cmake/wolfssl to support find_package(wolfssl). Disable with +./configure --disable-cmake-install. If new CMake build options are added `cmake/options.h.in` must also be updated. @@ -56,4 +59,3 @@ See the Microsoft [CMakeSettings.json schema reference](https://learn.microsoft. * Specific environment variables * *UI-related tweaks - diff --git a/cmake/consumer/CMakeLists.txt b/cmake/consumer/CMakeLists.txt new file mode 100644 index 0000000000..3ea3bde38f --- /dev/null +++ b/cmake/consumer/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.10) + +project(wolfssl_consumer C) + +find_package(wolfssl CONFIG REQUIRED) + +add_executable(wolfssl_consumer main.c) +target_link_libraries(wolfssl_consumer PRIVATE wolfssl::wolfssl) diff --git a/cmake/consumer/README.md b/cmake/consumer/README.md new file mode 100644 index 0000000000..2353fe1af4 --- /dev/null +++ b/cmake/consumer/README.md @@ -0,0 +1,12 @@ +# CMake consumer test + +This is a minimal CMake project that consumes the installed wolfSSL +package config. + +## Build + +``` +cmake -S . -B build -DCMAKE_PREFIX_PATH=/path/to/wolfssl/install +cmake --build build +./build/wolfssl_consumer +``` diff --git a/cmake/consumer/main.c b/cmake/consumer/main.c new file mode 100644 index 0000000000..c052969a55 --- /dev/null +++ b/cmake/consumer/main.c @@ -0,0 +1,11 @@ +#include +#include + +int main(void) +{ + if (wolfSSL_Init() != WOLFSSL_SUCCESS) { + return 1; + } + wolfSSL_Cleanup(); + return 0; +} diff --git a/cmake/include.am b/cmake/include.am index b7cd6c7911..709ffa65f2 100644 --- a/cmake/include.am +++ b/cmake/include.am @@ -1,7 +1,19 @@ EXTRA_DIST += cmake/README.md EXTRA_DIST += cmake/Config.cmake.in +EXTRA_DIST += cmake/wolfssl-config-version.cmake.in +EXTRA_DIST += cmake/wolfssl-targets.cmake.in +EXTRA_DIST += cmake/consumer/CMakeLists.txt +EXTRA_DIST += cmake/consumer/main.c +EXTRA_DIST += cmake/consumer/README.md EXTRA_DIST += cmake/config.in EXTRA_DIST += cmake/functions.cmake EXTRA_DIST += cmake/options.h.in EXTRA_DIST += cmake/modules/FindARIA.cmake EXTRA_DIST += cmake/modules/FindOQS.cmake + +if CMAKE_INSTALL +cmakedir = $(libdir)/cmake/wolfssl +cmake_DATA = cmake/wolfssl-config.cmake \ + cmake/wolfssl-config-version.cmake \ + cmake/wolfssl-targets.cmake +endif diff --git a/cmake/options.h.in b/cmake/options.h.in index 796d446578..49c55694e8 100644 --- a/cmake/options.h.in +++ b/cmake/options.h.in @@ -270,6 +270,10 @@ extern "C" { #cmakedefine WOLFSSL_AES_OFB #undef WOLFSSL_AES_SIV #cmakedefine WOLFSSL_AES_SIV +#undef HAVE_AES_ECB +#cmakedefine HAVE_AES_ECB +#undef WOLFSSL_AES_CTS +#cmakedefine WOLFSSL_AES_CTS #undef WOLFSSL_ALT_CERT_CHAINS #cmakedefine WOLFSSL_ALT_CERT_CHAINS #undef WOLFSSL_APPLE_NATIVE_CERT_VALIDATION @@ -302,6 +306,8 @@ extern "C" { #cmakedefine WOLFSSL_DTLS_CID #undef WOLFSSL_DTLS13 #cmakedefine WOLFSSL_DTLS13 +#undef WOLFSSL_DTLS_CH_FRAG +#cmakedefine WOLFSSL_DTLS_CH_FRAG #undef WOLFSSL_EITHER_SIDE #cmakedefine WOLFSSL_EITHER_SIDE #undef WOLFSSL_ENCRYPTED_KEYS @@ -402,6 +408,8 @@ extern "C" { #cmakedefine WOLFSSL_WC_XMSS #undef HAVE_SECRET_CALLBACK #cmakedefine HAVE_SECRET_CALLBACK +#undef WC_RSA_DIRECT +#cmakedefine WC_RSA_DIRECT #ifdef __cplusplus } diff --git a/cmake/wolfssl-config-version.cmake.in b/cmake/wolfssl-config-version.cmake.in new file mode 100644 index 0000000000..bc136fad8f --- /dev/null +++ b/cmake/wolfssl-config-version.cmake.in @@ -0,0 +1,17 @@ +# Generated by autoconf; do not edit. + +set(PACKAGE_VERSION "@PACKAGE_VERSION@") + +# Keep behavior aligned with the native CMake build's AnyNewerVersion semantics: +# compatible when the installed version is >= the requested version. +set(PACKAGE_VERSION_COMPATIBLE FALSE) +set(PACKAGE_VERSION_EXACT FALSE) + +if (PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + # not compatible +else () + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if (PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif () +endif () diff --git a/cmake/wolfssl-targets.cmake.in b/cmake/wolfssl-targets.cmake.in new file mode 100644 index 0000000000..afbe1ab7f7 --- /dev/null +++ b/cmake/wolfssl-targets.cmake.in @@ -0,0 +1,27 @@ +# Generated by autoconf; do not edit. + +if (NOT TARGET wolfssl::wolfssl) + add_library(wolfssl::wolfssl UNKNOWN IMPORTED) + + set(_wolfssl_libdir "@WOLFSSL_LIBDIR_ABS@") + set(_wolfssl_includedir "@WOLFSSL_INCLUDEDIR_ABS@") + + find_library(WOLFSSL_LIBRARY NAMES wolfssl PATHS "${_wolfssl_libdir}" NO_DEFAULT_PATH) + if (NOT WOLFSSL_LIBRARY) + find_library(WOLFSSL_LIBRARY NAMES wolfssl) + endif() + if (NOT WOLFSSL_LIBRARY) + message(FATAL_ERROR "wolfssl library not found. Looked in: ${_wolfssl_libdir}") + endif() + + set_target_properties(wolfssl::wolfssl PROPERTIES + IMPORTED_LOCATION "${WOLFSSL_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${_wolfssl_includedir}" + ) + + if (@WOLFSSL_HAVE_PTHREAD@) + set_property(TARGET wolfssl::wolfssl APPEND PROPERTY + INTERFACE_LINK_LIBRARIES Threads::Threads + ) + endif() +endif() diff --git a/configure.ac b/configure.ac index e248005e0b..ed7a512a47 100644 --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,13 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) AC_ARG_PROGRAM +# Optional CMake package install (enabled by default) +AC_ARG_ENABLE([cmake-install], + [AS_HELP_STRING([--disable-cmake-install],[Disable installation of CMake package files])], + [ ENABLED_CMAKE_INSTALL=$enableval ], + [ ENABLED_CMAKE_INSTALL=yes ]) +AM_CONDITIONAL([CMAKE_INSTALL],[test "x$ENABLED_CMAKE_INSTALL" = "xyes"]) + AC_CONFIG_HEADERS([config.h:config.in]) LT_PREREQ([2.4.2]) @@ -123,9 +130,18 @@ then AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_EXPERIMENTAL_SETTINGS" fi +# Kernel module benchmark +ENABLED_KERNEL_BENCHMARKS="" +AC_ARG_ENABLE([kernel-benchmarks], + [AS_HELP_STRING([--enable-kernel-benchmarks],[Enable crypto benchmarking autorun at module load time for kernel module (default: disabled)])], + [ENABLED_KERNEL_BENCHMARKS=$enableval]) +if test "$ENABLED_KERNEL_BENCHMARKS" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_KERNEL_BENCHMARKS" +fi +AC_SUBST([ENABLED_KERNEL_BENCHMARKS]) # Linux Kernel Module options (more options later) - AC_ARG_ENABLE([linuxkm], [AS_HELP_STRING([--enable-linuxkm],[Enable Linux Kernel Module (default: disabled)])], [ENABLED_LINUXKM=$enableval], @@ -145,6 +161,12 @@ AC_ARG_ENABLE([freebsdkm], [ENABLED_BSDKM=no] ) +AC_ARG_ENABLE([freebsdkm-crypto-register], + [AS_HELP_STRING([--enable-freebsdkm-crypto-register],[Register wolfCrypt implementations with the FreeBSD kernel opencrypto framework. (default: disabled)])], + [ENABLED_BSDKM_REGISTER=$enableval], + [ENABLED_BSDKM_REGISTER=no] + ) + AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h stddef.h time.h sys/ioctl.h sys/socket.h sys/time.h errno.h sys/un.h ctype.h sys/random.h]) AC_CHECK_LIB([network],[socket]) AC_C_BIGENDIAN @@ -727,10 +749,8 @@ AC_SUBST([ENABLED_LINUXKM_PIE]) AC_ARG_ENABLE([linuxkm-benchmarks], [AS_HELP_STRING([--enable-linuxkm-benchmarks],[Enable crypto benchmarking autorun at module load time for Linux kernel module (default: disabled)])], - [ENABLED_KERNEL_BENCHMARKS=$enableval], - [ENABLED_KERNEL_BENCHMARKS=no] - ) -if test "$ENABLED_KERNEL_BENCHMARKS" = "yes" + [ENABLED_KERNEL_BENCHMARKS=$enableval]) +if test "$ENABLED_LINUXKM" = "yes" && test "$ENABLED_KERNEL_BENCHMARKS" = "yes" then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_LINUXKM_BENCHMARKS" fi @@ -819,17 +839,15 @@ AC_ARG_WITH([bsd-export-syms], if test "x$ENABLED_BSDKM" = "xyes" then - # wolfcrypt only, no-asm supported for now. + # note: bsdkm is wolfcrypt only for now. HAVE_KERNEL_MODE=yes KERNEL_MODE_DEFAULTS=yes ENABLED_NO_LIBRARY=yes ENABLED_BENCHMARK=no - ENABLED_ASM=no output_objdir="$(realpath "$output_objdir")/bsdkm" AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_BSDKM -DWC_SIPHASH_NO_ASM" - AM_CFLAGS="$AM_CFLAGS -DTFM_NO_ASM -DWOLFSSL_NO_ASM" AM_CFLAGS="$AM_CFLAGS -DNO_DEV_RANDOM -DNO_WRITEV -DNO_STDIO_FILESYSTEM" AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_SOCK -DWOLFSSL_USER_IO" AM_CFLAGS="$AM_CFLAGS -DXMALLOC_OVERRIDE -DWOLFCRYPT_ONLY" @@ -846,7 +864,16 @@ then fi AC_SUBST([KERNEL_ROOT]) AC_SUBST([BSDKM_EXPORT_SYMS]) +fi +if test "x$ENABLED_BSDKM_REGISTER" = "xyes" +then + if test "$ENABLED_AESGCM" != "no" && test "$ENABLED_AESGCM_STREAM" = "no" && test "$enable_aesgcm_stream" != "no" && (test "$ENABLED_FIPS" = "no" || test $HAVE_FIPS_VERSION -ge 6); then + ENABLED_AESGCM_STREAM=yes + fi + + AM_CFLAGS="$AM_CFLAGS -DBSDKM_CRYPTO_REGISTER" + AC_SUBST([ENABLED_BSDKM_REGISTER]) fi # end FreeBSD configure @@ -1383,13 +1410,13 @@ then esac fi -# 32 bit armasm and RISC-V asm don't yet support WOLFSSL_AESGCM_STREAM. Disable +# RISC-V asm doesn't yet support WOLFSSL_AESGCM_STREAM. Disable # implicit activation, and error on explicit activation. -if test "$enable_riscv_asm" = "yes" || (test "$enable_armasm" = "yes" && test "$host_cpu" != "aarch64" && test "$host_cpu" != "aarch64_be") +if test "$enable_riscv_asm" = "yes" then if test "$enable_aesgcm_stream" = "yes" then - AC_MSG_ERROR([32 bit armasm and RISC-V asm don't yet support WOLFSSL_AESGCM_STREAM.]) + AC_MSG_ERROR([RISC-V asm doesn't yet support WOLFSSL_AESGCM_STREAM.]) fi enable_aesgcm_stream=no fi @@ -2061,9 +2088,11 @@ AC_ARG_ENABLE([singlethreaded], [ ENABLED_SINGLETHREADED=$enableval ], [ ENABLED_SINGLETHREADED=no ]) +WOLFSSL_HAVE_PTHREAD=0 AS_IF([ test "x$ENABLED_SINGLETHREADED" = "xno" ],[ AX_PTHREAD([ AC_DEFINE([HAVE_PTHREAD], [1], [Define if you have POSIX threads libraries and header files.]) + WOLFSSL_HAVE_PTHREAD=1 # If AX_PTHREAD is adding -Qunused-arguments, need to prepend with -Xcompiler libtool will use it. Newer # versions of clang don't need the -Q flag when using pthreads. AS_CASE([$PTHREAD_CFLAGS],[-Qunused-arguments*],[PTHREAD_CFLAGS="-Xcompiler $PTHREAD_CFLAGS"]) @@ -3969,6 +3998,8 @@ then ENABLED_X86_ASM=yes fi fi +AC_SUBST([ENABLED_AESNI]) +AC_SUBST([ENABLED_AESNI_WITH_AVX]) AC_ARG_ENABLE([aligndata], [AS_HELP_STRING([--enable-aligndata],[align data for ciphers (default: enabled)])], @@ -10689,11 +10720,9 @@ then if test "$ENABLED_AESGCM" = "no" then AC_MSG_ERROR([AES-GCM streaming is enabled but AES-GCM is disabled.]) - elif test "$ENABLED_RISCV_ASM" = "yes" || \ - (test "$ENABLED_ARMASM" = "yes" && \ - test "$host_cpu" != "aarch64" && test "$host_cpu" != "aarch64_be") + elif test "$ENABLED_RISCV_ASM" = "yes" then - AC_MSG_ERROR([32 bit armasm and RISC-V asm don't yet support WOLFSSL_AESGCM_STREAM.]) + AC_MSG_ERROR([RISC-V asm doesn't yet support WOLFSSL_AESGCM_STREAM.]) else AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AESGCM_STREAM" AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_AESGCM_STREAM" @@ -11263,6 +11292,26 @@ AC_SUBST([LIB_ADD]) AC_SUBST([LIB_STATIC_ADD]) AC_SUBST([LIBM]) AC_SUBST([PC_LIBS_PRIVATE]) +AC_SUBST([WOLFSSL_HAVE_PTHREAD]) +HAVE_PTHREAD=$WOLFSSL_HAVE_PTHREAD +AC_SUBST([HAVE_PTHREAD]) +PACKAGE_INIT='' +AC_SUBST([PACKAGE_INIT]) +WOLFSSL_PREFIX_ABS=$prefix +if test "x$WOLFSSL_PREFIX_ABS" = "xNONE"; then + WOLFSSL_PREFIX_ABS=$ac_default_prefix +fi +WOLFSSL_EXEC_PREFIX_ABS=$exec_prefix +if test "x$WOLFSSL_EXEC_PREFIX_ABS" = "xNONE"; then + WOLFSSL_EXEC_PREFIX_ABS=$WOLFSSL_PREFIX_ABS +fi +prefix=$WOLFSSL_PREFIX_ABS +exec_prefix=$WOLFSSL_EXEC_PREFIX_ABS +eval WOLFSSL_LIBDIR_ABS=\"$libdir\" +eval WOLFSSL_INCLUDEDIR_ABS=\"$includedir\" +AC_SUBST([WOLFSSL_PREFIX_ABS]) +AC_SUBST([WOLFSSL_LIBDIR_ABS]) +AC_SUBST([WOLFSSL_INCLUDEDIR_ABS]) # FINAL AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h]) @@ -11275,6 +11324,12 @@ AC_CONFIG_FILES([Makefile rpm/spec wolfcrypt/test/test_paths.h ]) +AS_IF([ test "x$ENABLED_CMAKE_INSTALL" = "xyes" ],[ +AC_CONFIG_FILES([cmake/wolfssl-config.cmake:cmake/Config.cmake.in + cmake/wolfssl-config-version.cmake:cmake/wolfssl-config-version.cmake.in + cmake/wolfssl-targets.cmake:cmake/wolfssl-targets.cmake.in + ]) +]) AC_CONFIG_FILES([scripts/unit.test],[chmod +x scripts/unit.test]) AC_CONFIG_FILES([debian/rules],[chmod +x debian/rules]) diff --git a/debian/libwolfssl-dev.install b/debian/libwolfssl-dev.install index 21de1f2062..4ee57d0d1f 100644 --- a/debian/libwolfssl-dev.install +++ b/debian/libwolfssl-dev.install @@ -2,5 +2,6 @@ usr/include/ usr/lib/*/libwolfssl.so usr/lib/*/libwolfssl.a usr/lib/*/pkgconfig/wolfssl.pc +usr/lib/*/cmake/wolfssl/* usr/bin/wolfssl-config usr/share/doc/wolfssl/ diff --git a/doc/dox_comments/header_files/cryptocb.h b/doc/dox_comments/header_files/cryptocb.h index 145d8c9ff5..b6a21922f3 100644 --- a/doc/dox_comments/header_files/cryptocb.h +++ b/doc/dox_comments/header_files/cryptocb.h @@ -180,3 +180,63 @@ void wc_CryptoCb_SetDeviceFindCb(CryptoDevCallbackFind cb); \sa wc_CryptoCb_RegisterDevice */ void wc_CryptoCb_InfoString(wc_CryptoInfo* info); + +/*! + \ingroup CryptoCb + + \brief Import an AES key into a CryptoCB device for hardware offload. + + This function allows AES keys to be handled by an external device + (e.g. Secure Element or HSM). When supported, the device callback stores + the key internally and sets an opaque handle in aes->devCtx. + + When CryptoCB AES SetKey support is enabled + (WOLF_CRYPTO_CB_AES_SETKEY), wolfCrypt routes AES-GCM operations + through the CryptoCB interface. + + **TLS Builds (Default):** + - Key bytes ARE stored in wolfCrypt memory (devKey) for fallback + - GCM tables ARE generated for software fallback + - Provides hardware acceleration with automatic fallback + + **Crypto-Only Builds (--disable-tls):** + - Key bytes NOT stored in wolfCrypt memory (true key isolation) + - GCM tables skipped (true hardware offload) + - Callback must handle all GCM operations (SetKey, Encrypt, Decrypt, Free) + + If the callback returns success (0), full AES-GCM offload is assumed. + The callback must handle SetKey, Encrypt, Decrypt, and Free operations. + + \param aes AES context + \param key Pointer to raw AES key material + \param keySz Size of key in bytes + + \return 0 on success + \return CRYPTOCB_UNAVAILABLE if device does not support this operation + \return BAD_FUNC_ARG on invalid parameters + + _Example_ + \code + #include + #include + + Aes aes; + byte key[32] = { /* 256-bit key */ }; + int devId = 1; + + /* Register your CryptoCB callback first */ + wc_CryptoCb_RegisterDevice(devId, myCryptoCallback, NULL); + + wc_AesInit(&aes, NULL, devId); + /* wc_AesGcmSetKey internally calls wc_CryptoCb_AesSetKey */ + if (wc_CryptoCb_AesSetKey(&aes, key, sizeof(key)) == 0) { + /* Key successfully imported to device via callback */ + /* aes.devCtx now contains device handle */ + /* Full GCM offload is assumed - callback must handle all operations */ + } + \endcode + + \sa wc_CryptoCb_RegisterDevice + \sa wc_AesInit +*/ +int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz); diff --git a/doc/dox_comments/header_files/doxygen_pages.h b/doc/dox_comments/header_files/doxygen_pages.h index 2765449ac8..58ae75852e 100644 --- a/doc/dox_comments/header_files/doxygen_pages.h +++ b/doc/dox_comments/header_files/doxygen_pages.h @@ -74,4 +74,27 @@ - \ref SAKKE_RSK - \ref SAKKE_Operations */ +/*! + \page AES_CryptoCB_KeyImport AES CryptoCB Key Import + + When enabled via WOLF_CRYPTO_CB_AES_SETKEY, wolfSSL invokes a CryptoCB + callback during AES key setup. The callback behavior determines the mode: + + **If callback returns 0 (success):** + - Key is imported to Secure Element/HSM + - Key is NOT copied to wolfSSL RAM (true key isolation) + - GCM tables are NOT generated (full hardware offload) + - All subsequent AES operations route through CryptoCB + + **If callback returns CRYPTOCB_UNAVAILABLE:** + - SE doesn't support key import + - Normal software AES path is used + - Key is copied to devKey for CryptoCB encrypt/decrypt acceleration + + This mode is compatible with Secure Elements and hardware-backed + key storage and is intended for protecting TLS traffic keys. + + \sa wc_CryptoCb_AesSetKey + \sa \ref Crypto Callbacks +*/ diff --git a/doc/dox_comments/header_files/memory.h b/doc/dox_comments/header_files/memory.h index fe18397db1..b5430758a3 100644 --- a/doc/dox_comments/header_files/memory.h +++ b/doc/dox_comments/header_files/memory.h @@ -376,7 +376,8 @@ int wolfSSL_is_static_memory(WOLFSSL* ssl, WOLFSSL_MEM_CONN_STATS* mem_stats); buffers to themselves for their lifetime. WOLFMEM_TRACK_STATS - each SSL keeps track of memory stats while running - \return none This function does not return a value. + \return Returns 0 on success. + \return Returns a non-zero integer on failure. \param pHint WOLFSSL_HEAP_HINT structure to use \param buf memory to use for all operations. @@ -396,7 +397,7 @@ int wolfSSL_is_static_memory(WOLFSSL* ssl, WOLFSSL_MEM_CONN_STATS* mem_stats); // load in memory for use ret = wc_LoadStaticMemory(&hint, memory, memorySz, flag, 0); - if (ret != SSL_SUCCESS) { + if (ret) { // handle error case } ... @@ -419,7 +420,8 @@ int wc_LoadStaticMemory(WOLFSSL_HEAP_HINT** pHint, unsigned char* buf, into functions. This extended version allows for custom bucket sizes and distributions instead of using the default predefined sizes. - \return none This function does not return a value. + \return Returns 0 on success. + \return Returns a non-zero integer on failure. \param pHint WOLFSSL_HEAP_HINT handle to initialize \param listSz number of entries in the size and distribution lists @@ -447,7 +449,7 @@ int wc_LoadStaticMemory(WOLFSSL_HEAP_HINT** pHint, unsigned char* buf, ret = wc_LoadStaticMemory_ex(&hint, listSz, sizeList, distList, memory, memorySz, flag, 0); - if (ret != SSL_SUCCESS) { + if (ret) { // handle error case } ... diff --git a/linuxkm/linuxkm_wc_port.h b/linuxkm/linuxkm_wc_port.h index 00e7e45d3e..ebe0d64bc5 100644 --- a/linuxkm/linuxkm_wc_port.h +++ b/linuxkm/linuxkm_wc_port.h @@ -545,9 +545,10 @@ * to assure that calls to get_random_bytes() in random.c are gated out * (they would recurse, potentially infinitely). */ - #if (defined(LINUXKM_LKCAPI_REGISTER_ALL) && \ - !defined(LINUXKM_LKCAPI_DONT_REGISTER_HASH_DRBG) && \ - !defined(LINUXKM_LKCAPI_DONT_REGISTER_HASH_DRBG_DEFAULT)) && \ + #if defined(LINUXKM_LKCAPI_REGISTER_ALL) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_HASH_DRBG) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_HASH_DRBG_DEFAULT) && \ + !defined(NO_LINUXKM_DRBG_GET_RANDOM_BYTES) && \ !defined(LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) #define LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT #endif diff --git a/linuxkm/lkcapi_sha_glue.c b/linuxkm/lkcapi_sha_glue.c index 1bdc56a8ac..bf2a16c929 100644 --- a/linuxkm/lkcapi_sha_glue.c +++ b/linuxkm/lkcapi_sha_glue.c @@ -30,6 +30,22 @@ #error SHA* WC_LINUXKM_C_FALLBACK_IN_SHIMS is not currently supported. #endif +#ifdef NO_LINUXKM_DRBG_GET_RANDOM_BYTES + #undef LINUXKM_DRBG_GET_RANDOM_BYTES +/* setup for LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT is in linuxkm_wc_port.h */ +#elif defined(LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) && \ + (defined(WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS) || \ + defined(WOLFSSL_LINUXKM_USE_GET_RANDOM_KPROBES)) + #ifndef LINUXKM_DRBG_GET_RANDOM_BYTES + #define LINUXKM_DRBG_GET_RANDOM_BYTES + #endif +#else + #ifdef LINUXKM_DRBG_GET_RANDOM_BYTES + #error LINUXKM_DRBG_GET_RANDOM_BYTES configured with no callback model configured. + #undef LINUXKM_DRBG_GET_RANDOM_BYTES + #endif +#endif + #include #include @@ -94,7 +110,14 @@ * exhaustion. A caller that really needs PR can pass in seed data in its call * to our rng_alg.generate() implementation. */ -#define WOLFKM_STDRNG_DRIVER ("sha2-256-drbg-nopr" WOLFKM_SHA_DRIVER_SUFFIX) +#ifdef LINUXKM_DRBG_GET_RANDOM_BYTES + #define WOLFKM_STDRNG_DRIVER ("sha2-256-drbg-nopr" \ + WOLFKM_DRIVER_SUFFIX_BASE \ + "-with-global-replace") +#else + #define WOLFKM_STDRNG_DRIVER ("sha2-256-drbg-nopr" \ + WOLFKM_DRIVER_SUFFIX_BASE) +#endif #ifdef LINUXKM_LKCAPI_REGISTER_SHA_ALL #define LINUXKM_LKCAPI_REGISTER_SHA1 @@ -388,7 +411,7 @@ #else #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_DRBG) && \ !defined(LINUXKM_LKCAPI_DONT_REGISTER_HASH_DRBG) - #error Config conflict: target kernel has CONFIG_CRYPTO_SHA3, but module is missing WOLFSSL_SHA3 + #error Config conflict: target kernel has CONFIG_CRYPTO_DRBG, but module is missing HAVE_HASHDRBG #endif #undef LINUXKM_LKCAPI_REGISTER_HASH_DRBG #endif @@ -1257,20 +1280,6 @@ static struct rng_alg wc_linuxkm_drbg = { }; static int wc_linuxkm_drbg_loaded = 0; -#ifdef NO_LINUXKM_DRBG_GET_RANDOM_BYTES - #undef LINUXKM_DRBG_GET_RANDOM_BYTES -#elif defined(LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) && \ - (defined(WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS) || defined(WOLFSSL_LINUXKM_USE_GET_RANDOM_KPROBES)) - #ifndef LINUXKM_DRBG_GET_RANDOM_BYTES - #define LINUXKM_DRBG_GET_RANDOM_BYTES - #endif -#else - #ifdef LINUXKM_DRBG_GET_RANDOM_BYTES - #error LINUXKM_DRBG_GET_RANDOM_BYTES configured with no callback model configured. - #undef LINUXKM_DRBG_GET_RANDOM_BYTES - #endif -#endif - #ifdef LINUXKM_DRBG_GET_RANDOM_BYTES #ifndef WOLFSSL_SMALL_STACK_CACHE diff --git a/src/include.am b/src/include.am index fe97320637..943522b4e8 100644 --- a/src/include.am +++ b/src/include.am @@ -17,10 +17,16 @@ MAINTAINERCLEANFILES+= $(FIPS_FILES) EXTRA_DIST += src/bio.c EXTRA_DIST += src/conf.c EXTRA_DIST += src/pk.c +EXTRA_DIST += src/pk_rsa.c +EXTRA_DIST += src/pk_ec.c +EXTRA_DIST += src/ssl_api_cert.c +EXTRA_DIST += src/ssl_api_crl_ocsp.c +EXTRA_DIST += src/ssl_api_pk.c 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_ech.c EXTRA_DIST += src/ssl_load.c EXTRA_DIST += src/ssl_misc.c EXTRA_DIST += src/ssl_p7p12.c diff --git a/src/internal.c b/src/internal.c index 74f59faff9..818f6e0d5d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -13848,6 +13848,34 @@ int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert) } x509->authInfoSet = dCert->extAuthInfoSet; x509->authInfoCrit = dCert->extAuthInfoCrit; + x509->authInfoListSz = dCert->extAuthInfoListSz; + x509->authInfoListOverflow = dCert->extAuthInfoListOverflow; + if (x509->authInfoListSz > WOLFSSL_MAX_AIA_ENTRIES) { + x509->authInfoListSz = WOLFSSL_MAX_AIA_ENTRIES; + x509->authInfoListOverflow = 1; + } + if (x509->authInfoListSz > 0) { + int i; + for (i = 0; i < x509->authInfoListSz; i++) { + x509->authInfoList[i].method = dCert->extAuthInfoList[i].method; + x509->authInfoList[i].uriSz = dCert->extAuthInfoList[i].uriSz; + x509->authInfoList[i].uri = NULL; + + if (dCert->extAuthInfoList[i].uri != NULL && + dCert->source != NULL && dCert->maxIdx > 0 && + x509->derCert != NULL && x509->derCert->buffer != NULL) { + word32 offset = (word32) + (dCert->extAuthInfoList[i].uri - dCert->source); + if (offset < (word32)dCert->maxIdx) { + x509->authInfoList[i].uri = + x509->derCert->buffer + offset; + } + else { + x509->authInfoList[i].uriSz = 0; + } + } + } + } if (dCert->extAuthInfo != NULL && dCert->extAuthInfoSz > 0) { x509->authInfo = (byte*)XMALLOC(dCert->extAuthInfoSz, x509->heap, DYNAMIC_TYPE_X509_EXT); diff --git a/src/pk.c b/src/pk.c index 8f07a679c1..34f26dfcdb 100644 --- a/src/pk.c +++ b/src/pk.c @@ -26,21 +26,6 @@ #include #endif -#ifdef HAVE_ECC - #include - #ifdef HAVE_SELFTEST - /* point compression types. */ - #define ECC_POINT_COMP_EVEN 0x02 - #define ECC_POINT_COMP_ODD 0x03 - #define ECC_POINT_UNCOMP 0x04 - #endif -#endif -#ifndef WOLFSSL_HAVE_ECC_KEY_GET_PRIV - /* FIPS build has replaced ecc.h. */ - #define wc_ecc_key_get_priv(key) (&((key)->k)) - #define WOLFSSL_HAVE_ECC_KEY_GET_PRIV -#endif - #if !defined(WOLFSSL_PK_INCLUDED) #ifndef WOLFSSL_IGNORE_FILE_WARN #warning pk.c does not need to be compiled separately from ssl.c @@ -941,3909 +926,9 @@ static int wolfssl_der_length(const unsigned char* seq, int len) #endif -/******************************************************************************* - * START OF RSA API - ******************************************************************************/ -#ifndef NO_RSA - -/* - * RSA METHOD - * Could be used to hold function pointers to implementations of RSA operations. - */ - -#if defined(OPENSSL_EXTRA) -/* Return a blank RSA method and set the name and flags. - * - * Only one implementation of RSA operations. - * name is duplicated. - * - * @param [in] name Name to use in method. - * @param [in] flags Flags to set into method. - * @return Newly allocated RSA method on success. - * @return NULL on failure. - */ -WOLFSSL_RSA_METHOD *wolfSSL_RSA_meth_new(const char *name, int flags) -{ - WOLFSSL_RSA_METHOD* meth = NULL; - int name_len = 0; - int err; - - /* Validate name is not NULL. */ - if (name == NULL) - return NULL; - /* Allocate an RSA METHOD to return. */ - meth = (WOLFSSL_RSA_METHOD*)XMALLOC(sizeof(WOLFSSL_RSA_METHOD), NULL, - DYNAMIC_TYPE_OPENSSL); - if (meth == NULL) - return NULL; - - XMEMSET(meth, 0, sizeof(*meth)); - meth->flags = flags; - meth->dynamic = 1; - - name_len = (int)XSTRLEN(name); - meth->name = (char*)XMALLOC((size_t)(name_len + 1), NULL, - DYNAMIC_TYPE_OPENSSL); - err = (meth->name == NULL); - - if (!err) { - XMEMCPY(meth->name, name, (size_t)(name_len + 1)); - } - - if (err) { - /* meth->name won't be allocated on error. */ - XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL); - meth = NULL; - } - return meth; -} - -/* Default RSA method is one with wolfSSL name and no flags. - * - * @return Newly allocated wolfSSL RSA method on success. - * @return NULL on failure. - */ -const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_default_method(void) -{ - static const WOLFSSL_RSA_METHOD wolfssl_rsa_meth = { - 0, /* No flags. */ - (char*)"wolfSSL RSA", - 0 /* Static definition. */ - }; - return &wolfssl_rsa_meth; -} - -/* Dispose of RSA method and allocated data. - * - * @param [in] meth RSA method to free. - */ -void wolfSSL_RSA_meth_free(WOLFSSL_RSA_METHOD *meth) -{ - /* Free method if available and dynamically allocated. */ - if ((meth != NULL) && meth->dynamic) { - /* Name was duplicated and must be freed. */ - XFREE(meth->name, NULL, DYNAMIC_TYPE_OPENSSL); - /* Dispose of RSA method. */ - XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL); - } -} - -#ifndef NO_WOLFSSL_STUB -/* Stub function for any RSA method setting function. - * - * Nothing is stored - not even flags or name. - * - * @param [in] meth RSA method. - * @param [in] p A pointer. - * @return 1 to indicate success. - */ -int wolfSSL_RSA_meth_set(WOLFSSL_RSA_METHOD *meth, void* p) -{ - WOLFSSL_STUB("RSA_METHOD is not implemented."); - - (void)meth; - (void)p; - - return 1; -} -#endif /* !NO_WOLFSSL_STUB */ -#endif /* OPENSSL_EXTRA */ - -/* - * RSA constructor/deconstructor APIs - */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Dispose of RSA key and allocated data. - * - * Cannot use rsa after this call. - * - * @param [in] rsa RSA key to free. - */ -void wolfSSL_RSA_free(WOLFSSL_RSA* rsa) -{ - int doFree = 1; - - WOLFSSL_ENTER("wolfSSL_RSA_free"); - - /* Validate parameter. */ - if (rsa == NULL) { - doFree = 0; - } - if (doFree) { - int err; - - /* Decrement reference count. */ - wolfSSL_RefDec(&rsa->ref, &doFree, &err); - #ifndef WOLFSSL_REFCNT_ERROR_RETURN - (void)err; - #endif - } - if (doFree) { - void* heap = rsa->heap; - - /* Dispose of allocated reference counting data. */ - wolfSSL_RefFree(&rsa->ref); - - #ifdef HAVE_EX_DATA_CLEANUP_HOOKS - wolfSSL_CRYPTO_cleanup_ex_data(&rsa->ex_data); - #endif - - if (rsa->internal != NULL) { - #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) - /* Check if RNG is owned before freeing it. */ - if (rsa->ownRng) { - WC_RNG* rng = ((RsaKey*)(rsa->internal))->rng; - if ((rng != NULL) && (rng != wolfssl_get_global_rng())) { - wc_FreeRng(rng); - XFREE(rng, heap, DYNAMIC_TYPE_RNG); - } - /* RNG isn't freed by wolfCrypt RSA free. */ - } - #endif - /* Dispose of allocated data in wolfCrypt RSA key. */ - wc_FreeRsaKey((RsaKey*)rsa->internal); - /* Dispose of memory for wolfCrypt RSA key. */ - XFREE(rsa->internal, heap, DYNAMIC_TYPE_RSA); - } - - /* Dispose of external representation of RSA values. */ - wolfSSL_BN_clear_free(rsa->iqmp); - wolfSSL_BN_clear_free(rsa->dmq1); - wolfSSL_BN_clear_free(rsa->dmp1); - wolfSSL_BN_clear_free(rsa->q); - wolfSSL_BN_clear_free(rsa->p); - wolfSSL_BN_clear_free(rsa->d); - wolfSSL_BN_free(rsa->e); - wolfSSL_BN_free(rsa->n); - - #if defined(OPENSSL_EXTRA) - if (rsa->meth) { - wolfSSL_RSA_meth_free((WOLFSSL_RSA_METHOD*)rsa->meth); - } - #endif - - /* Set back to NULLs for safety. */ - ForceZero(rsa, sizeof(*rsa)); - - XFREE(rsa, heap, DYNAMIC_TYPE_RSA); - (void)heap; - } -} - -/* Allocate and initialize a new RSA key. - * - * Not OpenSSL API. - * - * @param [in] heap Heap hint for dynamic memory allocation. - * @param [in] devId Device identifier value. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_RSA_new_ex(void* heap, int devId) -{ - WOLFSSL_RSA* rsa = NULL; - RsaKey* key = NULL; - int err = 0; - int rsaKeyInited = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_new"); - - /* Allocate memory for new wolfCrypt RSA key. */ - key = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA); - if (key == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_new malloc RsaKey failure"); - err = 1; - } - if (!err) { - /* Allocate memory for new RSA key. */ - rsa = (WOLFSSL_RSA*)XMALLOC(sizeof(WOLFSSL_RSA), heap, - DYNAMIC_TYPE_RSA); - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_new malloc WOLFSSL_RSA failure"); - err = 1; - } - } - if (!err) { - /* Clear all fields of RSA key. */ - XMEMSET(rsa, 0, sizeof(WOLFSSL_RSA)); - /* Cache heap to use for all allocations. */ - rsa->heap = heap; - #ifdef OPENSSL_EXTRA - /* Always have a method set. */ - rsa->meth = wolfSSL_RSA_get_default_method(); - #endif - - /* Initialize reference counting. */ - wolfSSL_RefInit(&rsa->ref, &err); -#ifdef WOLFSSL_REFCNT_ERROR_RETURN - } - if (!err) { -#endif - /* Initialize wolfCrypt RSA key. */ - if (wc_InitRsaKey_ex(key, heap, devId) != 0) { - WOLFSSL_ERROR_MSG("InitRsaKey WOLFSSL_RSA failure"); - err = 1; - } - else { - rsaKeyInited = 1; - } - } - #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) - if (!err) { - WC_RNG* rng; - - /* Create a local RNG. */ - rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), heap, DYNAMIC_TYPE_RNG); - if ((rng != NULL) && (wc_InitRng_ex(rng, heap, devId) != 0)) { - WOLFSSL_MSG("InitRng failure, attempting to use global RNG"); - XFREE(rng, heap, DYNAMIC_TYPE_RNG); - rng = NULL; - } - - rsa->ownRng = 1; - if (rng == NULL) { - /* Get the wolfSSL global RNG - not thread safe. */ - rng = wolfssl_get_global_rng(); - rsa->ownRng = 0; - } - if (rng == NULL) { - /* Couldn't create global either. */ - WOLFSSL_ERROR_MSG("wolfSSL_RSA_new no WC_RNG for blinding"); - err = 1; - } - else { - /* Set the local or global RNG into the wolfCrypt RSA key. */ - (void)wc_RsaSetRNG(key, rng); - /* Won't fail as key and rng are not NULL. */ - } - } - #endif /* !HAVE_FIPS && WC_RSA_BLINDING */ - if (!err) { - /* Set wolfCrypt RSA key into RSA key. */ - rsa->internal = key; - /* Data from external RSA key has not been set into internal one. */ - rsa->inSet = 0; - } - - if (err) { - /* Dispose of any allocated data on error. */ - /* No failure after RNG allocation - no need to free RNG. */ - if (rsaKeyInited) { - wc_FreeRsaKey(key); - } - XFREE(key, heap, DYNAMIC_TYPE_RSA); - XFREE(rsa, heap, DYNAMIC_TYPE_RSA); - /* Return NULL. */ - rsa = NULL; - } - return rsa; -} - -/* Allocate and initialize a new RSA key. - * - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_RSA_new(void) -{ - /* Call wolfSSL API to do work. */ - return wolfSSL_RSA_new_ex(NULL, INVALID_DEVID); -} - -/* Increments ref count of RSA key. - * - * @param [in, out] rsa RSA key. - * @return 1 on success - * @return 0 on error - */ -int wolfSSL_RSA_up_ref(WOLFSSL_RSA* rsa) -{ - int err = 0; - if (rsa != NULL) { - wolfSSL_RefInc(&rsa->ref, &err); - } - return !err; -} - -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#ifdef OPENSSL_EXTRA - -#if defined(WOLFSSL_KEY_GEN) - -/* Allocate a new RSA key and make it a copy. - * - * Encodes to and from DER to copy. - * - * @param [in] rsa RSA key to duplicate. - * @return RSA key on success. - * @return NULL on error. - */ -WOLFSSL_RSA* wolfSSL_RSAPublicKey_dup(WOLFSSL_RSA *rsa) -{ - WOLFSSL_RSA* ret = NULL; - int derSz = 0; - byte* derBuf = NULL; - int err; - - WOLFSSL_ENTER("wolfSSL_RSAPublicKey_dup"); - - err = (rsa == NULL); - if (!err) { - /* Create a new RSA key to return. */ - ret = wolfSSL_RSA_new(); - if (ret == NULL) { - WOLFSSL_ERROR_MSG("Error creating a new WOLFSSL_RSA structure"); - err = 1; - } - } - if (!err) { - /* Encode RSA public key to copy to DER - allocates DER buffer. */ - if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, rsa->heap)) < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - err = 1; - } - } - if (!err) { - /* Decode DER of the RSA public key into new key. */ - if (wolfSSL_RSA_LoadDer_ex(ret, derBuf, derSz, - WOLFSSL_RSA_LOAD_PUBLIC) != 1) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_LoadDer_ex failed"); - err = 1; - } - } - - /* Dispose of any allocated DER buffer. */ - XFREE(derBuf, rsa ? rsa->heap : NULL, DYNAMIC_TYPE_ASN1); - if (err) { - /* Disposes of any created RSA key - on error. */ - wolfSSL_RSA_free(ret); - ret = NULL; - } - return ret; -} - -/* wolfSSL_RSAPrivateKey_dup not supported */ - -#endif /* WOLFSSL_KEY_GEN */ - -static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, - void* heap); - -/* - * RSA to/from bin APIs - */ - -/* Convert RSA public key data to internal. - * - * Creates new RSA key from the DER encoded RSA public key. - * - * @param [out] out Pointer to RSA key to return through. May be NULL. - * @param [in, out] derBuf Pointer to start of DER encoded data. - * @param [in] derSz Length of the data in the DER buffer. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA *wolfSSL_d2i_RSAPublicKey(WOLFSSL_RSA **out, - const unsigned char **derBuf, long derSz) -{ - WOLFSSL_RSA *rsa = NULL; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_d2i_RSAPublicKey"); - - /* Validate parameters. */ - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("Bad argument"); - err = 1; - } - /* Create a new RSA key to return. */ - if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { - WOLFSSL_ERROR_MSG("RSA_new failed"); - err = 1; - } - /* Decode RSA key from DER. */ - if ((!err) && (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz, - WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { - WOLFSSL_ERROR_MSG("RSA_LoadDer failed"); - err = 1; - } - if ((!err) && (out != NULL)) { - /* Return through parameter too. */ - *out = rsa; - /* Move buffer on by the used amount. */ - *derBuf += wolfssl_der_length(*derBuf, (int)derSz); - } - - if (err) { - /* Dispose of any created RSA key. */ - wolfSSL_RSA_free(rsa); - rsa = NULL; - } - return rsa; -} - -/* Convert RSA private key data to internal. - * - * Create a new RSA key from the DER encoded RSA private key. - * - * @param [out] out Pointer to RSA key to return through. May be NULL. - * @param [in, out] derBuf Pointer to start of DER encoded data. - * @param [in] derSz Length of the data in the DER buffer. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA *wolfSSL_d2i_RSAPrivateKey(WOLFSSL_RSA **out, - const unsigned char **derBuf, long derSz) -{ - WOLFSSL_RSA *rsa = NULL; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_d2i_RSAPublicKey"); - - /* Validate parameters. */ - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("Bad argument"); - err = 1; - } - /* Create a new RSA key to return. */ - if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { - WOLFSSL_ERROR_MSG("RSA_new failed"); - err = 1; - } - /* Decode RSA key from DER. */ - if ((!err) && (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz, - WOLFSSL_RSA_LOAD_PRIVATE) != 1)) { - WOLFSSL_ERROR_MSG("RSA_LoadDer failed"); - err = 1; - } - if ((!err) && (out != NULL)) { - /* Return through parameter too. */ - *out = rsa; - /* Move buffer on by the used amount. */ - *derBuf += wolfssl_der_length(*derBuf, (int)derSz); - } - - if (err) { - /* Dispose of any created RSA key. */ - wolfSSL_RSA_free(rsa); - rsa = NULL; - } - return rsa; -} - -/* Converts an internal RSA structure to DER format for the private key. - * - * If "pp" is null then buffer size only is returned. - * If "*pp" is null then a created buffer is set in *pp and the caller is - * responsible for free'ing it. - * - * @param [in] rsa RSA key. - * @param [in, out] pp On in, pointer to allocated buffer or NULL. - * May be NULL. - * On out, newly allocated buffer or pointer to byte after - * encoding in passed in buffer. - * - * @return Size of DER encoding on success - * @return BAD_FUNC_ARG when rsa is NULL. - * @return 0 on failure. - */ -int wolfSSL_i2d_RSAPrivateKey(WOLFSSL_RSA *rsa, unsigned char **pp) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_i2d_RSAPrivateKey"); - - /* Validate parameters. */ - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Bad Function Arguments"); - ret = BAD_FUNC_ARG; - } - /* Encode the RSA key as a DER. Call allocates buffer into pp. - * No heap hint as this gets returned to the user */ - else if ((ret = wolfSSL_RSA_To_Der_ex(rsa, pp, 0, NULL)) < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - ret = 0; - } - - /* Size of DER encoding. */ - return ret; -} - -/* Converts an internal RSA structure to DER format for the public key. - * - * If "pp" is null then buffer size only is returned. - * If "*pp" is null then a created buffer is set in *pp and the caller is - * responsible for free'ing it. - * - * @param [in] rsa RSA key. - * @param [in, out] pp On in, pointer to allocated buffer or NULL. - * May be NULL. - * On out, newly allocated buffer or pointer to byte after - * encoding in passed in buffer. - * @return Size of DER encoding on success - * @return BAD_FUNC_ARG when rsa is NULL. - * @return 0 on failure. - */ -int wolfSSL_i2d_RSAPublicKey(WOLFSSL_RSA *rsa, unsigned char **pp) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_i2d_RSAPublicKey"); - - /* check for bad functions arguments */ - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Bad Function Arguments"); - ret = BAD_FUNC_ARG; - } - /* Encode the RSA key as a DER. Call allocates buffer into pp. - * No heap hint as this gets returned to the user */ - else if ((ret = wolfSSL_RSA_To_Der_ex(rsa, pp, 1, NULL)) < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - ret = 0; - } - - return ret; -} - -#endif /* OPENSSL_EXTRA */ - -/* - * RSA to/from BIO APIs - */ - -/* wolfSSL_d2i_RSAPublicKey_bio not supported */ - -#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ - || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) - -#if defined(WOLFSSL_KEY_GEN) && !defined(NO_BIO) - -/* Read DER data from a BIO. - * - * DER structures start with a constructed sequence. Use this to calculate the - * total length of the DER data. - * - * @param [in] bio BIO object to read from. - * @param [out] out Buffer holding DER encoding. - * @return Number of bytes to DER encoding on success. - * @return 0 on failure. - */ -static int wolfssl_read_der_bio(WOLFSSL_BIO* bio, unsigned char** out) -{ - int err = 0; - unsigned char seq[MAX_SEQ_SZ]; - unsigned char* der = NULL; - int derLen = 0; - - /* Read in a minimal amount to get a SEQUENCE header of any size. */ - if (wolfSSL_BIO_read(bio, seq, sizeof(seq)) != sizeof(seq)) { - WOLFSSL_ERROR_MSG("wolfSSL_BIO_read() of sequence failure"); - err = 1; - } - /* Calculate complete DER encoding length. */ - if ((!err) && ((derLen = wolfssl_der_length(seq, sizeof(seq))) <= 0)) { - WOLFSSL_ERROR_MSG("DER SEQUENCE decode failed"); - err = 1; - } - /* Allocate a buffer to read DER data into. */ - if ((!err) && ((der = (unsigned char*)XMALLOC((size_t)derLen, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER)) == NULL)) { - WOLFSSL_ERROR_MSG("Malloc failure"); - err = 1; - } - if ((!err) && (derLen <= (int)sizeof(seq))) { - /* Copy the previously read data into the buffer. */ - XMEMCPY(der, seq, derLen); - } - else if (!err) { - /* Calculate the unread amount. */ - int len = derLen - (int)sizeof(seq); - /* Copy the previously read data into the buffer. */ - XMEMCPY(der, seq, sizeof(seq)); - /* Read rest of DER data from BIO. */ - if (wolfSSL_BIO_read(bio, der + sizeof(seq), len) != len) { - WOLFSSL_ERROR_MSG("wolfSSL_BIO_read() failure"); - err = 1; - } - } - if (!err) { - /* Return buffer through parameter. */ - *out = der; - } - - if (err) { - /* Dispose of any allocated buffer on error. */ - XFREE(der, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - derLen = 0; - } - return derLen; -} - -/* Reads the RSA private key data from a BIO to the internal form. - * - * Creates new RSA key from the DER encoded RSA private key read from the BIO. - * - * @param [in] bio BIO object to read from. - * @param [out] out Pointer to RSA key to return through. May be NULL. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_d2i_RSAPrivateKey_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out) -{ - WOLFSSL_RSA* key = NULL; - unsigned char* der = NULL; - int derLen = 0; - int err; - - WOLFSSL_ENTER("wolfSSL_d2i_RSAPrivateKey_bio"); - - /* Validate parameters. */ - err = (bio == NULL); - /* Read just DER encoding from BIO - buffer allocated in call. */ - if ((!err) && ((derLen = wolfssl_read_der_bio(bio, &der)) == 0)) { - err = 1; - } - if (!err) { - /* Keep der for call to deallocate. */ - const unsigned char* cder = der; - /* Create an RSA key from the data from the BIO. */ - key = wolfSSL_d2i_RSAPrivateKey(NULL, &cder, derLen); - err = (key == NULL); - } - if ((!err) && (out != NULL)) { - /* Return the created RSA key through the parameter. */ - *out = key; - } - - if (err) { - /* Dispose of created key on error. */ - wolfSSL_RSA_free(key); - key = NULL; - } - /* Dispose of allocated data. */ - XFREE(der, bio ? bio->heap : NULL, DYNAMIC_TYPE_TMP_BUFFER); - return key; -} -#endif /* defined(WOLFSSL_KEY_GEN) && !NO_BIO */ - -#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ - -/* - * RSA DER APIs - */ - -#ifdef OPENSSL_EXTRA - -/* Create a DER encoding of key. - * - * Not OpenSSL API. - * - * @param [in] rsa RSA key. - * @param [out] outBuf Allocated buffer containing DER encoding. - * May be NULL. - * @param [in] publicKey Whether to encode as public key. - * @param [in] heap Heap hint. - * @return Encoding size on success. - * @return Negative on failure. - */ -int wolfSSL_RSA_To_Der(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, - void* heap) -{ - byte* p = NULL; - int ret; - - if (outBuf != NULL) { - p = *outBuf; - } - ret = wolfSSL_RSA_To_Der_ex(rsa, outBuf, publicKey, heap); - if ((ret > 0) && (p != NULL)) { - *outBuf = p; - } - return ret; -} - -/* Create a DER encoding of key. - * - * Buffer allocated with heap and DYNAMIC_TYPE_TMP_BUFFER. - * - * @param [in] rsa RSA key. - * @param [in, out] outBuf On in, pointer to allocated buffer or NULL. - * May be NULL. - * On out, newly allocated buffer or pointer to byte - * after encoding in passed in buffer. - * @param [in] publicKey Whether to encode as public key. - * @param [in] heap Heap hint. - * @return Encoding size on success. - * @return Negative on failure. - */ -static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, - void* heap) -{ - int ret = 1; - int derSz = 0; - byte* derBuf = NULL; - - WOLFSSL_ENTER("wolfSSL_RSA_To_Der"); - - /* Unused if memory is disabled. */ - (void)heap; - - /* Validate parameters. */ - if ((rsa == NULL) || ((publicKey != 0) && (publicKey != 1))) { - WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", BAD_FUNC_ARG); - ret = BAD_FUNC_ARG; - } - /* Push external RSA data into internal RSA key if not set. */ - if ((ret == 1) && (!rsa->inSet)) { - ret = SetRsaInternal(rsa); - } - /* wc_RsaKeyToPublicDer encode regardless of values. */ - if ((ret == 1) && publicKey && (mp_iszero(&((RsaKey*)rsa->internal)->n) || - mp_iszero(&((RsaKey*)rsa->internal)->e))) { - ret = BAD_FUNC_ARG; - } - - if (ret == 1) { - if (publicKey) { - /* Calculate length of DER encoded RSA public key. */ - derSz = wc_RsaPublicKeyDerSize((RsaKey*)rsa->internal, 1); - if (derSz < 0) { - WOLFSSL_ERROR_MSG("wc_RsaPublicKeyDerSize failed"); - ret = derSz; - } - } - else { - /* Calculate length of DER encoded RSA private key. */ - derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, NULL, 0); - if (derSz < 0) { - WOLFSSL_ERROR_MSG("wc_RsaKeyToDer failed"); - ret = derSz; - } - } - } - - if ((ret == 1) && (outBuf != NULL)) { - derBuf = *outBuf; - if (derBuf == NULL) { - /* Allocate buffer to hold DER encoded RSA key. */ - derBuf = (byte*)XMALLOC((size_t)derSz, heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("Memory allocation failed"); - ret = MEMORY_ERROR; - } - } - } - if ((ret == 1) && (outBuf != NULL)) { - if (publicKey > 0) { - /* RSA public key to DER. */ - derSz = wc_RsaKeyToPublicDer((RsaKey*)rsa->internal, derBuf, - (word32)derSz); - } - else { - /* RSA private key to DER. */ - derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, derBuf, - (word32)derSz); - } - if (derSz < 0) { - WOLFSSL_ERROR_MSG("RSA key encoding failed"); - ret = derSz; - } - else if ((*outBuf) != NULL) { - derBuf = NULL; - *outBuf += derSz; - } - else { - /* Return allocated buffer. */ - *outBuf = derBuf; - } - } - if (ret == 1) { - /* Success - return DER encoding size. */ - ret = derSz; - } - - if ((outBuf != NULL) && (*outBuf != derBuf)) { - /* Not returning buffer, needs to be disposed of. */ - XFREE(derBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); - } - WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", ret); - return ret; -} - -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Load the DER encoded private RSA key. - * - * Not OpenSSL API. - * - * @param [in] rsa RSA key. - * @param [in] derBuf Buffer holding DER encoding. - * @param [in] derSz Length of DER encoding. - * @return 1 on success. - * @return -1 on failure. - */ -int wolfSSL_RSA_LoadDer(WOLFSSL_RSA* rsa, const unsigned char* derBuf, - int derSz) -{ - /* Call implementation that handles both private and public keys. */ - return wolfSSL_RSA_LoadDer_ex(rsa, derBuf, derSz, WOLFSSL_RSA_LOAD_PRIVATE); -} - -/* Load the DER encoded public or private RSA key. - * - * Not OpenSSL API. - * - * @param [in] rsa RSA key. - * @param [in] derBuf Buffer holding DER encoding. - * @param [in] derSz Length of DER encoding. - * @param [in] opt Indicates public or private key. - * (WOLFSSL_RSA_LOAD_PUBLIC or WOLFSSL_RSA_LOAD_PRIVATE) - * @return 1 on success. - * @return -1 on failure. - */ -int wolfSSL_RSA_LoadDer_ex(WOLFSSL_RSA* rsa, const unsigned char* derBuf, - int derSz, int opt) -{ - int ret = 1; - int res; - word32 idx = 0; - word32 algId; - - WOLFSSL_ENTER("wolfSSL_RSA_LoadDer"); - - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->internal == NULL) || (derBuf == NULL) || - (derSz <= 0)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 1) { - rsa->pkcs8HeaderSz = 0; - /* Check if input buffer has PKCS8 header. In the case that it does not - * have a PKCS8 header then do not error out. */ - res = ToTraditionalInline_ex((const byte*)derBuf, &idx, (word32)derSz, - &algId); - if (res > 0) { - /* Store size of PKCS#8 header for encoding. */ - WOLFSSL_MSG("Found PKCS8 header"); - rsa->pkcs8HeaderSz = (word16)idx; - } - /* When decoding and not PKCS#8, return will be ASN_PARSE_E. */ - else if (res != WC_NO_ERR_TRACE(ASN_PARSE_E)) { - /* Something went wrong while decoding. */ - WOLFSSL_ERROR_MSG("Unexpected error with trying to remove PKCS#8 " - "header"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Decode private or public key data. */ - if (opt == WOLFSSL_RSA_LOAD_PRIVATE) { - res = wc_RsaPrivateKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, - (word32)derSz); - } - else { - res = wc_RsaPublicKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, - (word32)derSz); - } - /* Check for error. */ - if (res < 0) { - if (opt == WOLFSSL_RSA_LOAD_PRIVATE) { - WOLFSSL_ERROR_MSG("RsaPrivateKeyDecode failed"); - } - else { - WOLFSSL_ERROR_MSG("RsaPublicKeyDecode failed"); - } - WOLFSSL_ERROR_VERBOSE(res); - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Set external RSA key data from wolfCrypt key. */ - if (SetRsaExternal(rsa) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - else { - rsa->inSet = 1; - } - } - - return ret; -} - -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) - -#if !defined(NO_BIO) || !defined(NO_FILESYSTEM) -/* Load DER encoded data into WOLFSSL_RSA object. - * - * Creates a new WOLFSSL_RSA object if one is not passed in. - * - * @param [in, out] rsa WOLFSSL_RSA object to load into. - * When rsa or *rsa is NULL a new object is created. - * When not NULL and *rsa is NULL then new object - * returned through pointer. - * @param [in] in DER encoded RSA key data. - * @param [in] inSz Size of DER encoded data in bytes. - * @param [in] opt Public or private key encoded in data. Valid values: - * WOLFSSL_RSA_LOAD_PRIVATE, WOLFSSL_RSA_LOAD_PUBLIC. - * @return NULL on failure. - * @return WOLFSSL_RSA object on success. - */ -static WOLFSSL_RSA* wolfssl_rsa_d2i(WOLFSSL_RSA** rsa, const unsigned char* in, - long inSz, int opt) -{ - WOLFSSL_RSA* ret = NULL; - - if ((rsa != NULL) && (*rsa != NULL)) { - ret = *rsa; - } - else { - ret = wolfSSL_RSA_new(); - } - if ((ret != NULL) && (wolfSSL_RSA_LoadDer_ex(ret, in, (int)inSz, opt) - != 1)) { - if ((rsa == NULL) || (ret != *rsa)) { - wolfSSL_RSA_free(ret); - } - ret = NULL; - } - - if ((rsa != NULL) && (*rsa == NULL)) { - *rsa = ret; - } - return ret; -} -#endif - -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ - -/* - * RSA PEM APIs - */ - -#ifdef OPENSSL_EXTRA - -#ifndef NO_BIO -#if defined(WOLFSSL_KEY_GEN) -/* Writes PEM encoding of an RSA public key to a BIO. - * - * @param [in] bio BIO object to write to. - * @param [in] rsa RSA key to write. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa) -{ - int ret = 1; - int derSz = 0; - byte* derBuf = NULL; - - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSA_PUBKEY"); - - /* Validate parameters. */ - if ((bio == NULL) || (rsa == NULL)) { - WOLFSSL_ERROR_MSG("Bad Function Arguments"); - return 0; - } - - if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, bio->heap)) < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - ret = 0; - } - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed to get buffer"); - ret = 0; - } - if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, - PUBLICKEY_TYPE) != 1)) { - ret = 0; - } - - /* Dispose of DER buffer. */ - XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - return ret; -} - -#endif /* WOLFSSL_KEY_GEN */ -#endif /* !NO_BIO */ - -#if defined(WOLFSSL_KEY_GEN) -#ifndef NO_FILESYSTEM - -/* Writes PEM encoding of an RSA public key to a file pointer. - * - * @param [in] fp File pointer to write to. - * @param [in] rsa RSA key to write. - * @param [in] type PEM type to write out. - * @return 1 on success. - * @return 0 on failure. - */ -static int wolfssl_pem_write_rsa_public_key(XFILE fp, WOLFSSL_RSA* rsa, - int type) -{ - int ret = 1; - int derSz; - byte* derBuf = NULL; - - /* Validate parameters. */ - if ((fp == XBADFILE) || (rsa == NULL)) { - WOLFSSL_ERROR_MSG("Bad Function Arguments"); - return 0; - } - - if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, rsa->heap)) < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - ret = 0; - } - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed to get buffer"); - ret = 0; - } - if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, type, - rsa->heap) != 1)) { - ret = 0; - } - - /* Dispose of DER buffer. */ - XFREE(derBuf, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} - -/* Writes PEM encoding of an RSA public key to a file pointer. - * - * Header/footer will contain: PUBLIC KEY - * - * @param [in] fp File pointer to write to. - * @param [in] rsa RSA key to write. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_RSA_PUBKEY(XFILE fp, WOLFSSL_RSA* rsa) -{ - return wolfssl_pem_write_rsa_public_key(fp, rsa, PUBLICKEY_TYPE); -} - -/* Writes PEM encoding of an RSA public key to a file pointer. - * - * Header/footer will contain: RSA PUBLIC KEY - * - * @param [in] fp File pointer to write to. - * @param [in] rsa RSA key to write. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_RSAPublicKey(XFILE fp, WOLFSSL_RSA* rsa) -{ - return wolfssl_pem_write_rsa_public_key(fp, rsa, RSA_PUBLICKEY_TYPE); -} -#endif /* !NO_FILESYSTEM */ -#endif /* WOLFSSL_KEY_GEN */ - -#ifndef NO_BIO -/* Create an RSA public key by reading the PEM encoded data from the BIO. - * - * @param [in] bio BIO object to read from. - * @param [out] out RSA key created. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA *wolfSSL_PEM_read_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, - WOLFSSL_RSA** out, wc_pem_password_cb* cb, void *pass) -{ - WOLFSSL_RSA* rsa = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSA_PUBKEY"); - - if ((bio != NULL) && (pem_read_bio_key(bio, cb, pass, PUBLICKEY_TYPE, - &keyFormat, &der) >= 0)) { - rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, - WOLFSSL_RSA_LOAD_PUBLIC); - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); - } - } - - FreeDer(&der); - if ((out != NULL) && (rsa != NULL)) { - *out = rsa; - } - return rsa; -} - -WOLFSSL_RSA *wolfSSL_d2i_RSA_PUBKEY_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out) -{ - char* data = NULL; - int dataSz = 0; - int memAlloced = 0; - WOLFSSL_RSA* rsa = NULL; - - WOLFSSL_ENTER("wolfSSL_d2i_RSA_PUBKEY_bio"); - - if (bio == NULL) - return NULL; - - if (wolfssl_read_bio(bio, &data, &dataSz, &memAlloced) != 0) { - if (memAlloced) - XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return NULL; - } - - rsa = wolfssl_rsa_d2i(out, (const unsigned char*)data, dataSz, - WOLFSSL_RSA_LOAD_PUBLIC); - if (memAlloced) - XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - return rsa; -} -#endif /* !NO_BIO */ - -#ifndef NO_FILESYSTEM -/* Create an RSA public key by reading the PEM encoded data from the BIO. - * - * Header/footer should contain: PUBLIC KEY - * PEM decoder supports either 'RSA PUBLIC KEY' or 'PUBLIC KEY'. - * - * @param [in] fp File pointer to read from. - * @param [out] out RSA key created. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA *wolfSSL_PEM_read_RSA_PUBKEY(XFILE fp, - WOLFSSL_RSA** out, wc_pem_password_cb* cb, void *pass) -{ - WOLFSSL_RSA* rsa = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_RSA_PUBKEY"); - - if ((fp != XBADFILE) && (pem_read_file_key(fp, cb, pass, PUBLICKEY_TYPE, - &keyFormat, &der) >= 0)) { - rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, - WOLFSSL_RSA_LOAD_PUBLIC); - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); - } - } - - FreeDer(&der); - if ((out != NULL) && (rsa != NULL)) { - *out = rsa; - } - return rsa; -} - -/* Create an RSA public key by reading the PEM encoded data from the BIO. - * - * Header/footer should contain: RSA PUBLIC KEY - * PEM decoder supports either 'RSA PUBLIC KEY' or 'PUBLIC KEY'. - * - * @param [in] fp File pointer to read from. - * @param [out] rsa RSA key created. - * @param [in] cb Password callback when PEM encrypted. May be NULL. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * May be NULL. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_PEM_read_RSAPublicKey(XFILE fp, WOLFSSL_RSA** rsa, - wc_pem_password_cb* cb, void* pass) -{ - return wolfSSL_PEM_read_RSA_PUBKEY(fp, rsa, cb, pass); -} - -#endif /* NO_FILESYSTEM */ - -#if defined(WOLFSSL_KEY_GEN) && \ - (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) - -/* Writes PEM encoding of an RSA private key to newly allocated buffer. - * - * Buffer returned was allocated with: DYNAMIC_TYPE_KEY. - * - * @param [in] rsa RSA key to write. - * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. - * @param [in] passwd Password string when PEM encrypted. May be NULL. - * @param [in] passwdSz Length of password string when PEM encrypted. - * @param [out] pem Allocated buffer with PEM encoding. - * @param [out] pLen Length of PEM encoding. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_mem_RSAPrivateKey(WOLFSSL_RSA* rsa, - const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, - unsigned char **pem, int *pLen) -{ - int ret = 1; - byte* derBuf = NULL; - int derSz = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_write_mem_RSAPrivateKey"); - - /* Validate parameters. */ - if ((pem == NULL) || (pLen == NULL) || (rsa == NULL) || - (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - - /* Set the RSA key data into the wolfCrypt RSA key if not done so. */ - if ((ret == 1) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = 0; - } - - /* Encode wolfCrypt RSA key to DER - derBuf allocated in call. */ - if ((ret == 1) && ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 0, - rsa->heap)) < 0)) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - ret = 0; - } - - if ((ret == 1) && (der_to_enc_pem_alloc(derBuf, derSz, cipher, passwd, - passwdSz, PRIVATEKEY_TYPE, NULL, pem, pLen) != 1)) { - WOLFSSL_ERROR_MSG("der_to_enc_pem_alloc failed"); - ret = 0; - } - - return ret; -} - -#ifndef NO_BIO -/* Writes PEM encoding of an RSA private key to a BIO. - * - * @param [in] bio BIO object to write to. - * @param [in] rsa RSA key to write. - * @param [in] cipher Cipher to use when PEM encrypted. - * @param [in] passwd Password string when PEM encrypted. - * @param [in] len Length of password string when PEM encrypted. - * @param [in] cb Password callback to use when PEM encrypted. - * @param [in] arg NUL terminated string for passphrase when PEM encrypted. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_bio_RSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa, - const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int len, - wc_pem_password_cb* cb, void* arg) -{ - int ret = 1; - byte* pem = NULL; - int pLen = 0; - - (void)cb; - (void)arg; - - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSAPrivateKey"); - - /* Validate parameters. */ - if ((bio == NULL) || (rsa == NULL) || (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - - if (ret == 1) { - /* Write PEM to buffer that is allocated in the call. */ - ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, cipher, passwd, len, - &pem, &pLen); - if (ret != 1) { - WOLFSSL_ERROR_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed"); - } - } - /* Write PEM to BIO. */ - if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) <= 0)) { - WOLFSSL_ERROR_MSG("RSA private key BIO write failed"); - ret = 0; - } - - /* Dispose of any allocated PEM buffer. */ - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); - return ret; -} -#endif /* !NO_BIO */ - -#ifndef NO_FILESYSTEM -/* Writes PEM encoding of an RSA private key to a file pointer. - * - * TODO: Support use of the password callback and callback context. - * - * @param [in] fp File pointer to write to. - * @param [in] rsa RSA key to write. - * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. - * @param [in] passwd Password string when PEM encrypted. May be NULL. - * @param [in] passwdSz Length of password string when PEM encrypted. - * @param [in] cb Password callback to use when PEM encrypted. Unused. - * @param [in] arg NUL terminated string for passphrase when PEM - * encrypted. Unused. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_RSAPrivateKey(XFILE fp, WOLFSSL_RSA *rsa, - const WOLFSSL_EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz, - wc_pem_password_cb *cb, void *arg) -{ - int ret = 1; - byte* pem = NULL; - int pLen = 0; - - (void)cb; - (void)arg; - - WOLFSSL_ENTER("wolfSSL_PEM_write_RSAPrivateKey"); - - /* Validate parameters. */ - if ((fp == XBADFILE) || (rsa == NULL) || (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - - if (ret == 1) { - /* Write PEM to buffer that is allocated in the call. */ - ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, cipher, passwd, passwdSz, - &pem, &pLen); - if (ret != 1) { - WOLFSSL_ERROR_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed"); - } - } - /* Write PEM to file pointer. */ - if ((ret == 1) && ((int)XFWRITE(pem, 1, (size_t)pLen, fp) != pLen)) { - WOLFSSL_ERROR_MSG("RSA private key file write failed"); - ret = 0; - } - - /* Dispose of any allocated PEM buffer. */ - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); - return ret; -} -#endif /* NO_FILESYSTEM */ -#endif /* WOLFSSL_KEY_GEN && WOLFSSL_PEM_TO_DER */ - -#ifndef NO_BIO -/* Create an RSA private key by reading the PEM encoded data from the BIO. - * - * @param [in] bio BIO object to read from. - * @param [out] out RSA key created. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_PEM_read_bio_RSAPrivateKey(WOLFSSL_BIO* bio, - WOLFSSL_RSA** out, wc_pem_password_cb* cb, void* pass) -{ - WOLFSSL_RSA* rsa = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSAPrivateKey"); - - if ((bio != NULL) && (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, - &keyFormat, &der) >= 0)) { - rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, - WOLFSSL_RSA_LOAD_PRIVATE); - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); - } - } - - FreeDer(&der); - if ((out != NULL) && (rsa != NULL)) { - *out = rsa; - } - return rsa; -} -#endif /* !NO_BIO */ - -/* Create an RSA private key by reading the PEM encoded data from the file - * pointer. - * - * @param [in] fp File pointer to read from. - * @param [out] out RSA key created. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * @return RSA key on success. - * @return NULL on failure. - */ -#ifndef NO_FILESYSTEM -WOLFSSL_RSA* wolfSSL_PEM_read_RSAPrivateKey(XFILE fp, WOLFSSL_RSA** out, - wc_pem_password_cb* cb, void* pass) -{ - WOLFSSL_RSA* rsa = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_RSAPrivateKey"); - - if ((fp != XBADFILE) && (pem_read_file_key(fp, cb, pass, PRIVATEKEY_TYPE, - &keyFormat, &der) >= 0)) { - rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, - WOLFSSL_RSA_LOAD_PRIVATE); - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); - } - } - - FreeDer(&der); - if ((out != NULL) && (rsa != NULL)) { - *out = rsa; - } - return rsa; -} -#endif /* !NO_FILESYSTEM */ - -/* - * RSA print APIs - */ - -#if defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \ - !defined(NO_STDIO_FILESYSTEM) -/* Print an RSA key to a file pointer. - * - * @param [in] fp File pointer to write to. - * @param [in] rsa RSA key to write. - * @param [in] indent Number of spaces to prepend to each line. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_print_fp(XFILE fp, WOLFSSL_RSA* rsa, int indent) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_RSA_print_fp"); - - /* Validate parameters. */ - if ((fp == XBADFILE) || (rsa == NULL)) { - ret = 0; - } - - /* Set the external data from the wolfCrypt RSA key if not done. */ - if ((ret == 1) && (!rsa->exSet)) { - ret = SetRsaExternal(rsa); - } - - /* Get the key size from modulus if available. */ - if ((ret == 1) && (rsa->n != NULL)) { - int keySize = wolfSSL_BN_num_bits(rsa->n); - if (keySize == 0) { - ret = 0; - } - else { - if (XFPRINTF(fp, "%*s", indent, "") < 0) - ret = 0; - else if (XFPRINTF(fp, "RSA Private-Key: (%d bit, 2 primes)\n", - keySize) < 0) - ret = 0; - } - } - /* Print out any components available. */ - if ((ret == 1) && (rsa->n != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "modulus", rsa->n); - } - if ((ret == 1) && (rsa->d != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "privateExponent", rsa->d); - } - if ((ret == 1) && (rsa->p != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "prime1", rsa->p); - } - if ((ret == 1) && (rsa->q != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "prime2", rsa->q); - } - if ((ret == 1) && (rsa->dmp1 != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "exponent1", rsa->dmp1); - } - if ((ret == 1) && (rsa->dmq1 != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "exponent2", rsa->dmq1); - } - if ((ret == 1) && (rsa->iqmp != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "coefficient", rsa->iqmp); - } - - WOLFSSL_LEAVE("wolfSSL_RSA_print_fp", ret); - - return ret; -} -#endif /* XFPRINTF && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ - -#if defined(XSNPRINTF) && !defined(NO_BIO) -/* snprintf() must be available */ - -/* Maximum size of a header line. */ -#define RSA_PRINT_MAX_HEADER_LINE PRINT_NUM_MAX_INDENT - -/* Writes the human readable form of RSA to a BIO. - * - * @param [in] bio BIO object to write to. - * @param [in] rsa RSA key to write. - * @param [in] indent Number of spaces before each line. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_print(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa, int indent) -{ - int ret = 1; - int sz = 0; - RsaKey* key = NULL; - char line[RSA_PRINT_MAX_HEADER_LINE]; - int i = 0; - mp_int *num = NULL; - /* Header strings. */ - const char *name[] = { - "Modulus:", "Exponent:", "PrivateExponent:", "Prime1:", "Prime2:", - "Exponent1:", "Exponent2:", "Coefficient:" - }; - - WOLFSSL_ENTER("wolfSSL_RSA_print"); - - /* Validate parameters. */ - if ((bio == NULL) || (rsa == NULL) || (indent > PRINT_NUM_MAX_INDENT)) { - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 1) { - key = (RsaKey*)rsa->internal; - - /* Get size in bits of key for printing out. */ - sz = wolfSSL_RSA_bits(rsa); - if (sz <= 0) { - WOLFSSL_ERROR_MSG("Error getting RSA key size"); - ret = 0; - } - } - if (ret == 1) { - /* Print any indent spaces. */ - ret = wolfssl_print_indent(bio, line, sizeof(line), indent); - } - if (ret == 1) { - /* Print header line. */ - int len = XSNPRINTF(line, sizeof(line), "\nRSA %s: (%d bit)\n", - (!mp_iszero(&key->d)) ? "Private-Key" : "Public-Key", sz); - if (len >= (int)sizeof(line)) { - WOLFSSL_ERROR_MSG("Buffer overflow while formatting key preamble"); - ret = 0; - } - else { - if (wolfSSL_BIO_write(bio, line, len) <= 0) { - ret = 0; - } - } - } - - for (i = 0; (ret == 1) && (i < RSA_INTS); i++) { - /* Get mp_int for index. */ - switch (i) { - case 0: - /* Print out modulus */ - num = &key->n; - break; - case 1: - num = &key->e; - break; - case 2: - num = &key->d; - break; - case 3: - num = &key->p; - break; - case 4: - num = &key->q; - break; - case 5: - num = &key->dP; - break; - case 6: - num = &key->dQ; - break; - case 7: - num = &key->u; - break; - default: - WOLFSSL_ERROR_MSG("Bad index value"); - } - - if (i == 1) { - /* Print exponent as a 32-bit value. */ - ret = wolfssl_print_value(bio, num, name[i], indent); - } - else if (!mp_iszero(num)) { - /* Print name and MP integer. */ - ret = wolfssl_print_number(bio, num, name[i], indent); - } - } - - return ret; -} -#endif /* XSNPRINTF && !NO_BIO */ - -#endif /* OPENSSL_EXTRA */ - -/* - * RSA get/set/test APIs - */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Set RSA key data (external) from wolfCrypt RSA key (internal). - * - * @param [in, out] rsa RSA key. - * @return 1 on success. - * @return 0 on failure. - */ -int SetRsaExternal(WOLFSSL_RSA* rsa) -{ - int ret = 1; - - WOLFSSL_ENTER("SetRsaExternal"); - - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("rsa key NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 1) { - RsaKey* key = (RsaKey*)rsa->internal; - - /* Copy modulus. */ - ret = wolfssl_bn_set_value(&rsa->n, &key->n); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa n error"); - } - if (ret == 1) { - /* Copy public exponent. */ - ret = wolfssl_bn_set_value(&rsa->e, &key->e); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa e error"); - } - } - - if (key->type == RSA_PRIVATE) { - #ifndef WOLFSSL_RSA_PUBLIC_ONLY - if (ret == 1) { - /* Copy private exponent. */ - ret = wolfssl_bn_set_value(&rsa->d, &key->d); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa d error"); - } - } - if (ret == 1) { - /* Copy first prime. */ - ret = wolfssl_bn_set_value(&rsa->p, &key->p); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa p error"); - } - } - if (ret == 1) { - /* Copy second prime. */ - ret = wolfssl_bn_set_value(&rsa->q, &key->q); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa q error"); - } - } - #if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || \ - !defined(RSA_LOW_MEM) - if (ret == 1) { - /* Copy d mod p-1. */ - ret = wolfssl_bn_set_value(&rsa->dmp1, &key->dP); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa dP error"); - } - } - if (ret == 1) { - /* Copy d mod q-1. */ - ret = wolfssl_bn_set_value(&rsa->dmq1, &key->dQ); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa dq error"); - } - } - if (ret == 1) { - /* Copy 1/q mod p. */ - ret = wolfssl_bn_set_value(&rsa->iqmp, &key->u); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa u error"); - } - } - #endif - #else - WOLFSSL_ERROR_MSG("rsa private key not compiled in "); - ret = 0; - #endif /* !WOLFSSL_RSA_PUBLIC_ONLY */ - } - } - if (ret == 1) { - /* External values set. */ - rsa->exSet = 1; - } - else { - /* Return 0 on failure. */ - ret = 0; - } - - return ret; -} -#endif /* (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */ - -#ifdef OPENSSL_EXTRA - -/* Set wolfCrypt RSA key data (internal) from RSA key (external). - * - * @param [in, out] rsa RSA key. - * @return 1 on success. - * @return 0 on failure. - */ -int SetRsaInternal(WOLFSSL_RSA* rsa) -{ - int ret = 1; - - WOLFSSL_ENTER("SetRsaInternal"); - - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("rsa key NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 1) { - RsaKey* key = (RsaKey*)rsa->internal; - - /* Copy down modulus if available. */ - if ((rsa->n != NULL) && (wolfssl_bn_get_value(rsa->n, &key->n) != 1)) { - WOLFSSL_ERROR_MSG("rsa n key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Copy down public exponent if available. */ - if ((ret == 1) && (rsa->e != NULL) && - (wolfssl_bn_get_value(rsa->e, &key->e) != 1)) { - WOLFSSL_ERROR_MSG("rsa e key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Enough numbers for public key */ - key->type = RSA_PUBLIC; - -#ifndef WOLFSSL_RSA_PUBLIC_ONLY - /* Copy down private exponent if available. */ - if ((ret == 1) && (rsa->d != NULL)) { - if (wolfssl_bn_get_value(rsa->d, &key->d) != 1) { - WOLFSSL_ERROR_MSG("rsa d key error"); - ret = WOLFSSL_FATAL_ERROR; - } - else { - /* Enough numbers for private key */ - key->type = RSA_PRIVATE; - } - } - - /* Copy down first prime if available. */ - if ((ret == 1) && (rsa->p != NULL) && - (wolfssl_bn_get_value(rsa->p, &key->p) != 1)) { - WOLFSSL_ERROR_MSG("rsa p key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Copy down second prime if available. */ - if ((ret == 1) && (rsa->q != NULL) && - (wolfssl_bn_get_value(rsa->q, &key->q) != 1)) { - WOLFSSL_ERROR_MSG("rsa q key error"); - ret = WOLFSSL_FATAL_ERROR; - } - -#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM) - /* Copy down d mod p-1 if available. */ - if ((ret == 1) && (rsa->dmp1 != NULL) && - (wolfssl_bn_get_value(rsa->dmp1, &key->dP) != 1)) { - WOLFSSL_ERROR_MSG("rsa dP key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Copy down d mod q-1 if available. */ - if ((ret == 1) && (rsa->dmq1 != NULL) && - (wolfssl_bn_get_value(rsa->dmq1, &key->dQ) != 1)) { - WOLFSSL_ERROR_MSG("rsa dQ key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Copy down 1/q mod p if available. */ - if ((ret == 1) && (rsa->iqmp != NULL) && - (wolfssl_bn_get_value(rsa->iqmp, &key->u) != 1)) { - WOLFSSL_ERROR_MSG("rsa u key error"); - ret = WOLFSSL_FATAL_ERROR; - } -#endif -#endif - - if (ret == 1) { - /* All available numbers have been set down. */ - rsa->inSet = 1; - } - } - - return ret; -} - -/* Set the RSA method into object. - * - * @param [in, out] rsa RSA key. - * @param [in] meth RSA method. - * @return 1 always. - */ -int wolfSSL_RSA_set_method(WOLFSSL_RSA *rsa, WOLFSSL_RSA_METHOD *meth) -{ - if (rsa != NULL) { - /* Store the method into object. */ - rsa->meth = meth; - /* Copy over flags. */ - rsa->flags = meth->flags; - } - /* OpenSSL always assumes it will work. */ - return 1; -} - -/* Get the RSA method from the RSA object. - * - * @param [in] rsa RSA key. - * @return RSA method on success. - * @return NULL when RSA is NULL or no method set. - */ -const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_method(const WOLFSSL_RSA *rsa) -{ - return (rsa != NULL) ? rsa->meth : NULL; -} - -/* Get the size in bytes of the RSA key. - * - * Return compliant with OpenSSL - * - * @param [in] rsa RSA key. - * @return RSA modulus size in bytes. - * @return 0 on error. - */ -int wolfSSL_RSA_size(const WOLFSSL_RSA* rsa) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_size"); - - if (rsa != NULL) { - /* Make sure we have set the RSA values into wolfCrypt RSA key. */ - if (rsa->inSet || (SetRsaInternal((WOLFSSL_RSA*)rsa) == 1)) { - /* Get key size in bytes using wolfCrypt RSA key. */ - ret = wc_RsaEncryptSize((RsaKey*)rsa->internal); - } - } - - return ret; -} - -/* Get the size in bits of the RSA key. - * - * Uses external modulus field. - * - * @param [in] rsa RSA key. - * @return RSA modulus size in bits. - * @return 0 on error. - */ -int wolfSSL_RSA_bits(const WOLFSSL_RSA* rsa) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_bits"); - - if (rsa != NULL) { - /* Get number of bits in external modulus. */ - ret = wolfSSL_BN_num_bits(rsa->n); - } - - return ret; -} - -/* Get the BN objects that are the Chinese-Remainder Theorem (CRT) parameters. - * - * Only for those that are not NULL parameters. - * - * @param [in] rsa RSA key. - * @param [out] dmp1 BN that is d mod (p - 1). May be NULL. - * @param [out] dmq1 BN that is d mod (q - 1). May be NULL. - * @param [out] iqmp BN that is 1/q mod p. May be NULL. - */ -void wolfSSL_RSA_get0_crt_params(const WOLFSSL_RSA *rsa, - const WOLFSSL_BIGNUM **dmp1, const WOLFSSL_BIGNUM **dmq1, - const WOLFSSL_BIGNUM **iqmp) -{ - WOLFSSL_ENTER("wolfSSL_RSA_get0_crt_params"); - - /* For any parameters not NULL, return the BN from the key or NULL. */ - if (dmp1 != NULL) { - *dmp1 = (rsa != NULL) ? rsa->dmp1 : NULL; - } - if (dmq1 != NULL) { - *dmq1 = (rsa != NULL) ? rsa->dmq1 : NULL; - } - if (iqmp != NULL) { - *iqmp = (rsa != NULL) ? rsa->iqmp : NULL; - } -} - -/* Set the BN objects that are the Chinese-Remainder Theorem (CRT) parameters - * into RSA key. - * - * If CRT parameter is NULL then there must be one in the RSA key already. - * - * @param [in, out] rsa RSA key. - * @param [in] dmp1 BN that is d mod (p - 1). May be NULL. - * @param [in] dmq1 BN that is d mod (q - 1). May be NULL. - * @param [in] iqmp BN that is 1/q mod p. May be NULL. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_set0_crt_params(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *dmp1, - WOLFSSL_BIGNUM *dmq1, WOLFSSL_BIGNUM *iqmp) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_RSA_set0_crt_params"); - - /* If a param is NULL in rsa then it must be non-NULL in the - * corresponding user input. */ - if ((rsa == NULL) || ((rsa->dmp1 == NULL) && (dmp1 == NULL)) || - ((rsa->dmq1 == NULL) && (dmq1 == NULL)) || - ((rsa->iqmp == NULL) && (iqmp == NULL))) { - WOLFSSL_ERROR_MSG("Bad parameters"); - ret = 0; - } - if (ret == 1) { - /* Replace the BNs. */ - if (dmp1 != NULL) { - wolfSSL_BN_clear_free(rsa->dmp1); - rsa->dmp1 = dmp1; - } - if (dmq1 != NULL) { - wolfSSL_BN_clear_free(rsa->dmq1); - rsa->dmq1 = dmq1; - } - if (iqmp != NULL) { - wolfSSL_BN_clear_free(rsa->iqmp); - rsa->iqmp = iqmp; - } - - /* Set the values into the wolfCrypt RSA key. */ - if (SetRsaInternal(rsa) != 1) { - if (dmp1 != NULL) { - rsa->dmp1 = NULL; - } - if (dmq1 != NULL) { - rsa->dmq1 = NULL; - } - if (iqmp != NULL) { - rsa->iqmp = NULL; - } - ret = 0; - } - } - - return ret; -} - -/* Get the BN objects that are the factors of the RSA key (two primes p and q). - * - * @param [in] rsa RSA key. - * @param [out] p BN that is first prime. May be NULL. - * @param [out] q BN that is second prime. May be NULL. - */ -void wolfSSL_RSA_get0_factors(const WOLFSSL_RSA *rsa, const WOLFSSL_BIGNUM **p, - const WOLFSSL_BIGNUM **q) -{ - WOLFSSL_ENTER("wolfSSL_RSA_get0_factors"); - - /* For any primes not NULL, return the BN from the key or NULL. */ - if (p != NULL) { - *p = (rsa != NULL) ? rsa->p : NULL; - } - if (q != NULL) { - *q = (rsa != NULL) ? rsa->q : NULL; - } -} - -/* Set the BN objects that are the factors of the RSA key (two primes p and q). - * - * If factor parameter is NULL then there must be one in the RSA key already. - * - * @param [in, out] rsa RSA key. - * @param [in] p BN that is first prime. May be NULL. - * @param [in] q BN that is second prime. May be NULL. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_set0_factors(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *p, - WOLFSSL_BIGNUM *q) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_RSA_set0_factors"); - - /* If a param is null in r then it must be non-null in the - * corresponding user input. */ - if (rsa == NULL || ((rsa->p == NULL) && (p == NULL)) || - ((rsa->q == NULL) && (q == NULL))) { - WOLFSSL_ERROR_MSG("Bad parameters"); - ret = 0; - } - if (ret == 1) { - /* Replace the BNs. */ - if (p != NULL) { - wolfSSL_BN_clear_free(rsa->p); - rsa->p = p; - } - if (q != NULL) { - wolfSSL_BN_clear_free(rsa->q); - rsa->q = q; - } - - /* Set the values into the wolfCrypt RSA key. */ - if (SetRsaInternal(rsa) != 1) { - if (p != NULL) { - rsa->p = NULL; - } - if (q != NULL) { - rsa->q = NULL; - } - ret = 0; - } - } - - return ret; -} - -/* Get the BN objects for the basic key numbers of the RSA key (modulus, public - * exponent, private exponent). - * - * @param [in] rsa RSA key. - * @param [out] n BN that is the modulus. May be NULL. - * @param [out] e BN that is the public exponent. May be NULL. - * @param [out] d BN that is the private exponent. May be NULL. - */ -void wolfSSL_RSA_get0_key(const WOLFSSL_RSA *rsa, const WOLFSSL_BIGNUM **n, - const WOLFSSL_BIGNUM **e, const WOLFSSL_BIGNUM **d) -{ - WOLFSSL_ENTER("wolfSSL_RSA_get0_key"); - - /* For any parameters not NULL, return the BN from the key or NULL. */ - if (n != NULL) { - *n = (rsa != NULL) ? rsa->n : NULL; - } - if (e != NULL) { - *e = (rsa != NULL) ? rsa->e : NULL; - } - if (d != NULL) { - *d = (rsa != NULL) ? rsa->d : NULL; - } -} - -/* Set the BN objects for the basic key numbers into the RSA key (modulus, - * public exponent, private exponent). - * - * If BN parameter is NULL then there must be one in the RSA key already. - * - * @param [in,out] rsa RSA key. - * @param [in] n BN that is the modulus. May be NULL. - * @param [in] e BN that is the public exponent. May be NULL. - * @param [in] d BN that is the private exponent. May be NULL. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_set0_key(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *n, WOLFSSL_BIGNUM *e, - WOLFSSL_BIGNUM *d) -{ - int ret = 1; - - /* If the fields n and e in r are NULL, the corresponding input - * parameters MUST be non-NULL for n and e. d may be - * left NULL (in case only the public key is used). - */ - if ((rsa == NULL) || ((rsa->n == NULL) && (n == NULL)) || - ((rsa->e == NULL) && (e == NULL))) { - ret = 0; - } - if (ret == 1) { - /* Replace the BNs. */ - if (n != NULL) { - wolfSSL_BN_free(rsa->n); - rsa->n = n; - } - if (e != NULL) { - wolfSSL_BN_free(rsa->e); - rsa->e = e; - } - if (d != NULL) { - /* Private key is sensitive data. */ - wolfSSL_BN_clear_free(rsa->d); - rsa->d = d; - } - - /* Set the values into the wolfCrypt RSA key. */ - if (SetRsaInternal(rsa) != 1) { - if (n != NULL) { - rsa->n = NULL; - } - if (e != NULL) { - rsa->e = NULL; - } - if (d != NULL) { - rsa->d = NULL; - } - ret = 0; - } - } - - return ret; -} - -/* Get the flags of the RSA key. - * - * @param [in] rsa RSA key. - * @return Flags set in RSA key on success. - * @return 0 when RSA key is NULL. - */ -int wolfSSL_RSA_flags(const WOLFSSL_RSA *rsa) -{ - int ret = 0; - - /* Get flags from the RSA key if available. */ - if (rsa != NULL) { - ret = rsa->flags; - } - - return ret; -} - -/* Set the flags into the RSA key. - * - * @param [in, out] rsa RSA key. - * @param [in] flags Flags to set. - */ -void wolfSSL_RSA_set_flags(WOLFSSL_RSA *rsa, int flags) -{ - /* Add the flags into RSA key if available. */ - if (rsa != NULL) { - rsa->flags |= flags; - } -} - -/* Clear the flags in the RSA key. - * - * @param [in, out] rsa RSA key. - * @param [in] flags Flags to clear. - */ -void wolfSSL_RSA_clear_flags(WOLFSSL_RSA *rsa, int flags) -{ - /* Clear the flags passed in that are on the RSA key if available. */ - if (rsa != NULL) { - rsa->flags &= ~flags; - } -} - -/* Test the flags in the RSA key. - * - * @param [in] rsa RSA key. - * @return Matching flags of RSA key on success. - * @return 0 when RSA key is NULL. - */ -int wolfSSL_RSA_test_flags(const WOLFSSL_RSA *rsa, int flags) -{ - /* Return the flags passed in that are set on the RSA key if available. */ - return (rsa != NULL) ? (rsa->flags & flags) : 0; -} - -/* Get the extra data, by index, associated with the RSA key. - * - * @param [in] rsa RSA key. - * @param [in] idx Index of extra data. - * @return Extra data (anonymous type) on success. - * @return NULL on failure. - */ -void* wolfSSL_RSA_get_ex_data(const WOLFSSL_RSA *rsa, int idx) -{ - WOLFSSL_ENTER("wolfSSL_RSA_get_ex_data"); - -#ifdef HAVE_EX_DATA - return (rsa == NULL) ? NULL : - wolfSSL_CRYPTO_get_ex_data(&rsa->ex_data, idx); -#else - (void)rsa; - (void)idx; - - return NULL; -#endif -} - -/* Set extra data against the RSA key at an index. - * - * @param [in, out] rsa RSA key. - * @param [in] idx Index set set extra data at. - * @param [in] data Extra data of anonymous type. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_set_ex_data(WOLFSSL_RSA *rsa, int idx, void *data) -{ - WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data"); - -#ifdef HAVE_EX_DATA - return (rsa == NULL) ? 0 : - wolfSSL_CRYPTO_set_ex_data(&rsa->ex_data, idx, data); -#else - (void)rsa; - (void)idx; - (void)data; - - return 0; -#endif -} - -#ifdef HAVE_EX_DATA_CLEANUP_HOOKS -/* Set the extra data and cleanup callback against the RSA key at an index. - * - * Not OpenSSL API. - * - * @param [in, out] rsa RSA key. - * @param [in] idx Index set set extra data at. - * @param [in] data Extra data of anonymous type. - * @param [in] freeCb Callback function to free extra data. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_set_ex_data_with_cleanup(WOLFSSL_RSA *rsa, int idx, void *data, - wolfSSL_ex_data_cleanup_routine_t freeCb) -{ - WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data_with_cleanup"); - - return (rsa == NULL) ? 0 : - wolfSSL_CRYPTO_set_ex_data_with_cleanup(&rsa->ex_data, idx, data, - freeCb); -} -#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ - -/* - * RSA check key APIs - */ - -#ifdef WOLFSSL_RSA_KEY_CHECK -/* Check that the RSA key is valid using wolfCrypt. - * - * @param [in] rsa RSA key. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_check_key(const WOLFSSL_RSA* rsa) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_RSA_check_key"); - - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->internal == NULL)) { - ret = 0; - } - - /* Constant RSA - assume internal data has been set. */ - - /* Check wolfCrypt RSA key. */ - if ((ret == 1) && (wc_CheckRsaKey((RsaKey*)rsa->internal) != 0)) { - ret = 0; - } - - WOLFSSL_LEAVE("wolfSSL_RSA_check_key", ret); - - return ret; -} -#endif /* WOLFSSL_RSA_KEY_CHECK */ - -/* - * RSA generate APIs - */ - -/* Get a random number generator associated with the RSA key. - * - * If not able, then get the global if possible. - * *tmpRng must not be an initialized RNG. - * *tmpRng is allocated when WOLFSSL_SMALL_STACK is defined and an RNG isn't - * associated with the wolfCrypt RSA key. - * - * @param [in] rsa RSA key. - * @param [out] tmpRng Temporary random number generator. - * @param [out] initTmpRng Temporary random number generator was initialized. - * - * @return A wolfCrypt RNG to use on success. - * @return NULL on error. - */ -WC_RNG* WOLFSSL_RSA_GetRNG(WOLFSSL_RSA* rsa, WC_RNG** tmpRng, int* initTmpRng) -{ - WC_RNG* rng = NULL; - int err = 0; - - /* Check validity of parameters. */ - if ((rsa == NULL) || (initTmpRng == NULL)) { - err = 1; - } - if (!err) { - /* Haven't initialized any RNG passed through tmpRng. */ - *initTmpRng = 0; - - #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) - /* Use wolfCrypt RSA key's RNG if available/set. */ - rng = ((RsaKey*)rsa->internal)->rng; - #endif - } - if ((!err) && (rng == NULL) && (tmpRng != NULL)) { - /* Make an RNG with tmpRng or get global. */ - rng = wolfssl_make_rng(*tmpRng, initTmpRng); - if ((rng != NULL) && *initTmpRng) { - *tmpRng = rng; - } - } - - return rng; -} - -/* Use the wolfCrypt RSA APIs to generate a new RSA key. - * - * @param [in, out] rsa RSA key. - * @param [in] bits Number of bits that the modulus must have. - * @param [in] e A BN object holding the public exponent to use. - * @param [in] cb Status callback. Unused. - * @return 0 on success. - * @return wolfSSL native error code on error. - */ -static int wolfssl_rsa_generate_key_native(WOLFSSL_RSA* rsa, int bits, - WOLFSSL_BIGNUM* e, void* cb) -{ -#ifdef WOLFSSL_KEY_GEN - int ret = 0; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG* tmpRng = NULL; -#else - WC_RNG _tmpRng[1]; - WC_RNG* tmpRng = _tmpRng; -#endif - int initTmpRng = 0; - WC_RNG* rng = NULL; - long en = 0; -#endif - - (void)cb; - - WOLFSSL_ENTER("wolfssl_rsa_generate_key_native"); - -#ifdef WOLFSSL_KEY_GEN - /* Get RNG in wolfCrypt RSA key or initialize a new one (or global). */ - rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); - if (rng == NULL) { - /* Something went wrong so return memory error. */ - ret = MEMORY_E; - } - if ((ret == 0) && ((en = (long)wolfSSL_BN_get_word(e)) <= 0)) { - ret = BAD_FUNC_ARG; - } - if (ret == 0) { - /* Generate an RSA key. */ - ret = wc_MakeRsaKey((RsaKey*)rsa->internal, bits, en, rng); - if (ret != MP_OKAY) { - WOLFSSL_ERROR_MSG("wc_MakeRsaKey failed"); - } - } - if (ret == 0) { - /* Get the values from wolfCrypt RSA key into external RSA key. */ - ret = SetRsaExternal(rsa); - if (ret == 1) { - /* Internal matches external. */ - rsa->inSet = 1; - /* Return success. */ - ret = 0; - } - else { - /* Something went wrong so return memory error. */ - ret = MEMORY_E; - } - } - - /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ - if (initTmpRng) { - wc_FreeRng(tmpRng); - } - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - - return ret; -#else - WOLFSSL_ERROR_MSG("No Key Gen built in"); - - (void)rsa; - (void)e; - (void)bits; - - return NOT_COMPILED_IN; -#endif -} - -/* Generate an RSA key that has the specified modulus size and public exponent. - * - * Note: Because of wc_MakeRsaKey an RSA key size generated can be rounded - * down to nearest multiple of 8. For example generating a key of size - * 2999 bits will make a key of size 374 bytes instead of 375 bytes. - * - * @param [in] bits Number of bits that the modulus must have i.e. 2048. - * @param [in] e Public exponent to use i.e. 65537. - * @param [in] cb Status callback. Unused. - * @param [in] data Data to pass to status callback. Unused. - * @return A new RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_RSA_generate_key(int bits, unsigned long e, - void(*cb)(int, int, void*), void* data) -{ - WOLFSSL_RSA* rsa = NULL; - WOLFSSL_BIGNUM* bn = NULL; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_generate_key"); - - (void)cb; - (void)data; - - /* Validate bits. */ - if (bits < 0) { - WOLFSSL_ERROR_MSG("Bad argument: bits was less than 0"); - err = 1; - } - /* Create a new BN to hold public exponent - for when wolfCrypt supports - * longer values. */ - if ((!err) && ((bn = wolfSSL_BN_new()) == NULL)) { - WOLFSSL_ERROR_MSG("Error creating big number"); - err = 1; - } - /* Set public exponent. */ - if ((!err) && (wolfSSL_BN_set_word(bn, e) != 1)) { - WOLFSSL_ERROR_MSG("Error using e value"); - err = 1; - } - - /* Create an RSA key object to hold generated key. */ - if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { - WOLFSSL_ERROR_MSG("memory error"); - err = 1; - } - while (!err) { - int ret; - - /* Use wolfCrypt to generate RSA key. */ - ret = wolfssl_rsa_generate_key_native(rsa, bits, bn, NULL); - #ifdef HAVE_FIPS - /* Keep trying if failed to find a prime. */ - if (ret == WC_NO_ERR_TRACE(PRIME_GEN_E)) { - continue; - } - #endif - if (ret != WOLFSSL_ERROR_NONE) { - /* Unrecoverable error in generation. */ - err = 1; - } - /* Done generating - unrecoverable error or success. */ - break; - } - if (err) { - /* Dispose of RSA key object if generation didn't work. */ - wolfSSL_RSA_free(rsa); - /* Returning NULL on error. */ - rsa = NULL; - } - /* Dispose of the temporary BN used for the public exponent. */ - wolfSSL_BN_free(bn); - - return rsa; -} - -/* Generate an RSA key that has the specified modulus size and public exponent. - * - * Note: Because of wc_MakeRsaKey an RSA key size generated can be rounded - * down to nearest multiple of 8. For example generating a key of size - * 2999 bits will make a key of size 374 bytes instead of 375 bytes. - * - * @param [in] bits Number of bits that the modulus must have i.e. 2048. - * @param [in] e Public exponent to use, i.e. 65537, as a BN. - * @param [in] cb Status callback. Unused. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_generate_key_ex(WOLFSSL_RSA* rsa, int bits, WOLFSSL_BIGNUM* e, - void* cb) -{ - int ret = 1; - - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("bad arguments"); - ret = 0; - } - else { - for (;;) { - /* Use wolfCrypt to generate RSA key. */ - int gen_ret = wolfssl_rsa_generate_key_native(rsa, bits, e, cb); - #ifdef HAVE_FIPS - /* Keep trying again if public key value didn't work. */ - if (gen_ret == WC_NO_ERR_TRACE(PRIME_GEN_E)) { - continue; - } - #endif - if (gen_ret != WOLFSSL_ERROR_NONE) { - /* Unrecoverable error in generation. */ - ret = 0; - } - /* Done generating - unrecoverable error or success. */ - break; - } - } - - return ret; -} - -#endif /* OPENSSL_EXTRA */ - -/* - * RSA padding APIs - */ - -#ifdef WC_RSA_PSS - -#if defined(OPENSSL_EXTRA) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) -static int rsa_pss_calc_salt(int saltLen, int hashLen, int emLen) -{ - /* Calculate the salt length to use for special cases. */ - switch (saltLen) { - /* Negative saltLen values are treated differently. */ - case WC_RSA_PSS_SALTLEN_DIGEST: - saltLen = hashLen; - break; - case WC_RSA_PSS_SALTLEN_MAX_SIGN: - case WC_RSA_PSS_SALTLEN_MAX: - #ifdef WOLFSSL_PSS_LONG_SALT - saltLen = emLen - hashLen - 2; - #else - saltLen = hashLen; - (void)emLen; - #endif - break; - default: - break; - } - if (saltLen < 0) { - /* log invalid salt, let wolfCrypt handle error */ - WOLFSSL_ERROR_MSG("invalid saltLen"); - saltLen = -3; /* for wolfCrypt to produce error must be < -2 */ - } - return saltLen; -} -#endif /* OPENSSL_EXTRA && !HAVE_SELFTEST */ - -#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ - defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX)) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - -/* Add PKCS#1 PSS padding to hash. - * - * - * +-----------+ - * | M | - * +-----------+ - * | - * V - * Hash - * | - * V - * +--------+----------+----------+ - * M' = |Padding1| mHash | salt | - * +--------+----------+----------+ - * | - * +--------+----------+ V - * DB = |Padding2|maskedseed| Hash - * +--------+----------+ | - * | | - * V | +--+ - * xor <--- MGF <---| |bc| - * | | +--+ - * | | | - * V V V - * +-------------------+----------+--+ - * EM = | maskedDB |maskedseed|bc| - * +-------------------+----------+--+ - * Diagram taken from https://tools.ietf.org/html/rfc3447#section-9.1 - * - * @param [in] rsa RSA key. - * @param [out] em Encoded message. - * @param [in[ mHash Message hash. - * @param [in] hashAlg Hash algorithm. - * @param [in] mgf1Hash MGF algorithm. - * @param [in] saltLen Length of salt to generate. - * @return 1 on success. - * @return 0 on failure. - */ - -int wolfSSL_RSA_padding_add_PKCS1_PSS_mgf1(WOLFSSL_RSA *rsa, unsigned char *em, - const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, - const WOLFSSL_EVP_MD *mgf1Hash, int saltLen) -{ - int ret = 1; - enum wc_HashType hashType = WC_HASH_TYPE_NONE; - int hashLen = 0; - int emLen = 0; - int mgf = 0; - int initTmpRng = 0; - WC_RNG *rng = NULL; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG* tmpRng = NULL; -#else - WC_RNG _tmpRng[1]; - WC_RNG* tmpRng = _tmpRng; -#endif - - WOLFSSL_ENTER("wolfSSL_RSA_padding_add_PKCS1_PSS"); - - /* Validate parameters. */ - if ((rsa == NULL) || (em == NULL) || (mHash == NULL) || (hashAlg == NULL)) { - ret = 0; - } - - if (mgf1Hash == NULL) - mgf1Hash = hashAlg; - - if (ret == 1) { - /* Get/create an RNG. */ - rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); - if (rng == NULL) { - WOLFSSL_ERROR_MSG("WOLFSSL_RSA_GetRNG error"); - ret = 0; - } - } - - /* TODO: use wolfCrypt RSA key to get emLen and bits? */ - /* Set the external data from the wolfCrypt RSA key if not done. */ - if ((ret == 1) && (!rsa->exSet)) { - ret = SetRsaExternal(rsa); - } - - if (ret == 1) { - /* Get the wolfCrypt hash algorithm type. */ - hashType = EvpMd2MacType(hashAlg); - if (hashType > WC_HASH_TYPE_MAX) { - WOLFSSL_ERROR_MSG("EvpMd2MacType error"); - ret = 0; - } - } - if (ret == 1) { - /* Get the wolfCrypt MGF algorithm from hash algorithm. */ - mgf = wc_hash2mgf(EvpMd2MacType(mgf1Hash)); - if (mgf == WC_MGF1NONE) { - WOLFSSL_ERROR_MSG("wc_hash2mgf error"); - ret = 0; - } - } - if (ret == 1) { - /* Get the length of the hash output. */ - hashLen = wolfSSL_EVP_MD_size(hashAlg); - if (hashLen < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_EVP_MD_size error"); - ret = 0; - } - } - - if (ret == 1) { - /* Get length of RSA key - encrypted message length. */ - emLen = wolfSSL_RSA_size(rsa); - if (emLen <= 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_size error"); - ret = 0; - } - } - - if (ret == 1) { - saltLen = rsa_pss_calc_salt(saltLen, hashLen, emLen); - } - - if (ret == 1) { - /* Generate RSA PKCS#1 PSS padding for hash using wolfCrypt. */ - if (wc_RsaPad_ex(mHash, (word32)hashLen, em, (word32)emLen, - RSA_BLOCK_TYPE_1, rng, WC_RSA_PSS_PAD, hashType, mgf, NULL, 0, - saltLen, wolfSSL_BN_num_bits(rsa->n), NULL) != MP_OKAY) { - WOLFSSL_ERROR_MSG("wc_RsaPad_ex error"); - ret = 0; - } - } - - /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ - if (initTmpRng) { - wc_FreeRng(tmpRng); - } - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - - return ret; -} - -int wolfSSL_RSA_padding_add_PKCS1_PSS(WOLFSSL_RSA *rsa, unsigned char *em, - const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, int saltLen) -{ - return wolfSSL_RSA_padding_add_PKCS1_PSS_mgf1(rsa, em, mHash, hashAlg, NULL, - saltLen); -} - -/* Checks that the hash is valid for the RSA PKCS#1 PSS encoded message. - * - * Refer to wolfSSL_RSA_padding_add_PKCS1_PSS for a diagram. - * - * @param [in] rsa RSA key. - * @param [in[ mHash Message hash. - * @param [in] hashAlg Hash algorithm. - * @param [in] mgf1Hash MGF algorithm. - * @param [in] em Encoded message. - * @param [in] saltLen Length of salt to generate. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_verify_PKCS1_PSS_mgf1(WOLFSSL_RSA *rsa, - const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, - const WOLFSSL_EVP_MD *mgf1Hash, const unsigned char *em, int saltLen) -{ - int ret = 1; - int hashLen = 0; - int mgf = 0; - int emLen = 0; - int mPrimeLen = 0; - enum wc_HashType hashType = WC_HASH_TYPE_NONE; - byte *mPrime = NULL; - byte *buf = NULL; - - WOLFSSL_ENTER("wolfSSL_RSA_verify_PKCS1_PSS"); - - /* Validate parameters. */ - if ((rsa == NULL) || (mHash == NULL) || (hashAlg == NULL) || (em == NULL)) { - ret = 0; - } - - if (mgf1Hash == NULL) - mgf1Hash = hashAlg; - - /* TODO: use wolfCrypt RSA key to get emLen and bits? */ - /* Set the external data from the wolfCrypt RSA key if not done. */ - if ((ret == 1) && (!rsa->exSet)) { - ret = SetRsaExternal(rsa); - } - - if (ret == 1) { - /* Get hash length for hash algorithm. */ - hashLen = wolfSSL_EVP_MD_size(hashAlg); - if (hashLen < 0) { - ret = 0; - } - } - - if (ret == 1) { - /* Get length of RSA key - encrypted message length. */ - emLen = wolfSSL_RSA_size(rsa); - if (emLen <= 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_size error"); - ret = 0; - } - } - - if (ret == 1) { - saltLen = rsa_pss_calc_salt(saltLen, hashLen, emLen); - } - - if (ret == 1) { - /* Get the wolfCrypt hash algorithm type. */ - hashType = EvpMd2MacType(hashAlg); - if (hashType > WC_HASH_TYPE_MAX) { - WOLFSSL_ERROR_MSG("EvpMd2MacType error"); - ret = 0; - } - } - - if (ret == 1) { - /* Get the wolfCrypt MGF algorithm from hash algorithm. */ - if ((mgf = wc_hash2mgf(EvpMd2MacType(mgf1Hash))) == WC_MGF1NONE) { - WOLFSSL_ERROR_MSG("wc_hash2mgf error"); - ret = 0; - } - } - - if (ret == 1) { - /* Allocate buffer to unpad inline with. */ - buf = (byte*)XMALLOC((size_t)emLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - WOLFSSL_ERROR_MSG("malloc error"); - ret = 0; - } - } - - if (ret == 1) { - /* Copy encrypted message to temp for inline unpadding. */ - XMEMCPY(buf, em, (size_t)emLen); - - /* Remove and verify the PSS padding. */ - mPrimeLen = wc_RsaUnPad_ex(buf, (word32)emLen, &mPrime, - RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD, hashType, mgf, NULL, 0, saltLen, - wolfSSL_BN_num_bits(rsa->n), NULL); - if (mPrimeLen < 0) { - WOLFSSL_ERROR_MSG("wc_RsaPad_ex error"); - ret = 0; - } - } - - if (ret == 1) { - /* Verify the hash is correct. */ - if (wc_RsaPSS_CheckPadding_ex(mHash, (word32)hashLen, mPrime, - (word32)mPrimeLen, hashType, saltLen, - wolfSSL_BN_num_bits(rsa->n)) != MP_OKAY) { - WOLFSSL_ERROR_MSG("wc_RsaPSS_CheckPadding_ex error"); - ret = 0; - } - } - - /* Dispose of any allocated buffer. */ - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return ret; -} - -int wolfSSL_RSA_verify_PKCS1_PSS(WOLFSSL_RSA *rsa, const unsigned char *mHash, - const WOLFSSL_EVP_MD *hashAlg, - const unsigned char *em, int saltLen) -{ - return wolfSSL_RSA_verify_PKCS1_PSS_mgf1(rsa, mHash, hashAlg, NULL, em, - saltLen); -} -#endif /* (!HAVE_FIPS || FIPS_VERSION_GT(2,0)) && \ - (OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_NGINX) */ -#endif /* WC_RSA_PSS */ - -/* - * RSA sign/verify APIs - */ - -#if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) - #ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER - #define DEF_PSS_SALT_LEN RSA_PSS_SALT_LEN_DEFAULT - #else - #define DEF_PSS_SALT_LEN RSA_PSS_SALT_LEN_DISCOVER - #endif -#else - #define DEF_PSS_SALT_LEN 0 /* not used */ -#endif - -#if defined(OPENSSL_EXTRA) - -/* Encode the message hash. - * - * Used by signing and verification. - * - * @param [in] hashAlg Hash algorithm OID. - * @param [in] hash Hash of message to encode for signing. - * @param [in] hLen Length of hash of message. - * @param [out] enc Encoded message hash. - * @param [out] encLen Length of encoded message hash. - * @param [in] padding Which padding scheme is being used. - * @return 1 on success. - * @return 0 on failure. - */ -static int wolfssl_rsa_sig_encode(int hashAlg, const unsigned char* hash, - unsigned int hLen, unsigned char* enc, unsigned int* encLen, int padding) -{ - int ret = 1; - int hType = WC_HASH_TYPE_NONE; - - /* Validate parameters. */ - if ((hash == NULL) || (enc == NULL) || (encLen == NULL)) { - ret = 0; - } - - if ((ret == 1) && (hashAlg != WC_NID_undef) && - (padding == WC_RSA_PKCS1_PADDING)) { - /* Convert hash algorithm to hash type for PKCS#1.5 padding. */ - hType = (int)nid2oid(hashAlg, oidHashType); - if (hType == -1) { - ret = 0; - } - } - if ((ret == 1) && (padding == WC_RSA_PKCS1_PADDING)) { - /* PKCS#1.5 encoding. */ - word32 encSz = wc_EncodeSignature(enc, hash, hLen, hType); - if (encSz == 0) { - WOLFSSL_ERROR_MSG("Bad Encode Signature"); - ret = 0; - } - else { - *encLen = (unsigned int)encSz; - } - } - /* Other padding schemes require the hash as is. */ - if ((ret == 1) && (padding != WC_RSA_PKCS1_PADDING)) { - XMEMCPY(enc, hash, hLen); - *encLen = hLen; - } - - return ret; -} - -/* Sign the message hash using hash algorithm and RSA key. - * - * @param [in] hashAlg Hash algorithm OID. - * @param [in] hash Hash of message to encode for signing. - * @param [in] hLen Length of hash of message. - * @param [out] enc Encoded message hash. - * @param [out] encLen Length of encoded message hash. - * @param [in] rsa RSA key. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_sign(int hashAlg, const unsigned char* hash, unsigned int hLen, - unsigned char* sigRet, unsigned int* sigLen, WOLFSSL_RSA* rsa) -{ - if (sigLen != NULL) { - /* No size checking in this API */ - *sigLen = RSA_MAX_SIZE / CHAR_BIT; - } - /* flag is 1: output complete signature. */ - return wolfSSL_RSA_sign_generic_padding(hashAlg, hash, hLen, sigRet, - sigLen, rsa, 1, WC_RSA_PKCS1_PADDING); -} - -/* Sign the message hash using hash algorithm and RSA key. - * - * Not OpenSSL API. - * - * @param [in] hashAlg Hash algorithm NID. - * @param [in] hash Hash of message to encode for signing. - * @param [in] hLen Length of hash of message. - * @param [out] enc Encoded message hash. - * @param [out] encLen Length of encoded message hash. - * @param [in] rsa RSA key. - * @param [in] flag When 1: Output encrypted signature. - * When 0: Output encoded hash. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_sign_ex(int hashAlg, const unsigned char* hash, - unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, - WOLFSSL_RSA* rsa, int flag) -{ - int ret = 0; - - if ((flag == 0) || (flag == 1)) { - if (sigLen != NULL) { - /* No size checking in this API */ - *sigLen = RSA_MAX_SIZE / CHAR_BIT; - } - ret = wolfSSL_RSA_sign_generic_padding(hashAlg, hash, hLen, sigRet, - sigLen, rsa, flag, WC_RSA_PKCS1_PADDING); - } - - return ret; -} - -int wolfSSL_RSA_sign_generic_padding(int hashAlg, const unsigned char* hash, - unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, - WOLFSSL_RSA* rsa, int flag, int padding) -{ - return wolfSSL_RSA_sign_mgf(hashAlg, hash, hLen, sigRet, sigLen, rsa, flag, - padding, hashAlg, DEF_PSS_SALT_LEN); -} - -/** - * Sign a message hash with the chosen message digest, padding, and RSA key. - * - * Not OpenSSL API. - * - * @param [in] hashAlg Hash NID - * @param [in] hash Message hash to sign. - * @param [in] mLen Length of message hash to sign. - * @param [out] sigRet Output buffer. - * @param [in, out] sigLen On Input: length of sigRet buffer. - * On Output: length of data written to sigRet. - * @param [in] rsa RSA key used to sign the input. - * @param [in] flag 1: Output the signature. - * 0: Output the value that the unpadded signature - * should be compared to. - * @param [in] padding Padding to use. Only RSA_PKCS1_PSS_PADDING and - * WC_RSA_PKCS1_PADDING are currently supported for - * signing. - * @param [in] mgf1Hash MGF1 Hash NID - * @param [in] saltLen Length of RSA PSS salt - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash, - unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, - WOLFSSL_RSA* rsa, int flag, int padding, int mgf1Hash, int saltLen) -{ - int ret = 1; - word32 outLen = 0; - int signSz = 0; - WC_RNG* rng = NULL; - int initTmpRng = 0; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG* tmpRng = NULL; - byte* encodedSig = NULL; -#else - WC_RNG _tmpRng[1]; - WC_RNG* tmpRng = _tmpRng; - byte encodedSig[MAX_ENCODED_SIG_SZ]; -#endif - unsigned int encSz = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_sign_mgf"); - - if (flag == 0) { - /* Only encode message. */ - return wolfssl_rsa_sig_encode(hashAlg, hash, hLen, sigRet, sigLen, - padding); - } - - /* Validate parameters. */ - if ((hash == NULL) || (sigRet == NULL) || sigLen == NULL || rsa == NULL) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - - /* Set wolfCrypt RSA key data from external if not already done. */ - if ((ret == 1) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = 0; - } - - if (ret == 1) { - /* Get the maximum signature length. */ - outLen = (word32)wolfSSL_BN_num_bytes(rsa->n); - /* Check not an error return. */ - if (outLen == 0) { - WOLFSSL_ERROR_MSG("Bad RSA size"); - ret = 0; - } - /* Check signature buffer is big enough. */ - else if (outLen > *sigLen) { - WOLFSSL_ERROR_MSG("Output buffer too small"); - ret = 0; - } - } - -#ifdef WOLFSSL_SMALL_STACK - if (ret == 1) { - /* Allocate encoded signature buffer if doing PKCS#1 padding. */ - encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, - DYNAMIC_TYPE_SIGNATURE); - if (encodedSig == NULL) { - ret = 0; - } - } -#endif - - if (ret == 1) { - /* Get/create an RNG. */ - rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); - if (rng == NULL) { - WOLFSSL_ERROR_MSG("WOLFSSL_RSA_GetRNG error"); - ret = 0; - } - } - - /* Either encodes with PKCS#1.5 or copies hash into encodedSig. */ - if ((ret == 1) && (wolfssl_rsa_sig_encode(hashAlg, hash, hLen, encodedSig, - &encSz, padding) == 0)) { - WOLFSSL_ERROR_MSG("Bad Encode Signature"); - ret = 0; - } - - if (ret == 1) { - switch (padding) { - #if defined(WC_RSA_NO_PADDING) || defined(WC_RSA_DIRECT) - case WC_RSA_NO_PAD: - if ((signSz = wc_RsaDirect(encodedSig, encSz, sigRet, &outLen, - (RsaKey*)rsa->internal, RSA_PRIVATE_ENCRYPT, rng)) <= 0) { - WOLFSSL_ERROR_MSG("Bad RSA Sign no pad"); - ret = 0; - } - break; - #endif - #if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) - case WC_RSA_PKCS1_PSS_PADDING: - { - RsaKey* key = (RsaKey*)rsa->internal; - enum wc_HashType mgf1, hType; - hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); - if (mgf1Hash == WC_NID_undef) - mgf1Hash = hashAlg; - mgf1 = wc_OidGetHash((int)nid2oid(mgf1Hash, oidHashType)); - /* handle compat layer salt special cases */ - saltLen = rsa_pss_calc_salt(saltLen, wc_HashGetDigestSize(hType), - wolfSSL_RSA_size(rsa)); - - /* Create RSA PSS signature. */ - if ((signSz = wc_RsaPSS_Sign_ex(encodedSig, encSz, sigRet, outLen, - hType, wc_hash2mgf(mgf1), saltLen, key, rng)) <= 0) { - WOLFSSL_ERROR_MSG("Bad RSA PSS Sign"); - ret = 0; - } - break; - } - #endif - #ifndef WC_NO_RSA_OAEP - case WC_RSA_PKCS1_OAEP_PADDING: - /* Not a signature padding scheme. */ - WOLFSSL_ERROR_MSG("RSA_PKCS1_OAEP_PADDING not supported for " - "signing"); - ret = 0; - break; - #endif - case WC_RSA_PKCS1_PADDING: - { - /* Sign (private encrypt) PKCS#1 encoded signature. */ - if ((signSz = wc_RsaSSL_Sign(encodedSig, encSz, sigRet, outLen, - (RsaKey*)rsa->internal, rng)) <= 0) { - WOLFSSL_ERROR_MSG("Bad PKCS1 RSA Sign"); - ret = 0; - } - break; - } - default: - WOLFSSL_ERROR_MSG("Unsupported padding"); - (void)mgf1Hash; - (void)saltLen; - ret = 0; - break; - } - } - - if (ret == 1) { - /* Return the size of signature generated. */ - *sigLen = (unsigned int)signSz; - } - - /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ - if (initTmpRng) { - wc_FreeRng(tmpRng); - } - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - WC_FREE_VAR_EX(encodedSig, NULL, DYNAMIC_TYPE_SIGNATURE); - - WOLFSSL_LEAVE("wolfSSL_RSA_sign_mgf", ret); - return ret; -} - -/** - * Verify a message hash with the chosen message digest, padding, and RSA key. - * - * @param [in] hashAlg Hash NID - * @param [in] hash Message hash. - * @param [in] mLen Length of message hash. - * @param [in] sigRet Signature data. - * @param [in] sigLen Length of signature data. - * @param [in] rsa RSA key used to sign the input - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_verify(int hashAlg, const unsigned char* hash, - unsigned int hLen, const unsigned char* sig, unsigned int sigLen, - WOLFSSL_RSA* rsa) -{ - return wolfSSL_RSA_verify_ex(hashAlg, hash, hLen, sig, sigLen, rsa, - WC_RSA_PKCS1_PADDING); -} - -int wolfSSL_RSA_verify_ex(int hashAlg, const unsigned char* hash, - unsigned int hLen, const unsigned char* sig, unsigned int sigLen, - WOLFSSL_RSA* rsa, int padding) -{ - return wolfSSL_RSA_verify_mgf(hashAlg, hash, hLen, sig, sigLen, rsa, - padding, hashAlg, DEF_PSS_SALT_LEN); -} - -/** - * Verify a message hash with the chosen message digest, padding, and RSA key. - * - * Not OpenSSL API. - * - * @param [in] hashAlg Hash NID - * @param [in] hash Message hash. - * @param [in] mLen Length of message hash. - * @param [in] sigRet Signature data. - * @param [in] sigLen Length of signature data. - * @param [in] rsa RSA key used to sign the input - * @param [in] padding Padding to use. Only RSA_PKCS1_PSS_PADDING and - * WC_RSA_PKCS1_PADDING are currently supported for - * signing. - * @param [in] mgf1Hash MGF1 Hash NID - * @param [in] saltLen Length of RSA PSS salt - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_verify_mgf(int hashAlg, const unsigned char* hash, - unsigned int hLen, const unsigned char* sig, unsigned int sigLen, - WOLFSSL_RSA* rsa, int padding, int mgf1Hash, int saltLen) -{ - int ret = 1; -#ifdef WOLFSSL_SMALL_STACK - unsigned char* encodedSig = NULL; -#else - unsigned char encodedSig[MAX_ENCODED_SIG_SZ]; -#endif - unsigned char* sigDec = NULL; - unsigned int len = MAX_ENCODED_SIG_SZ; - int verLen = 0; -#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && !defined(HAVE_SELFTEST) - enum wc_HashType hType = WC_HASH_TYPE_NONE; -#endif - - WOLFSSL_ENTER("wolfSSL_RSA_verify_mgf"); - - /* Validate parameters. */ - if ((hash == NULL) || (sig == NULL) || (rsa == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - - if (ret == 1) { - /* Allocate memory for decrypted signature. */ - sigDec = (unsigned char *)XMALLOC(sigLen, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sigDec == NULL) { - WOLFSSL_ERROR_MSG("Memory allocation failure"); - ret = 0; - } - } - if (ret == 1 && padding == WC_RSA_PKCS1_PSS_PADDING) { - #if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) - RsaKey* key = (RsaKey*)rsa->internal; - enum wc_HashType mgf1; - hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); - if (mgf1Hash == WC_NID_undef) - mgf1Hash = hashAlg; - mgf1 = wc_OidGetHash((int)nid2oid(mgf1Hash, oidHashType)); - - /* handle compat layer salt special cases */ - saltLen = rsa_pss_calc_salt(saltLen, wc_HashGetDigestSize(hType), - wolfSSL_RSA_size(rsa)); - - verLen = wc_RsaPSS_Verify_ex((byte*)sig, sigLen, sigDec, sigLen, - hType, wc_hash2mgf(mgf1), saltLen, key); - if (verLen > 0) { - /* Check PSS padding is valid. */ - if (wc_RsaPSS_CheckPadding_ex(hash, hLen, sigDec, (word32)verLen, - hType, saltLen, mp_count_bits(&key->n)) != 0) { - WOLFSSL_ERROR_MSG("wc_RsaPSS_CheckPadding_ex error"); - ret = WOLFSSL_FAILURE; - } - else { - /* Success! Free resources and return early */ - XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_SUCCESS; - } - } - else { - WOLFSSL_ERROR_MSG("wc_RsaPSS_Verify_ex failed!"); - ret = WOLFSSL_FAILURE; - } - #else - (void)mgf1Hash; - (void)saltLen; - WOLFSSL_ERROR_MSG("RSA PSS not compiled in!"); - ret = WOLFSSL_FAILURE; - #endif - } - -#ifdef WOLFSSL_SMALL_STACK - if (ret == 1) { - /* Allocate memory for encoded signature. */ - encodedSig = (unsigned char *)XMALLOC(len, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (encodedSig == NULL) { - WOLFSSL_ERROR_MSG("Memory allocation failure"); - ret = 0; - } - } -#endif - if (ret == 1) { - /* Make encoded signature to compare with decrypted signature. */ - if (wolfssl_rsa_sig_encode(hashAlg, hash, hLen, encodedSig, &len, - padding) <= 0) { - WOLFSSL_ERROR_MSG("Message Digest Error"); - ret = 0; - } - } - if (ret == 1) { - /* Decrypt signature */ - #if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && \ - !defined(HAVE_SELFTEST) - hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); - if ((verLen = wc_RsaSSL_Verify_ex2(sig, sigLen, (unsigned char *)sigDec, - sigLen, (RsaKey*)rsa->internal, padding, hType)) <= 0) { - WOLFSSL_ERROR_MSG("RSA Decrypt error"); - ret = 0; - } - #else - verLen = wc_RsaSSL_Verify(sig, sigLen, (unsigned char *)sigDec, sigLen, - (RsaKey*)rsa->internal); - if (verLen < 0) { - ret = 0; - } - #endif - } - if (ret == 1) { - /* Compare decrypted signature to encoded signature. */ - if (((int)len != verLen) || - (XMEMCMP(encodedSig, sigDec, (size_t)verLen) != 0)) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_verify_ex failed"); - ret = 0; - } - } - - /* Dispose of any allocated data. */ - WC_FREE_VAR_EX(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - WOLFSSL_LEAVE("wolfSSL_RSA_verify_mgf", ret); - return ret; -} - -/* - * RSA public/private encrypt/decrypt APIs - */ - -/* Encrypt with the RSA public key. - * - * Return compliant with OpenSSL. - * - * @param [in] len Length of data to encrypt. - * @param [in] from Data to encrypt. - * @param [out] to Encrypted data. - * @param [in] rsa RSA key. - * @param [in] padding Type of padding to place around plaintext. - * @return Size of encrypted data on success. - * @return -1 on failure. - */ -int wolfSSL_RSA_public_encrypt(int len, const unsigned char* from, - unsigned char* to, WOLFSSL_RSA* rsa, int padding) -{ - int ret = 0; - int initTmpRng = 0; - WC_RNG *rng = NULL; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG* tmpRng = NULL; -#else - WC_RNG _tmpRng[1]; - WC_RNG* tmpRng = _tmpRng; -#endif -#if !defined(HAVE_FIPS) - int mgf = WC_MGF1NONE; - enum wc_HashType hash = WC_HASH_TYPE_NONE; - int pad_type = WC_RSA_NO_PAD; -#endif - int outLen = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_public_encrypt"); - - /* Validate parameters. */ - if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || - (from == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - #if !defined(HAVE_FIPS) - /* Convert to wolfCrypt padding, hash and MGF. */ - switch (padding) { - case WC_RSA_PKCS1_PADDING: - pad_type = WC_RSA_PKCSV15_PAD; - break; - case WC_RSA_PKCS1_OAEP_PADDING: - pad_type = WC_RSA_OAEP_PAD; - hash = WC_HASH_TYPE_SHA; - mgf = WC_MGF1SHA1; - break; - case WC_RSA_NO_PAD: - pad_type = WC_RSA_NO_PAD; - break; - default: - WOLFSSL_ERROR_MSG("RSA_public_encrypt doesn't support padding " - "scheme"); - ret = WOLFSSL_FATAL_ERROR; - } - #else - /* Check for supported padding schemes in FIPS. */ - /* TODO: Do we support more schemes in later versions of FIPS? */ - if (padding != WC_RSA_PKCS1_PADDING) { - WOLFSSL_ERROR_MSG("RSA_public_encrypt pad type not supported in " - "FIPS"); - ret = WOLFSSL_FATAL_ERROR; - } - #endif - } - - /* Set wolfCrypt RSA key data from external if not already done. */ - if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - /* Calculate maximum length of encrypted data. */ - outLen = wolfSSL_RSA_size(rsa); - if (outLen == 0) { - WOLFSSL_ERROR_MSG("Bad RSA size"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 0) { - /* Get an RNG. */ - rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); - if (rng == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 0) { - /* Use wolfCrypt to public-encrypt with RSA key. */ - #if !defined(HAVE_FIPS) - ret = wc_RsaPublicEncrypt_ex(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal, rng, pad_type, hash, mgf, NULL, 0); - #else - ret = wc_RsaPublicEncrypt(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal, rng); - #endif - } - - /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ - if (initTmpRng) { - wc_FreeRng(tmpRng); - } - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - - /* wolfCrypt error means return -1. */ - if (ret <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - WOLFSSL_LEAVE("wolfSSL_RSA_public_encrypt", ret); - return ret; -} - -/* Decrypt with the RSA public key. - * - * Return compliant with OpenSSL. - * - * @param [in] len Length of encrypted data. - * @param [in] from Encrypted data. - * @param [out] to Decrypted data. - * @param [in] rsa RSA key. - * @param [in] padding Type of padding to around plaintext to remove. - * @return Size of decrypted data on success. - * @return -1 on failure. - */ -int wolfSSL_RSA_private_decrypt(int len, const unsigned char* from, - unsigned char* to, WOLFSSL_RSA* rsa, int padding) -{ - int ret = 0; -#if !defined(HAVE_FIPS) - int mgf = WC_MGF1NONE; - enum wc_HashType hash = WC_HASH_TYPE_NONE; - int pad_type = WC_RSA_NO_PAD; -#endif - int outLen = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_private_decrypt"); - - /* Validate parameters. */ - if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || - (from == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - #if !defined(HAVE_FIPS) - switch (padding) { - case WC_RSA_PKCS1_PADDING: - pad_type = WC_RSA_PKCSV15_PAD; - break; - case WC_RSA_PKCS1_OAEP_PADDING: - pad_type = WC_RSA_OAEP_PAD; - hash = WC_HASH_TYPE_SHA; - mgf = WC_MGF1SHA1; - break; - case WC_RSA_NO_PAD: - pad_type = WC_RSA_NO_PAD; - break; - default: - WOLFSSL_ERROR_MSG("RSA_private_decrypt unsupported padding"); - ret = WOLFSSL_FATAL_ERROR; - } - #else - /* Check for supported padding schemes in FIPS. */ - /* TODO: Do we support more schemes in later versions of FIPS? */ - if (padding != WC_RSA_PKCS1_PADDING) { - WOLFSSL_ERROR_MSG("RSA_public_encrypt pad type not supported in " - "FIPS"); - ret = WOLFSSL_FATAL_ERROR; - } - #endif - } - - /* Set wolfCrypt RSA key data from external if not already done. */ - if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - /* Calculate maximum length of decrypted data. */ - outLen = wolfSSL_RSA_size(rsa); - if (outLen == 0) { - WOLFSSL_ERROR_MSG("Bad RSA size"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 0) { - /* Use wolfCrypt to private-decrypt with RSA key. - * Size of 'to' buffer must be size of RSA key */ - #if !defined(HAVE_FIPS) - ret = wc_RsaPrivateDecrypt_ex(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal, pad_type, hash, mgf, NULL, 0); - #else - ret = wc_RsaPrivateDecrypt(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal); - #endif - } - - /* wolfCrypt error means return -1. */ - if (ret <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - WOLFSSL_LEAVE("wolfSSL_RSA_private_decrypt", ret); - return ret; -} - -/* Decrypt with the RSA public key. - * - * @param [in] len Length of encrypted data. - * @param [in] from Encrypted data. - * @param [out] to Decrypted data. - * @param [in] rsa RSA key. - * @param [in] padding Type of padding to around plaintext to remove. - * @return Size of decrypted data on success. - * @return -1 on failure. - */ -int wolfSSL_RSA_public_decrypt(int len, const unsigned char* from, - unsigned char* to, WOLFSSL_RSA* rsa, int padding) -{ - int ret = 0; -#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - int pad_type = WC_RSA_NO_PAD; -#endif - int outLen = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_public_decrypt"); - - /* Validate parameters. */ - if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || - (from == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - switch (padding) { - case WC_RSA_PKCS1_PADDING: - pad_type = WC_RSA_PKCSV15_PAD; - break; - case WC_RSA_NO_PAD: - pad_type = WC_RSA_NO_PAD; - break; - /* TODO: RSA_X931_PADDING not supported */ - default: - WOLFSSL_ERROR_MSG("RSA_public_decrypt unsupported padding"); - ret = WOLFSSL_FATAL_ERROR; - } - #else - if (padding != WC_RSA_PKCS1_PADDING) { - WOLFSSL_ERROR_MSG("RSA_public_decrypt pad type not supported in " - "FIPS"); - ret = WOLFSSL_FATAL_ERROR; - } - #endif - } - - /* Set wolfCrypt RSA key data from external if not already done. */ - if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - /* Calculate maximum length of encrypted data. */ - outLen = wolfSSL_RSA_size(rsa); - if (outLen == 0) { - WOLFSSL_ERROR_MSG("Bad RSA size"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 0) { - /* Use wolfCrypt to public-decrypt with RSA key. */ - #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - /* Size of 'to' buffer must be size of RSA key. */ - ret = wc_RsaSSL_Verify_ex(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal, pad_type); - #else - /* For FIPS v1/v2 only PKCSV15 padding is supported */ - ret = wc_RsaSSL_Verify(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal); - #endif - } - - /* wolfCrypt error means return -1. */ - if (ret <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - WOLFSSL_LEAVE("wolfSSL_RSA_public_decrypt", ret); - return ret; -} - -/* Encrypt with the RSA private key. - * - * Calls wc_RsaSSL_Sign. - * - * @param [in] len Length of data to encrypt. - * @param [in] from Data to encrypt. - * @param [out] to Encrypted data. - * @param [in] rsa RSA key. - * @param [in] padding Type of padding to place around plaintext. - * @return Size of encrypted data on success. - * @return -1 on failure. - */ -int wolfSSL_RSA_private_encrypt(int len, const unsigned char* from, - unsigned char* to, WOLFSSL_RSA* rsa, int padding) -{ - int ret = 0; - int initTmpRng = 0; - WC_RNG *rng = NULL; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG* tmpRng = NULL; -#else - WC_RNG _tmpRng[1]; - WC_RNG* tmpRng = _tmpRng; -#endif - - WOLFSSL_ENTER("wolfSSL_RSA_private_encrypt"); - - /* Validate parameters. */ - if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || - (from == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - switch (padding) { - case WC_RSA_PKCS1_PADDING: - #ifdef WC_RSA_NO_PADDING - case WC_RSA_NO_PAD: - #endif - break; - /* TODO: RSA_X931_PADDING not supported */ - default: - WOLFSSL_ERROR_MSG("RSA_private_encrypt unsupported padding"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - /* Set wolfCrypt RSA key data from external if not already done. */ - if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - /* Get an RNG. */ - rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); - if (rng == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 0) { - /* Use wolfCrypt to private-encrypt with RSA key. - * Size of output buffer must be size of RSA key. */ - if (padding == WC_RSA_PKCS1_PADDING) { - ret = wc_RsaSSL_Sign(from, (word32)len, to, - (word32)wolfSSL_RSA_size(rsa), (RsaKey*)rsa->internal, rng); - } - #ifdef WC_RSA_NO_PADDING - else if (padding == WC_RSA_NO_PAD) { - word32 outLen = (word32)wolfSSL_RSA_size(rsa); - ret = wc_RsaFunction(from, (word32)len, to, &outLen, - RSA_PRIVATE_ENCRYPT, (RsaKey*)rsa->internal, rng); - if (ret == 0) - ret = (int)outLen; - } - #endif - } - - /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ - if (initTmpRng) { - wc_FreeRng(tmpRng); - } - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - - /* wolfCrypt error means return -1. */ - if (ret <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - WOLFSSL_LEAVE("wolfSSL_RSA_private_encrypt", ret); - return ret; -} - -/* - * RSA misc operation APIs - */ - -/* Calculate d mod p-1 and q-1 into BNs. - * - * Not OpenSSL API. - * - * @param [in, out] rsa RSA key. - * @return 1 on success. - * @return -1 on failure. - */ -int wolfSSL_RSA_GenAdd(WOLFSSL_RSA* rsa) -{ - int ret = 1; - int err; - mp_int* t = NULL; - WC_DECLARE_VAR(tmp, mp_int, 1, 0); - - WOLFSSL_ENTER("wolfSSL_RsaGenAdd"); - - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->p == NULL) || (rsa->q == NULL) || - (rsa->d == NULL) || (rsa->dmp1 == NULL) || (rsa->dmq1 == NULL)) { - WOLFSSL_ERROR_MSG("rsa no init error"); - ret = WOLFSSL_FATAL_ERROR; - } - -#ifdef WOLFSSL_SMALL_STACK - if (ret == 1) { - tmp = (mp_int *)XMALLOC(sizeof(*tmp), rsa->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (tmp == NULL) { - WOLFSSL_ERROR_MSG("Memory allocation failure"); - ret = WOLFSSL_FATAL_ERROR; - } - } -#endif - - if (ret == 1) { - /* Initialize temp MP integer. */ - if (mp_init(tmp) != MP_OKAY) { - WOLFSSL_ERROR_MSG("mp_init error"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 1) { - t = tmp; - - /* Sub 1 from p into temp. */ - err = mp_sub_d((mp_int*)rsa->p->internal, 1, tmp); - if (err != MP_OKAY) { - WOLFSSL_ERROR_MSG("mp_sub_d error"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Calculate d mod (p - 1) into dmp1 MP integer of BN. */ - err = mp_mod((mp_int*)rsa->d->internal, tmp, - (mp_int*)rsa->dmp1->internal); - if (err != MP_OKAY) { - WOLFSSL_ERROR_MSG("mp_mod error"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Sub 1 from q into temp. */ - err = mp_sub_d((mp_int*)rsa->q->internal, 1, tmp); - if (err != MP_OKAY) { - WOLFSSL_ERROR_MSG("mp_sub_d error"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Calculate d mod (q - 1) into dmq1 MP integer of BN. */ - err = mp_mod((mp_int*)rsa->d->internal, tmp, - (mp_int*)rsa->dmq1->internal); - if (err != MP_OKAY) { - WOLFSSL_ERROR_MSG("mp_mod error"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - mp_clear(t); - -#ifdef WOLFSSL_SMALL_STACK - if (rsa != NULL) { - XFREE(tmp, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER); - } -#endif - - return ret; -} - - -#ifndef NO_WOLFSSL_STUB -/* Enable blinding for RSA key operations. - * - * Blinding is a compile time option in wolfCrypt. - * - * @param [in] rsa RSA key. Unused. - * @param [in] bnCtx BN context to use for blinding. Unused. - * @return 1 always. - */ -int wolfSSL_RSA_blinding_on(WOLFSSL_RSA* rsa, WOLFSSL_BN_CTX* bnCtx) -{ - WOLFSSL_STUB("RSA_blinding_on"); - WOLFSSL_ENTER("wolfSSL_RSA_blinding_on"); - - (void)rsa; - (void)bnCtx; - - return 1; /* on by default */ -} -#endif - -#endif /* OPENSSL_EXTRA */ - -#endif /* !NO_RSA */ - -/******************************************************************************* - * END OF RSA API - ******************************************************************************/ +#define WOLFSSL_PK_RSA_INCLUDED +#include "src/pk_rsa.c" /******************************************************************************* @@ -5393,7 +1478,7 @@ int wolfSSL_i2d_DSA_SIG(const WOLFSSL_DSA_SIG *sig, byte **out) } /** - * Same as wolfSSL_DSA_SIG_new but also initializes the internal bignums as well. + * Same as wolfSSL_DSA_SIG_new but also initializes the internal bignums. * @return New WOLFSSL_DSA_SIG with r and s created as well */ static WOLFSSL_DSA_SIG* wolfSSL_DSA_SIG_new_bn(void) @@ -6226,7 +2311,8 @@ WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSA_PUBKEY(WOLFSSL_BIO* bio,WOLFSSL_DSA** dsa, #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* return 1 if success, -1 if error */ -int wolfSSL_DSA_LoadDer(WOLFSSL_DSA* dsa, const unsigned char* derBuf, int derSz) +int wolfSSL_DSA_LoadDer(WOLFSSL_DSA* dsa, const unsigned char* derBuf, + int derSz) { word32 idx = 0; int ret; @@ -6330,7 +2416,7 @@ WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSAparams(WOLFSSL_BIO *bp, WOLFSSL_DSA **x, * cb is for a call back when encountering encrypted PEM files * if cb == NULL and u != NULL then u = null terminated password string */ - WOLFSSL_MSG("Not yet supporting call back or password for encrypted PEM"); + WOLFSSL_MSG("Not supporting callback or password for encrypted PEM"); } if (PemToDer(buf, (long)bufSz, DSA_PARAM_TYPE, &pDer, NULL, NULL, @@ -8950,5511 +5036,9 @@ int wolfSSL_DH_compute_key_padded(unsigned char* key, ******************************************************************************/ -/******************************************************************************* - * START OF EC API - ******************************************************************************/ +#define WOLFSSL_PK_EC_INCLUDED +#include "src/pk_ec.c" -#ifdef HAVE_ECC - -#if defined(OPENSSL_EXTRA) - -/* Start EC_curve */ - -/* Get the NIST name for the numeric ID. - * - * @param [in] nid Numeric ID of an EC curve. - * @return String representing NIST name of EC curve on success. - * @return NULL on error. - */ -const char* wolfSSL_EC_curve_nid2nist(int nid) -{ - const char* name = NULL; - const WOLF_EC_NIST_NAME* nist_name; - - /* Attempt to find the curve info matching the NID passed in. */ - for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { - if (nist_name->nid == nid) { - /* NID found - return name. */ - name = nist_name->name; - break; - } - } - - return name; -} - -/* Get the numeric ID for the NIST name. - * - * @param [in] name NIST name of EC curve. - * @return NID matching NIST name on success. - * @return 0 on error. - */ -int wolfSSL_EC_curve_nist2nid(const char* name) -{ - int nid = 0; - const WOLF_EC_NIST_NAME* nist_name; - - /* Attempt to find the curve info matching the NIST name passed in. */ - for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { - if (XSTRCMP(nist_name->name, name) == 0) { - /* Name found - return NID. */ - nid = nist_name->nid; - break; - } - } - - return nid; -} - -#endif /* OPENSSL_EXTRA */ - -/* End EC_curve */ - -/* Start EC_METHOD */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Get the EC method of the EC group object. - * - * wolfSSL doesn't use method tables. Implementation used is dependent upon - * the NID. - * - * @param [in] group EC group object. - * @return EC method. - */ -const WOLFSSL_EC_METHOD* wolfSSL_EC_GROUP_method_of( - const WOLFSSL_EC_GROUP *group) -{ - /* No method table used so just return the same object. */ - return group; -} - -/* Get field type for method. - * - * Only prime fields are supported. - * - * @param [in] meth EC method. - * @return X9.63 prime field NID on success. - * @return 0 on error. - */ -int wolfSSL_EC_METHOD_get_field_type(const WOLFSSL_EC_METHOD *meth) -{ - int nid = 0; - - if (meth != NULL) { - /* Only field type supported by code base. */ - nid = WC_NID_X9_62_prime_field; - } - - return nid; -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -/* End EC_METHOD */ - -/* Start EC_GROUP */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Converts ECC curve enum values in ecc_curve_id to the associated OpenSSL NID - * value. - * - * @param [in] n ECC curve id. - * @return ECC curve NID (OpenSSL compatible value). - */ -int EccEnumToNID(int n) -{ - WOLFSSL_ENTER("EccEnumToNID"); - - switch(n) { - case ECC_SECP192R1: - return WC_NID_X9_62_prime192v1; - case ECC_PRIME192V2: - return WC_NID_X9_62_prime192v2; - case ECC_PRIME192V3: - return WC_NID_X9_62_prime192v3; - case ECC_PRIME239V1: - return WC_NID_X9_62_prime239v1; - case ECC_PRIME239V2: - return WC_NID_X9_62_prime239v2; - case ECC_PRIME239V3: - return WC_NID_X9_62_prime239v3; - case ECC_SECP256R1: - return WC_NID_X9_62_prime256v1; - case ECC_SECP112R1: - return WC_NID_secp112r1; - case ECC_SECP112R2: - return WC_NID_secp112r2; - case ECC_SECP128R1: - return WC_NID_secp128r1; - case ECC_SECP128R2: - return WC_NID_secp128r2; - case ECC_SECP160R1: - return WC_NID_secp160r1; - case ECC_SECP160R2: - return WC_NID_secp160r2; - case ECC_SECP224R1: - return WC_NID_secp224r1; - case ECC_SECP384R1: - return WC_NID_secp384r1; - case ECC_SECP521R1: - return WC_NID_secp521r1; - case ECC_SECP160K1: - return WC_NID_secp160k1; - case ECC_SECP192K1: - return WC_NID_secp192k1; - case ECC_SECP224K1: - return WC_NID_secp224k1; - case ECC_SECP256K1: - return WC_NID_secp256k1; - case ECC_BRAINPOOLP160R1: - return WC_NID_brainpoolP160r1; - case ECC_BRAINPOOLP192R1: - return WC_NID_brainpoolP192r1; - case ECC_BRAINPOOLP224R1: - return WC_NID_brainpoolP224r1; - case ECC_BRAINPOOLP256R1: - return WC_NID_brainpoolP256r1; - case ECC_BRAINPOOLP320R1: - return WC_NID_brainpoolP320r1; - case ECC_BRAINPOOLP384R1: - return WC_NID_brainpoolP384r1; - case ECC_BRAINPOOLP512R1: - return WC_NID_brainpoolP512r1; - #ifdef WOLFSSL_SM2 - case ECC_SM2P256V1: - return WC_NID_sm2; - #endif - default: - WOLFSSL_MSG("NID not found"); - return WOLFSSL_FATAL_ERROR; - } -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) -/* Converts OpenSSL NID of EC curve to the enum value in ecc_curve_id - * - * Used by ecc_sets[]. - * - * @param [in] n OpenSSL NID of EC curve. - * @return wolfCrypt EC curve id. - * @return -1 on error. - */ -int NIDToEccEnum(int nid) -{ - int id; - - WOLFSSL_ENTER("NIDToEccEnum"); - - switch (nid) { - case WC_NID_X9_62_prime192v1: - id = ECC_SECP192R1; - break; - case WC_NID_X9_62_prime192v2: - id = ECC_PRIME192V2; - break; - case WC_NID_X9_62_prime192v3: - id = ECC_PRIME192V3; - break; - case WC_NID_X9_62_prime239v1: - id = ECC_PRIME239V1; - break; - case WC_NID_X9_62_prime239v2: - id = ECC_PRIME239V2; - break; - case WC_NID_X9_62_prime239v3: - id = ECC_PRIME239V3; - break; - case WC_NID_X9_62_prime256v1: - id = ECC_SECP256R1; - break; - case WC_NID_secp112r1: - id = ECC_SECP112R1; - break; - case WC_NID_secp112r2: - id = ECC_SECP112R2; - break; - case WC_NID_secp128r1: - id = ECC_SECP128R1; - break; - case WC_NID_secp128r2: - id = ECC_SECP128R2; - break; - case WC_NID_secp160r1: - id = ECC_SECP160R1; - break; - case WC_NID_secp160r2: - id = ECC_SECP160R2; - break; - case WC_NID_secp224r1: - id = ECC_SECP224R1; - break; - case WC_NID_secp384r1: - id = ECC_SECP384R1; - break; - case WC_NID_secp521r1: - id = ECC_SECP521R1; - break; - case WC_NID_secp160k1: - id = ECC_SECP160K1; - break; - case WC_NID_secp192k1: - id = ECC_SECP192K1; - break; - case WC_NID_secp224k1: - id = ECC_SECP224K1; - break; - case WC_NID_secp256k1: - id = ECC_SECP256K1; - break; - case WC_NID_brainpoolP160r1: - id = ECC_BRAINPOOLP160R1; - break; - case WC_NID_brainpoolP192r1: - id = ECC_BRAINPOOLP192R1; - break; - case WC_NID_brainpoolP224r1: - id = ECC_BRAINPOOLP224R1; - break; - case WC_NID_brainpoolP256r1: - id = ECC_BRAINPOOLP256R1; - break; - case WC_NID_brainpoolP320r1: - id = ECC_BRAINPOOLP320R1; - break; - case WC_NID_brainpoolP384r1: - id = ECC_BRAINPOOLP384R1; - break; - case WC_NID_brainpoolP512r1: - id = ECC_BRAINPOOLP512R1; - break; - default: - WOLFSSL_MSG("NID not found"); - /* -1 on error. */ - id = WOLFSSL_FATAL_ERROR; - } - - return id; -} - -/* Set the fields of the EC group based on numeric ID. - * - * @param [in, out] group EC group. - * @param [in] nid Numeric ID of an EC curve. - */ -static void ec_group_set_nid(WOLFSSL_EC_GROUP* group, int nid) -{ - int eccEnum; - int realNid; - - /* Convert ecc_curve_id enum to NID. */ - if ((realNid = EccEnumToNID(nid)) != -1) { - /* ecc_curve_id enum passed in - have real NID value set. */ - eccEnum = nid; - } - else { - /* NID passed in is OpenSSL type. */ - realNid = nid; - /* Convert NID to ecc_curve_id enum. */ - eccEnum = NIDToEccEnum(nid); - } - - /* Set the numeric ID of the curve */ - group->curve_nid = realNid; - /* Initialize index to -1 (i.e. wolfCrypt doesn't support curve). */ - group->curve_idx = -1; - - /* Find index and OID sum for curve if wolfCrypt supports it. */ - if (eccEnum != -1) { - int i; - - /* Find id and set the internal curve idx and OID sum. */ - for (i = 0; ecc_sets[i].size != 0; i++) { - if (ecc_sets[i].id == eccEnum) { - /* Found id in wolfCrypt supported EC curves. */ - group->curve_idx = i; - group->curve_oid = (int)ecc_sets[i].oidSum; - break; - } - } - } -} - -/* Create a new EC group with the numeric ID for an EC curve. - * - * @param [in] nid Numeric ID of an EC curve. - * @return New, allocated EC group on success. - * @return NULL on error. - */ -WOLFSSL_EC_GROUP* wolfSSL_EC_GROUP_new_by_curve_name(int nid) -{ - int err = 0; - WOLFSSL_EC_GROUP* group; - - WOLFSSL_ENTER("wolfSSL_EC_GROUP_new_by_curve_name"); - - /* Allocate EC group. */ - group = (WOLFSSL_EC_GROUP*)XMALLOC(sizeof(WOLFSSL_EC_GROUP), NULL, - DYNAMIC_TYPE_ECC); - if (group == NULL) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_new_by_curve_name malloc failure"); - err = 1; - } - - if (!err) { - /* Reset all fields. */ - XMEMSET(group, 0, sizeof(WOLFSSL_EC_GROUP)); - - /* Set the fields of group based on the numeric ID. */ - ec_group_set_nid(group, nid); - } - - return group; -} -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Dispose of the EC group. - * - * Cannot use group after this call. - * - * @param [in] group EC group to free. - */ -void wolfSSL_EC_GROUP_free(WOLFSSL_EC_GROUP *group) -{ - WOLFSSL_ENTER("wolfSSL_EC_GROUP_free"); - - /* Dispose of EC group. */ - XFREE(group, NULL, DYNAMIC_TYPE_ECC); -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#ifdef OPENSSL_EXTRA -#ifndef NO_BIO - -/* Creates an EC group from the DER encoding. - * - * Only named curves supported. - * - * @param [out] group Reference to EC group object. - * @param [in] in Buffer holding DER encoding of curve. - * @param [in] inSz Length of data in buffer. - * @return EC group on success. - * @return NULL on error. - */ -static WOLFSSL_EC_GROUP* wolfssl_ec_group_d2i(WOLFSSL_EC_GROUP** group, - const unsigned char** in_pp, long inSz) -{ - int err = 0; - WOLFSSL_EC_GROUP* ret = NULL; - word32 idx = 0; - word32 oid = 0; - int id = 0; - const unsigned char* in; - - if (in_pp == NULL || *in_pp == NULL) - return NULL; - - in = *in_pp; - - /* Use the group passed in. */ - if ((group != NULL) && (*group != NULL)) { - ret = *group; - } - - /* Only support named curves. */ - if (in[0] != ASN_OBJECT_ID) { - WOLFSSL_ERROR_MSG("Invalid or unsupported encoding"); - err = 1; - } - /* Decode the OBJECT ID - expecting an EC curve OID. */ - if ((!err) && (GetObjectId(in, &idx, &oid, oidCurveType, (word32)inSz) != - 0)) { - err = 1; - } - if (!err) { - /* Get the internal ID for OID. */ - id = wc_ecc_get_oid(oid, NULL, NULL); - if (id < 0) { - err = 1; - } - } - if (!err) { - /* Get the NID for the internal ID. */ - int nid = EccEnumToNID(id); - if (ret == NULL) { - /* Create a new EC group with the numeric ID. */ - ret = wolfSSL_EC_GROUP_new_by_curve_name(nid); - if (ret == NULL) { - err = 1; - } - } - else { - ec_group_set_nid(ret, nid); - } - } - if ((!err) && (group != NULL)) { - /* Return the EC group through reference. */ - *group = ret; - } - - if (err) { - if ((ret != NULL) && (ret != *group)) { - wolfSSL_EC_GROUP_free(ret); - } - ret = NULL; - } - else { - *in_pp += idx; - } - return ret; -} - -/* Creates a new EC group from the PEM encoding in the BIO. - * - * @param [in] bio BIO to read PEM encoding from. - * @param [out] group Reference to EC group object. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * @return EC group on success. - * @return NULL on error. - */ -WOLFSSL_EC_GROUP* wolfSSL_PEM_read_bio_ECPKParameters(WOLFSSL_BIO* bio, - WOLFSSL_EC_GROUP** group, wc_pem_password_cb* cb, void* pass) -{ - int err = 0; - WOLFSSL_EC_GROUP* ret = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - if (bio == NULL) { - err = 1; - } - - /* Read parameters from BIO and convert PEM to DER. */ - if ((!err) && (pem_read_bio_key(bio, cb, pass, ECC_PARAM_TYPE, - &keyFormat, &der) < 0)) { - err = 1; - } - if (!err) { - /* Create EC group from DER encoding. */ - const byte** p = (const byte**)&der->buffer; - ret = wolfssl_ec_group_d2i(group, p, der->length); - if (ret == NULL) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_GROUP"); - } - } - - /* Dispose of any allocated data. */ - FreeDer(&der); - return ret; -} - -WOLFSSL_EC_GROUP *wolfSSL_d2i_ECPKParameters(WOLFSSL_EC_GROUP **out, - const unsigned char **in, long len) -{ - return wolfssl_ec_group_d2i(out, in, len); -} - -int wolfSSL_i2d_ECPKParameters(const WOLFSSL_EC_GROUP* grp, unsigned char** pp) -{ - unsigned char* out = NULL; - int len = 0; - int idx; - const byte* oid = NULL; - word32 oidSz = 0; - - if (grp == NULL || !wc_ecc_is_valid_idx(grp->curve_idx) || - grp->curve_idx < 0) - return WOLFSSL_FATAL_ERROR; - - /* Get the actual DER encoding of the OID. ecc_sets[grp->curve_idx].oid - * is just the numerical representation. */ - if (wc_ecc_get_oid((word32)grp->curve_oid, &oid, &oidSz) < 0) - return WOLFSSL_FATAL_ERROR; - - len = SetObjectId((int)oidSz, NULL) + (int)oidSz; - - if (pp == NULL) - return len; - - if (*pp == NULL) { - out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1); - if (out == NULL) - return WOLFSSL_FATAL_ERROR; - } - else { - out = *pp; - } - - idx = SetObjectId((int)oidSz, out); - XMEMCPY(out + idx, oid, oidSz); - if (*pp == NULL) - *pp = out; - else - *pp += len; - - return len; -} -#endif /* !NO_BIO */ - -#if defined(OPENSSL_ALL) && !defined(NO_CERTS) -/* Copy an EC group. - * - * Only used by wolfSSL_EC_KEY_dup at this time. - * - * @param [in, out] dst Destination EC group. - * @param [in] src Source EC group. - * @return 0 on success. - */ -static int wolfssl_ec_group_copy(WOLFSSL_EC_GROUP* dst, - const WOLFSSL_EC_GROUP* src) -{ - /* Copy the fields. */ - dst->curve_idx = src->curve_idx; - dst->curve_nid = src->curve_nid; - dst->curve_oid = src->curve_oid; - - return 0; -} -#endif /* OPENSSL_ALL && !NO_CERTS */ - -/* Copies ecc_key into new WOLFSSL_EC_GROUP object - * - * @param [in] src EC group to duplicate. - * - * @return EC group on success. - * @return NULL on error. - */ -WOLFSSL_EC_GROUP* wolfSSL_EC_GROUP_dup(const WOLFSSL_EC_GROUP *src) -{ - WOLFSSL_EC_GROUP* newGroup = NULL; - - if (src != NULL) { - /* Create new group base on NID in original EC group. */ - newGroup = wolfSSL_EC_GROUP_new_by_curve_name(src->curve_nid); - } - - return newGroup; -} - -/* Compare two EC groups. - * - * Return code compliant with OpenSSL. - * - * @param [in] a First EC group. - * @param [in] b Second EC group. - * @param [in] ctx Big number context to use when comparing fields. Unused. - * - * @return 0 if equal. - * @return 1 if not equal. - * @return -1 on error. - */ -int wolfSSL_EC_GROUP_cmp(const WOLFSSL_EC_GROUP *a, const WOLFSSL_EC_GROUP *b, - WOLFSSL_BN_CTX *ctx) -{ - int ret; - - /* No BN operations performed. */ - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_EC_GROUP_cmp"); - - /* Validate parameters. */ - if ((a == NULL) || (b == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_cmp Bad arguments"); - /* Return error value. */ - ret = WOLFSSL_FATAL_ERROR; - } - /* Compare NID and wolfSSL curve index. */ - else { - /* 0 when same, 1 when not. */ - ret = ((a->curve_nid == b->curve_nid) && - (a->curve_idx == b->curve_idx)) ? 0 : 1; - } - - return ret; -} - -#ifndef NO_WOLFSSL_STUB -/* Set the ASN.1 flag that indicate encoding of curve. - * - * Stub function - flag not used elsewhere. - * Always encoded as named curve. - * - * @param [in] group EC group to modify. - * @param [in] flag ASN.1 flag to set. Valid values: - * OPENSSL_EC_EXPLICIT_CURVE, OPENSSL_EC_NAMED_CURVE - */ -void wolfSSL_EC_GROUP_set_asn1_flag(WOLFSSL_EC_GROUP *group, int flag) -{ - (void)group; - (void)flag; - - WOLFSSL_ENTER("wolfSSL_EC_GROUP_set_asn1_flag"); - WOLFSSL_STUB("EC_GROUP_set_asn1_flag"); -} -#endif - -/* Get the curve NID of the group. - * - * Return code compliant with OpenSSL. - * - * @param [in] group EC group. - * @return Curve NID on success. - * @return 0 on error. - */ -int wolfSSL_EC_GROUP_get_curve_name(const WOLFSSL_EC_GROUP *group) -{ - int nid = 0; - WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_curve_name"); - - if (group == NULL) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_curve_name Bad arguments"); - } - else { - nid = group->curve_nid; - } - - return nid; -} - -/* Get the degree (curve size in bits) of the EC group. - * - * Return code compliant with OpenSSL. - * - * @return Degree of the curve on success. - * @return 0 on error. - */ -int wolfSSL_EC_GROUP_get_degree(const WOLFSSL_EC_GROUP *group) -{ - int degree = 0; - - WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_degree"); - - if (group == NULL) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_degree Bad arguments"); - } - else { - switch (group->curve_nid) { - case WC_NID_secp112r1: - case WC_NID_secp112r2: - degree = 112; - break; - case WC_NID_secp128r1: - case WC_NID_secp128r2: - degree = 128; - break; - case WC_NID_secp160k1: - case WC_NID_secp160r1: - case WC_NID_secp160r2: - case WC_NID_brainpoolP160r1: - degree = 160; - break; - case WC_NID_secp192k1: - case WC_NID_brainpoolP192r1: - case WC_NID_X9_62_prime192v1: - case WC_NID_X9_62_prime192v2: - case WC_NID_X9_62_prime192v3: - degree = 192; - break; - case WC_NID_secp224k1: - case WC_NID_secp224r1: - case WC_NID_brainpoolP224r1: - degree = 224; - break; - case WC_NID_X9_62_prime239v1: - case WC_NID_X9_62_prime239v2: - case WC_NID_X9_62_prime239v3: - degree = 239; - break; - case WC_NID_secp256k1: - case WC_NID_brainpoolP256r1: - case WC_NID_X9_62_prime256v1: - degree = 256; - break; - case WC_NID_brainpoolP320r1: - degree = 320; - break; - case WC_NID_secp384r1: - case WC_NID_brainpoolP384r1: - degree = 384; - break; - case WC_NID_brainpoolP512r1: - degree = 512; - break; - case WC_NID_secp521r1: - degree = 521; - break; - } - } - - return degree; -} -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) -/* Get the length of the order in bits of the EC group. - * - * TODO: consider switch statement or calculating directly from hex string - * array instead of using mp_int. - * - * @param [in] group EC group. - * @return Length of order in bits on success. - * @return 0 on error. - */ -int wolfSSL_EC_GROUP_order_bits(const WOLFSSL_EC_GROUP *group) -{ - int ret = 0; - WC_DECLARE_VAR(order, mp_int, 1, 0); - - /* Validate parameter. */ - if ((group == NULL) || (group->curve_idx < 0)) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_order_bits NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - -#ifdef WOLFSSL_SMALL_STACK - if (ret == 0) { - /* Allocate memory for mp_int that will hold order value. */ - order = (mp_int *)XMALLOC(sizeof(*order), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (order == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } -#endif - - if (ret == 0) { - /* Initialize mp_int. */ - ret = mp_init(order); - } - - if (ret == 0) { - /* Read hex string of order from wolfCrypt array of curves. */ - ret = mp_read_radix(order, ecc_sets[group->curve_idx].order, - MP_RADIX_HEX); - if (ret == 0) { - /* Get bits of order. */ - ret = mp_count_bits(order); - } - /* Clear and free mp_int. */ - mp_clear(order); - } - - WC_FREE_VAR_EX(order, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - /* Convert error code to length of 0. */ - if (ret < 0) { - ret = 0; - } - - return ret; -} -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ - -#if defined(OPENSSL_EXTRA) -/* Get the order of the group as a BN. - * - * Return code compliant with OpenSSL. - * - * @param [in] group EC group. - * @param [in, out] order BN to hold order value. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_GROUP_get_order(const WOLFSSL_EC_GROUP *group, - WOLFSSL_BIGNUM *order, WOLFSSL_BN_CTX *ctx) -{ - int ret = 1; - mp_int* mp = NULL; - - /* No BN operations performed - done with mp_int in BN. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (order == NULL) || (order->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order NULL error"); - ret = 0; - } - - if (ret == 1 && - (group->curve_idx < 0 || !wc_ecc_is_valid_idx(group->curve_idx))) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order Bad group idx"); - ret = 0; - } - - if (ret == 1) { - mp = (mp_int*)order->internal; - } - /* Initialize */ - if ((ret == 1) && (mp_init(mp) != MP_OKAY)) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_init failure"); - ret = 0; - } - /* Read hex string of order from wolfCrypt array of curves. */ - if ((ret == 1) && (mp_read_radix(mp, ecc_sets[group->curve_idx].order, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_read order failure"); - /* Zero out any partial value but don't free. */ - mp_zero(mp); - ret = 0; - } - - return ret; -} - -#endif /* OPENSSL_EXTRA */ - -/* End EC_GROUP */ - -/* Start EC_POINT */ - -#if defined(OPENSSL_EXTRA) - -/* Set data of EC point into internal, wolfCrypt EC point object. - * - * EC_POINT Openssl -> WolfSSL - * - * @param [in, out] p EC point to update. - * @return 1 on success. - * @return -1 on failure. - */ -static int ec_point_internal_set(WOLFSSL_EC_POINT *p) -{ - int ret = 1; - - WOLFSSL_ENTER("ec_point_internal_set"); - - /* Validate parameter. */ - if ((p == NULL) || (p->internal == NULL)) { - WOLFSSL_MSG("ECPoint NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - else { - /* Get internal point as a wolfCrypt EC point. */ - ecc_point* point = (ecc_point*)p->internal; - - /* Set X ordinate if available. */ - if ((p->X != NULL) && (wolfssl_bn_get_value(p->X, point->x) != 1)) { - WOLFSSL_MSG("ecc point X error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Set Y ordinate if available. */ - if ((ret == 1) && (p->Y != NULL) && (wolfssl_bn_get_value(p->Y, - point->y) != 1)) { - WOLFSSL_MSG("ecc point Y error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Set Z ordinate if available. */ - if ((ret == 1) && (p->Z != NULL) && (wolfssl_bn_get_value(p->Z, - point->z) != 1)) { - WOLFSSL_MSG("ecc point Z error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Internal values set when operations succeeded. */ - p->inSet = (ret == 1); - } - - return ret; -} - -/* Set data of internal, wolfCrypt EC point object into EC point. - * - * EC_POINT WolfSSL -> OpenSSL - * - * @param [in, out] p EC point to update. - * @return 1 on success. - * @return -1 on failure. - */ -static int ec_point_external_set(WOLFSSL_EC_POINT *p) -{ - int ret = 1; - - WOLFSSL_ENTER("ec_point_external_set"); - - /* Validate parameter. */ - if ((p == NULL) || (p->internal == NULL)) { - WOLFSSL_MSG("ECPoint NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - else { - /* Get internal point as a wolfCrypt EC point. */ - ecc_point* point = (ecc_point*)p->internal; - - /* Set X ordinate. */ - if (wolfssl_bn_set_value(&p->X, point->x) != 1) { - WOLFSSL_MSG("ecc point X error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Set Y ordinate. */ - if ((ret == 1) && (wolfssl_bn_set_value(&p->Y, point->y) != 1)) { - WOLFSSL_MSG("ecc point Y error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Set Z ordinate. */ - if ((ret == 1) && (wolfssl_bn_set_value(&p->Z, point->z) != 1)) { - WOLFSSL_MSG("ecc point Z error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* External values set when operations succeeded. */ - p->exSet = (ret == 1); - } - - return ret; -} - -/* Setup internals of EC point. - * - * Assumes point is not NULL. - * - * @param [in, out] point EC point to update. - * @return 1 on success. - * @return 0 on failure. - */ -static int ec_point_setup(const WOLFSSL_EC_POINT *point) { - int ret = 1; - - /* Check if internal values need setting. */ - if (!point->inSet) { - WOLFSSL_MSG("No ECPoint internal set, do it"); - - /* Forcing to non-constant type to update internals. */ - if (ec_point_internal_set((WOLFSSL_EC_POINT *)point) != 1) { - WOLFSSL_MSG("ec_point_internal_set failed"); - ret = 0; - } - } - - return ret; -} - -/* Create a new EC point from the group. - * - * @param [in] group EC group. - * @return EC point on success. - * @return NULL on error. - */ -WOLFSSL_EC_POINT* wolfSSL_EC_POINT_new(const WOLFSSL_EC_GROUP* group) -{ - int err = 0; - WOLFSSL_EC_POINT* point = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_new"); - - /* Validate parameter. */ - if (group == NULL) { - WOLFSSL_MSG("wolfSSL_EC_POINT_new NULL error"); - err = 1; - } - - if (!err) { - /* Allocate memory for new EC point. */ - point = (WOLFSSL_EC_POINT*)XMALLOC(sizeof(WOLFSSL_EC_POINT), NULL, - DYNAMIC_TYPE_ECC); - if (point == NULL) { - WOLFSSL_MSG("wolfSSL_EC_POINT_new malloc ecc point failure"); - err = 1; - } - } - if (!err) { - /* Clear fields of EC point. */ - XMEMSET(point, 0, sizeof(WOLFSSL_EC_POINT)); - - /* Allocate internal EC point. */ - point->internal = wc_ecc_new_point(); - if (point->internal == NULL) { - WOLFSSL_MSG("ecc_new_point failure"); - err = 1; - } - } - - if (err) { - XFREE(point, NULL, DYNAMIC_TYPE_ECC); - point = NULL; - } - return point; -} - -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Dispose of the EC point. - * - * Cannot use point after this call. - * - * @param [in, out] point EC point to free. - */ -void wolfSSL_EC_POINT_free(WOLFSSL_EC_POINT *point) -{ - WOLFSSL_ENTER("wolfSSL_EC_POINT_free"); - - if (point != NULL) { - if (point->internal != NULL) { - wc_ecc_del_point((ecc_point*)point->internal); - point->internal = NULL; - } - - /* Free ordinates. */ - wolfSSL_BN_free(point->X); - wolfSSL_BN_free(point->Y); - wolfSSL_BN_free(point->Z); - /* Clear fields. */ - point->X = NULL; - point->Y = NULL; - point->Z = NULL; - point->inSet = 0; - point->exSet = 0; - - /* Dispose of EC point. */ - XFREE(point, NULL, DYNAMIC_TYPE_ECC); - } -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#ifdef OPENSSL_EXTRA - -/* Clear and dispose of the EC point. - * - * Cannot use point after this call. - * - * @param [in, out] point EC point to free. - */ -void wolfSSL_EC_POINT_clear_free(WOLFSSL_EC_POINT *point) -{ - WOLFSSL_ENTER("wolfSSL_EC_POINT_clear_free"); - - if (point != NULL) { - if (point->internal != NULL) { - /* Force internal point to be zeros. */ - #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - wc_ecc_forcezero_point((ecc_point*)point->internal); - #else - ecc_point* p = (ecc_point*)point->internal; - mp_forcezero(p->x); - mp_forcezero(p->y); - mp_forcezero(p->z); - #endif - wc_ecc_del_point((ecc_point*)point->internal); - point->internal = NULL; - } - - /* Clear the ordinates before freeing. */ - wolfSSL_BN_clear_free(point->X); - wolfSSL_BN_clear_free(point->Y); - wolfSSL_BN_clear_free(point->Z); - /* Clear fields. */ - point->X = NULL; - point->Y = NULL; - point->Z = NULL; - point->inSet = 0; - point->exSet = 0; - - /* Dispose of EC point. */ - XFREE(point, NULL, DYNAMIC_TYPE_ECC); - } -} - -/* Print out the internals of EC point in debug and when logging callback set. - * - * Not an OpenSSL API. - * - * TODO: Use WOLFSSL_MSG_EX()? - * - * @param [in] msg Message to prepend. - * @param [in] point EC point to print. - */ -void wolfSSL_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT *point) -{ -#if defined(DEBUG_WOLFSSL) - char *num; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_dump"); - - /* Only print when debugging on. */ - if (WOLFSSL_IS_DEBUG_ON()) { - if (point == NULL) { - /* No point passed in so just put out "NULL". */ - WOLFSSL_MSG_EX("%s = NULL\n", msg); - } - else { - /* Put out message and status of internal/external data set. */ - WOLFSSL_MSG_EX("%s:\n\tinSet=%d, exSet=%d\n", msg, point->inSet, - point->exSet); - /* Get x-ordinate as a hex string and print. */ - num = wolfSSL_BN_bn2hex(point->X); - WOLFSSL_MSG_EX("\tX = %s\n", num); - XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); - /* Get x-ordinate as a hex string and print. */ - num = wolfSSL_BN_bn2hex(point->Y); - WOLFSSL_MSG_EX("\tY = %s\n", num); - XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); - /* Get z-ordinate as a hex string and print. */ - num = wolfSSL_BN_bn2hex(point->Z); - WOLFSSL_MSG_EX("\tZ = %s\n", num); - XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); - } - } -#else - (void)msg; - (void)point; -#endif -} - -/* Convert EC point to hex string that as either uncompressed or compressed. - * - * ECC point compression types were not included in selftest ecc.h - * - * @param [in] group EC group for point. - * @param [in] point EC point to encode. - * @param [in] form Format of encoding. Valid values: - * POINT_CONVERSION_UNCOMPRESSED, POINT_CONVERSION_COMPRESSED - * @param [in] ctx Context to use for BN operations. Unused. - * @return Allocated hex string on success. - * @return NULL on error. - */ -char* wolfSSL_EC_POINT_point2hex(const WOLFSSL_EC_GROUP* group, - const WOLFSSL_EC_POINT* point, int form, WOLFSSL_BN_CTX* ctx) -{ - static const char* hexDigit = "0123456789ABCDEF"; - char* hex = NULL; - int i; - int sz = 0; - int len = 0; - int err = 0; - - /* No BN operations performed. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL)) { - err = 1; - } - /* Get curve id expects a positive index. */ - if ((!err) && (group->curve_idx < 0)) { - err = 1; - } - - if (!err) { - /* Get curve id to look up ordinate size. */ - int id = wc_ecc_get_curve_id(group->curve_idx); - /* Get size of ordinate. */ - if ((sz = wc_ecc_get_curve_size_from_id(id)) < 0) { - err = 1; - } - } - if (!err) { - /* [] */ - len = sz + 1; - if (form == WC_POINT_CONVERSION_UNCOMPRESSED) { - /* Include y ordinate when uncompressed. */ - len += sz; - } - - /* Hex string: allocate 2 bytes to represent each byte plus 1 for '\0'. - */ - hex = (char*)XMALLOC((size_t)(2 * len + 1), NULL, DYNAMIC_TYPE_ECC); - if (hex == NULL) { - err = 1; - } - } - if (!err) { - /* Make bytes all zeros to allow for ordinate values less than max size. - */ - XMEMSET(hex, 0, (size_t)(2 * len + 1)); - - /* Calculate offset as leading zeros not encoded. */ - i = sz - mp_unsigned_bin_size((mp_int*)point->X->internal) + 1; - /* Put in x-ordinate after format byte. */ - if (mp_to_unsigned_bin((mp_int*)point->X->internal, (byte*)(hex + i)) < - 0) { - err = 1; - } - } - if (!err) { - if (form == WC_POINT_CONVERSION_COMPRESSED) { - /* Compressed format byte value dependent on whether y-ordinate is - * odd. - */ - hex[0] = mp_isodd((mp_int*)point->Y->internal) ? - ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN; - /* No y-ordinate. */ - } - else { - /* Put in uncompressed format byte. */ - hex[0] = ECC_POINT_UNCOMP; - /* Calculate offset as leading zeros not encoded. */ - i = 1 + 2 * sz - mp_unsigned_bin_size((mp_int*)point->Y->internal); - /* Put in y-ordinate after x-ordinate. */ - if (mp_to_unsigned_bin((mp_int*)point->Y->internal, - (byte*)(hex + i)) < 0) { - err = 1; - } - } - } - if (!err) { - /* Convert binary encoding to hex string. */ - /* Start at end so as not to overwrite. */ - for (i = len-1; i >= 0; i--) { - /* Get byte value and store has hex string. */ - byte b = (byte)hex[i]; - hex[i * 2 + 1] = hexDigit[b & 0xf]; - hex[i * 2 ] = hexDigit[b >> 4]; - } - /* Memset put trailing zero or '\0' on end of string. */ - } - - if (err && (hex != NULL)) { - /* Dispose of allocated data not being returned. */ - XFREE(hex, NULL, DYNAMIC_TYPE_ECC); - hex = NULL; - } - /* Return hex string encoding. */ - return hex; -} - -static size_t hex_to_bytes(const char *hex, unsigned char *output, size_t sz) -{ - word32 i; - for (i = 0; i < sz; i++) { - signed char ch1, ch2; - ch1 = HexCharToByte(hex[i * 2]); - ch2 = HexCharToByte(hex[i * 2 + 1]); - if ((ch1 < 0) || (ch2 < 0)) { - WOLFSSL_MSG("hex_to_bytes: syntax error"); - return 0; - } - output[i] = (unsigned char)((ch1 << 4) + ch2); - } - return sz; -} - -WOLFSSL_EC_POINT* wolfSSL_EC_POINT_hex2point(const WOLFSSL_EC_GROUP *group, - const char *hex, WOLFSSL_EC_POINT*p, WOLFSSL_BN_CTX *ctx) -{ - /* for uncompressed mode */ - size_t str_sz; - WOLFSSL_BIGNUM *Gx = NULL; - WOLFSSL_BIGNUM *Gy = NULL; - char strGx[MAX_ECC_BYTES * 2 + 1]; - - /* for compressed mode */ - int key_sz; - byte *octGx = (byte *)strGx; /* octGx[MAX_ECC_BYTES] */ - - int p_alloc = 0; - int ret; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_hex2point"); - - if (group == NULL || hex == NULL || ctx == NULL) - return NULL; - - if (p == NULL) { - if ((p = wolfSSL_EC_POINT_new(group)) == NULL) { - WOLFSSL_MSG("wolfSSL_EC_POINT_new"); - goto err; - } - p_alloc = 1; - } - - key_sz = (wolfSSL_EC_GROUP_get_degree(group) + 7) / 8; - if (hex[0] == '0' && hex[1] == '4') { /* uncompressed mode */ - str_sz = (size_t)key_sz * 2; - - XMEMSET(strGx, 0x0, str_sz + 1); - XMEMCPY(strGx, hex + 2, str_sz); - - if (wolfSSL_BN_hex2bn(&Gx, strGx) == 0) - goto err; - - if (wolfSSL_BN_hex2bn(&Gy, hex + 2 + str_sz) == 0) - goto err; - - ret = wolfSSL_EC_POINT_set_affine_coordinates_GFp - (group, p, Gx, Gy, ctx); - - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp"); - goto err; - } - } - else if (hex[0] == '0' && (hex[1] == '2' || hex[1] == '3')) { - size_t sz = XSTRLEN(hex + 2) / 2; - /* compressed mode */ - octGx[0] = ECC_POINT_COMP_ODD; - if (hex_to_bytes(hex + 2, octGx + 1, sz) != sz) { - goto err; - } - if (wolfSSL_ECPoint_d2i(octGx, (word32)key_sz + 1, group, p) - != WOLFSSL_SUCCESS) { - goto err; - } - } - else - goto err; - - wolfSSL_BN_free(Gx); - wolfSSL_BN_free(Gy); - return p; - -err: - wolfSSL_BN_free(Gx); - wolfSSL_BN_free(Gy); - if (p_alloc) { - wolfSSL_EC_POINT_free(p); - } - return NULL; - -} - -/* Encode the EC point as an uncompressed point in DER. - * - * Return code compliant with OpenSSL. - * Not OpenSSL API. - * - * @param [in] group EC group point belongs to. - * @param [in] point EC point to encode. - * @param [out] out Buffer to encode into. May be NULL. - * @param [in, out] len On in, length of buffer in bytes. - * On out, length of encoding in bytes. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_ECPoint_i2d(const WOLFSSL_EC_GROUP *group, - const WOLFSSL_EC_POINT *point, unsigned char *out, unsigned int *len) -{ - int res = 1; - - WOLFSSL_ENTER("wolfSSL_ECPoint_i2d"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL) || (len == NULL)) { - WOLFSSL_MSG("wolfSSL_ECPoint_i2d NULL error"); - res = 0; - } - - /* Ensure points internals are set up. */ - if ((res == 1) && (ec_point_setup(point) != 1)) { - res = 0; - } - - /* Dump the point if encoding. */ - if ((res == 1) && (out != NULL)) { - wolfSSL_EC_POINT_dump("i2d p", point); - } - - if (res == 1) { - /* DER encode point in uncompressed format. */ - int ret = wc_ecc_export_point_der(group->curve_idx, - (ecc_point*)point->internal, out, len); - /* Check return. When out is NULL, return will be length only error. */ - if ((ret != MP_OKAY) && ((out != NULL) || - (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)))) { - WOLFSSL_MSG("wolfSSL_ECPoint_i2d wc_ecc_export_point_der failed"); - res = 0; - } - } - - return res; -} - -/* Decode the uncompressed point in DER into EC point. - * - * Return code compliant with OpenSSL. - * Not OpenSSL API. - * - * @param [in] in Buffer containing DER encoded point. - * @param [in] len Length of data in bytes. - * @param [in] group EC group associated with point. - * @param [in, out] point EC point to set data into. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_ECPoint_d2i(const unsigned char *in, unsigned int len, - const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *point) -{ - int ret = 1; - WOLFSSL_BIGNUM* x = NULL; - WOLFSSL_BIGNUM* y = NULL; - - WOLFSSL_ENTER("wolfSSL_ECPoint_d2i"); - - /* Validate parameters. */ - if ((in == NULL) || (group == NULL) || (point == NULL) || - (point->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_ECPoint_d2i NULL error"); - ret = 0; - } - - if (ret == 1) { - #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - /* Import point into internal EC point. */ - if (wc_ecc_import_point_der_ex(in, len, group->curve_idx, - (ecc_point*)point->internal, 0) != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_import_point_der_ex failed"); - ret = 0; - } - #else - /* ECC_POINT_UNCOMP is not defined CAVP self test so use magic number */ - if (in[0] == 0x04) { - /* Import point into internal EC point. */ - if (wc_ecc_import_point_der((unsigned char *)in, len, - group->curve_idx, (ecc_point*)point->internal) != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_import_point_der failed"); - ret = 0; - } - } - else { - WOLFSSL_MSG("Only uncompressed points supported with " - "HAVE_SELFTEST"); - ret = 0; - } - #endif - } - - if (ret == 1) - point->inSet = 1; - - /* Set new external point. */ - if (ret == 1 && ec_point_external_set(point) != 1) { - WOLFSSL_MSG("ec_point_external_set failed"); - ret = 0; - } - - if (ret == 1 && !wolfSSL_BN_is_one(point->Z)) { -#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) - x = wolfSSL_BN_new(); - y = wolfSSL_BN_new(); - if (x == NULL || y == NULL) - ret = 0; - - if (ret == 1 && wolfSSL_EC_POINT_get_affine_coordinates_GFp(group, - point, x, y, NULL) != 1) { - WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp failed"); - ret = 0; - } - - /* wolfSSL_EC_POINT_set_affine_coordinates_GFp check that the point is - * on the curve. */ - if (ret == 1 && wolfSSL_EC_POINT_set_affine_coordinates_GFp(group, - point, x, y, NULL) != 1) { - WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp failed"); - ret = 0; - } -#else - WOLFSSL_MSG("Importing non-affine point. This may cause issues in math " - "operations later on."); -#endif - } - - if (ret == 1) { - /* Dump new point. */ - wolfSSL_EC_POINT_dump("d2i p", point); - } - - wolfSSL_BN_free(x); - wolfSSL_BN_free(y); - - return ret; -} - -/* Encode point as octet string. - * - * HYBRID not supported. - * - * @param [in] group EC group that point belongs to. - * @param [in] point EC point to encode. - * @param [in] form Format of encoding. Valid values: - * POINT_CONVERSION_UNCOMPRESSED,POINT_CONVERSION_COMPRESSED - * @param [out] buf Buffer to write encoding into. - * @param [in] len Length of buffer. - * @param [in] ctx Context to use for BN operations. Unused. - * @return Length of encoded data on success. - * @return 0 on error. - */ -size_t wolfSSL_EC_POINT_point2oct(const WOLFSSL_EC_GROUP *group, - const WOLFSSL_EC_POINT *point, int form, byte *buf, size_t len, - WOLFSSL_BN_CTX *ctx) -{ - int err = 0; - word32 enc_len = (word32)len; -#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - int compressed = ((form == WC_POINT_CONVERSION_COMPRESSED) ? 1 : 0); -#endif /* !HAVE_SELFTEST */ - - WOLFSSL_ENTER("wolfSSL_EC_POINT_point2oct"); - - /* No BN operations performed. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL)) { - err = 1; - } - - /* Ensure points internals are set up. */ - if ((!err) && (ec_point_setup(point) != 1)) { - err = 1; - } - - /* Special case when point is infinity. */ - if ((!err) && wolfSSL_EC_POINT_is_at_infinity(group, point)) { - /* Encoding is a single octet: 0x00. */ - enc_len = 1; - if (buf != NULL) { - /* Check whether buffer has space. */ - if (len < 1) { - wolfSSL_ECerr(WOLFSSL_EC_F_EC_GFP_SIMPLE_POINT2OCT, BUFFER_E); - err = 1; - } - else { - /* Put in encoding of infinity. */ - buf[0] = 0x00; - } - } - } - /* Not infinity. */ - else if (!err) { - /* Validate format. */ - if (form != WC_POINT_CONVERSION_UNCOMPRESSED - #ifndef HAVE_SELFTEST - && form != WC_POINT_CONVERSION_COMPRESSED - #endif /* !HAVE_SELFTEST */ - ) { - WOLFSSL_MSG("Unsupported point form"); - err = 1; - } - - if (!err) { - int ret; - - #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - /* Encode as compressed or uncompressed. */ - ret = wc_ecc_export_point_der_ex(group->curve_idx, - (ecc_point*)point->internal, buf, &enc_len, compressed); - #else - /* Encode uncompressed point in DER format. */ - ret = wc_ecc_export_point_der(group->curve_idx, - (ecc_point*)point->internal, buf, &enc_len); - #endif /* !HAVE_SELFTEST */ - /* Check return. When buf is NULL, return will be length only - * error. - */ - if (ret != ((buf != NULL) ? MP_OKAY : WC_NO_ERR_TRACE(LENGTH_ONLY_E))) { - err = 1; - } - } - } - -#if defined(DEBUG_WOLFSSL) - if (!err) { - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_point2oct point", point); - WOLFSSL_MSG("\twolfSSL_EC_POINT_point2oct output:"); - WOLFSSL_BUFFER(buf, enc_len); - } -#endif - - /* On error, return encoding length of 0. */ - if (err) { - enc_len = 0; - } - return (size_t)enc_len; -} - - -/* Convert octet string to EC point. - * - * @param [in] group EC group. - * @param [in, out] point EC point to set data into. - * @param [in] buf Buffer holding octet string. - * @param [in] len Length of data in buffer in bytes. - * @param [in] ctx Context to use for BN operations. Unused. - */ -int wolfSSL_EC_POINT_oct2point(const WOLFSSL_EC_GROUP *group, - WOLFSSL_EC_POINT *point, const unsigned char *buf, size_t len, - WOLFSSL_BN_CTX *ctx) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point"); - - /* No BN operations performed. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL)) { - ret = 0; - } - else { - /* Decode DER encoding into EC point. */ - ret = wolfSSL_ECPoint_d2i((unsigned char*)buf, (unsigned int)len, group, - point); - } - - return ret; -} - -/* Convert an EC point to a single BN. - * - * @param [in] group EC group. - * @param [in] point EC point. - * @param [in] form Format of encoding. Valid values: - * WC_POINT_CONVERSION_UNCOMPRESSED, - * WC_POINT_CONVERSION_COMPRESSED. - * @param [in, out] bn BN to hold point value. - * When NULL a new BN is allocated otherwise this is - * returned on success. - * @param [in] ctx Context to use for BN operations. Unused. - * @return BN object with point as a value on success. - * @return NULL on error. - */ -WOLFSSL_BIGNUM *wolfSSL_EC_POINT_point2bn(const WOLFSSL_EC_GROUP* group, - const WOLFSSL_EC_POINT* point, int form, WOLFSSL_BIGNUM* bn, - WOLFSSL_BN_CTX* ctx) -{ - int err = 0; - size_t len = 0; - byte *buf = NULL; - WOLFSSL_BIGNUM *ret = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL)) { - err = 1; - } - - /* Calculate length of octet encoding. */ - if ((!err) && ((len = wolfSSL_EC_POINT_point2oct(group, point, form, NULL, - 0, ctx)) == 0)) { - err = 1; - } - /* Allocate buffer to hold octet encoding. */ - if ((!err) && ((buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER)) == - NULL)) { - WOLFSSL_MSG("malloc failed"); - err = 1; - } - /* Encode EC point as an octet string. */ - if ((!err) && (wolfSSL_EC_POINT_point2oct(group, point, form, buf, len, - ctx) != len)) { - err = 1; - } - /* Load BN with octet string data. */ - if (!err) { - ret = wolfSSL_BN_bin2bn(buf, (int)len, bn); - } - - /* Dispose of any allocated data. */ - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} - -#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) -/* Check if EC point is on the the curve defined by the EC group. - * - * @param [in] group EC group defining curve. - * @param [in] point EC point to check. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 when point is on curve. - * @return 0 when point is not on curve or error. - */ -int wolfSSL_EC_POINT_is_on_curve(const WOLFSSL_EC_GROUP *group, - const WOLFSSL_EC_POINT *point, WOLFSSL_BN_CTX *ctx) -{ - int err = 0; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_is_on_curve"); - - /* No BN operations performed. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL)) { - WOLFSSL_MSG("Invalid arguments"); - err = 1; - } - - /* Ensure internal EC point set. */ - if ((!err) && (!point->inSet) && ec_point_internal_set( - (WOLFSSL_EC_POINT*)point) != 1) { - WOLFSSL_MSG("ec_point_internal_set error"); - err = 1; - } - - /* Check point is on curve from group. */ - if ((!err) && (wc_ecc_point_is_on_curve((ecc_point*)point->internal, - group->curve_idx) != MP_OKAY)) { - err = 1; - } - - /* Return boolean of on curve. No error means on curve. */ - return !err; -} -#endif /* USE_ECC_B_PARAM && !HAVE_SELFTEST && !(FIPS_VERSION <= 2) */ - -#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) -/* Convert Jacobian ordinates to affine. - * - * @param [in] group EC group. - * @param [in] point EC point to get coordinates from. - * @return 1 on success. - * @return 0 on error. - */ -int ec_point_convert_to_affine(const WOLFSSL_EC_GROUP *group, - WOLFSSL_EC_POINT *point) -{ - int err = 0; - mp_digit mp = 0; - WC_DECLARE_VAR(modulus, mp_int, 1, 0); - - /* Allocate memory for curve's prime modulus. */ - WC_ALLOC_VAR_EX(modulus, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, err=1); - /* Initialize the MP integer. */ - if ((!err) && (mp_init(modulus) != MP_OKAY)) { - WOLFSSL_MSG("mp_init failed"); - err = 1; - } - - if (!err) { - /* Get the modulus from the hex string in the EC curve set. */ - if (mp_read_radix(modulus, ecc_sets[group->curve_idx].prime, - MP_RADIX_HEX) != MP_OKAY) { - WOLFSSL_MSG("mp_read_radix failed"); - err = 1; - } - /* Get Montgomery multiplier for the modulus as ordinates in - * Montgomery form. - */ - if ((!err) && (mp_montgomery_setup(modulus, &mp) != MP_OKAY)) { - WOLFSSL_MSG("mp_montgomery_setup failed"); - err = 1; - } - /* Map internal EC point from Jacobian to affine. */ - if ((!err) && (ecc_map((ecc_point*)point->internal, modulus, mp) != - MP_OKAY)) { - WOLFSSL_MSG("ecc_map failed"); - err = 1; - } - /* Set new ordinates into external EC point. */ - if ((!err) && (ec_point_external_set((WOLFSSL_EC_POINT *)point) != 1)) { - WOLFSSL_MSG("ec_point_external_set failed"); - err = 1; - } - - point->exSet = !err; - mp_clear(modulus); - } - - WC_FREE_VAR_EX(modulus, NULL, DYNAMIC_TYPE_BIGINT); - - return err; -} - -/* Get the affine coordinates of the EC point on a Prime curve. - * - * When z-ordinate is not one then coordinates are Jacobian and need to be - * converted to affine before storing in BNs. - * - * Return code compliant with OpenSSL. - * - * TODO: OpenSSL doesn't change point when Jacobian. Do the same? - * - * @param [in] group EC group. - * @param [in] point EC point to get coordinates from. - * @param [in, out] x BN to hold x-ordinate. - * @param [in, out] y BN to hold y-ordinate. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_get_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group, - const WOLFSSL_EC_POINT* point, WOLFSSL_BIGNUM* x, WOLFSSL_BIGNUM* y, - WOLFSSL_BN_CTX* ctx) -{ - int ret = 1; - - /* BN operations don't need context. */ - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_get_affine_coordinates_GFp"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL) || (point->internal == NULL) || - (x == NULL) || (y == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp NULL error"); - ret = 0; - } - /* Don't return point at infinity. */ - if ((ret == 1) && wolfSSL_EC_POINT_is_at_infinity(group, point)) { - ret = 0; - } - - /* Ensure internal EC point has values of external EC point. */ - if ((ret == 1) && (ec_point_setup(point) != 1)) { - ret = 0; - } - - /* Check whether ordinates are in Jacobian form. */ - if ((ret == 1) && (!wolfSSL_BN_is_one(point->Z))) { - /* Convert from Jacobian to affine. */ - if (ec_point_convert_to_affine(group, (WOLFSSL_EC_POINT*)point) == 1) { - ret = 0; - } - } - - /* Copy the externally set x and y ordinates. */ - if ((ret == 1) && (wolfSSL_BN_copy(x, point->X) == NULL)) { - ret = 0; - } - if ((ret == 1) && (wolfSSL_BN_copy(y, point->Y) == NULL)) { - ret = 0; - } - - return ret; -} -#endif /* !WOLFSSL_SP_MATH && !WOLF_CRYPTO_CB_ONLY_ECC */ - -/* Sets the affine coordinates that belong on a prime curve. - * - * @param [in] group EC group. - * @param [in, out] point EC point to set coordinates into. - * @param [in] x BN holding x-ordinate. - * @param [in] y BN holding y-ordinate. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_set_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group, - WOLFSSL_EC_POINT* point, const WOLFSSL_BIGNUM* x, const WOLFSSL_BIGNUM* y, - WOLFSSL_BN_CTX* ctx) -{ - int ret = 1; - - /* BN operations don't need context. */ - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_set_affine_coordinates_GFp"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL) || (point->internal == NULL) || - (x == NULL) || (y == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp NULL error"); - ret = 0; - } - - /* Ensure we have a object for x-ordinate. */ - if ((ret == 1) && (point->X == NULL) && - ((point->X = wolfSSL_BN_new()) == NULL)) { - WOLFSSL_MSG("wolfSSL_BN_new failed"); - ret = 0; - } - /* Ensure we have a object for y-ordinate. */ - if ((ret == 1) && (point->Y == NULL) && - ((point->Y = wolfSSL_BN_new()) == NULL)) { - WOLFSSL_MSG("wolfSSL_BN_new failed"); - ret = 0; - } - /* Ensure we have a object for z-ordinate. */ - if ((ret == 1) && (point->Z == NULL) && - ((point->Z = wolfSSL_BN_new()) == NULL)) { - WOLFSSL_MSG("wolfSSL_BN_new failed"); - ret = 0; - } - - /* Copy the x-ordinate. */ - if ((ret == 1) && ((wolfSSL_BN_copy(point->X, x)) == NULL)) { - WOLFSSL_MSG("wolfSSL_BN_copy failed"); - ret = 0; - } - /* Copy the y-ordinate. */ - if ((ret == 1) && ((wolfSSL_BN_copy(point->Y, y)) == NULL)) { - WOLFSSL_MSG("wolfSSL_BN_copy failed"); - ret = 0; - } - /* z-ordinate is one for affine coordinates. */ - if ((ret == 1) && ((wolfSSL_BN_one(point->Z)) == 0)) { - WOLFSSL_MSG("wolfSSL_BN_one failed"); - ret = 0; - } - - /* Copy the new point data to internal object. */ - if ((ret == 1) && (ec_point_internal_set((WOLFSSL_EC_POINT *)point) != 1)) { - WOLFSSL_MSG("ec_point_internal_set failed"); - ret = 0; - } - -#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - /* Check that the point is valid. */ - if ((ret == 1) && (wolfSSL_EC_POINT_is_on_curve(group, - (WOLFSSL_EC_POINT *)point, ctx) != 1)) { - WOLFSSL_MSG("EC_POINT_is_on_curve failed"); - ret = 0; - } -#endif - - return ret; -} - -#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \ - !defined(HAVE_SELFTEST) && !defined(WOLFSSL_SP_MATH) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) -/* Add two points on the same together. - * - * @param [in] curveIdx Index of curve in ecc_set. - * @param [out] r Result point. - * @param [in] p1 First point to add. - * @param [in] p2 Second point to add. - * @return 1 on success. - * @return 0 on error. - */ -static int wolfssl_ec_point_add(int curveIdx, ecc_point* r, ecc_point* p1, - ecc_point* p2) -{ - int ret = 1; -#ifdef WOLFSSL_SMALL_STACK - mp_int* a = NULL; - mp_int* prime = NULL; - mp_int* mu = NULL; -#else - mp_int a[1]; - mp_int prime[1]; - mp_int mu[1]; -#endif - mp_digit mp = 0; - ecc_point* montP1 = NULL; - ecc_point* montP2 = NULL; - -#ifdef WOLFSSL_SMALL_STACK - if (ret == 1) { - /* Allocate memory for curve parameter: a. */ - a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); - if (a == NULL) { - WOLFSSL_MSG("Failed to allocate memory for mp_int a"); - ret = 0; - } - } - if (ret == 1) { - /* Allocate memory for curve parameter: prime. */ - prime = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); - if (prime == NULL) { - WOLFSSL_MSG("Failed to allocate memory for mp_int prime"); - ret = 0; - } - } - if (ret == 1) { - /* Allocate memory for mu (Montgomery normalizer). */ - mu = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); - if (mu == NULL) { - WOLFSSL_MSG("Failed to allocate memory for mp_int mu"); - ret = 0; - } - } - if (ret == 1) { - /* Zero out all MP int data in case initialization fails. */ - XMEMSET(a, 0, sizeof(mp_int)); - XMEMSET(prime, 0, sizeof(mp_int)); - XMEMSET(mu, 0, sizeof(mp_int)); - } -#endif - - /* Initialize the MP ints. */ - if ((ret == 1) && (mp_init_multi(prime, a, mu, NULL, NULL, NULL) != - MP_OKAY)) { - WOLFSSL_MSG("mp_init_multi error"); - ret = 0; - } - - /* Read the curve parameter: a. */ - if ((ret == 1) && (mp_read_radix(a, ecc_sets[curveIdx].Af, MP_RADIX_HEX) != - MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix a error"); - ret = 0; - } - - /* Read the curve parameter: prime. */ - if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix prime error"); - ret = 0; - } - - /* Calculate the Montgomery product. */ - if ((ret == 1) && (mp_montgomery_setup(prime, &mp) != MP_OKAY)) { - WOLFSSL_MSG("mp_montgomery_setup nqm error"); - ret = 0; - } - - /* TODO: use the heap filed of one of the points? */ - /* Allocate new points to hold the Montgomery form values. */ - if ((ret == 1) && (((montP1 = wc_ecc_new_point_h(NULL)) == NULL) || - ((montP2 = wc_ecc_new_point_h(NULL)) == NULL))) { - WOLFSSL_MSG("wc_ecc_new_point_h nqm error"); - ret = 0; - } - - /* Calculate the Montgomery normalizer. */ - if ((ret == 1) && (mp_montgomery_calc_normalization(mu, prime) != - MP_OKAY)) { - WOLFSSL_MSG("mp_montgomery_calc_normalization error"); - ret = 0; - } - - /* Convert to Montgomery form. */ - if ((ret == 1) && (mp_cmp_d(mu, 1) == MP_EQ)) { - /* Copy the points if the normalizer is 1. */ - if ((wc_ecc_copy_point(p1, montP1) != MP_OKAY) || - (wc_ecc_copy_point(p2, montP2) != MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_copy_point error"); - ret = 0; - } - } - else if (ret == 1) { - /* Multiply each ordinate by the Montgomery normalizer. */ - if ((mp_mulmod(p1->x, mu, prime, montP1->x) != MP_OKAY) || - (mp_mulmod(p1->y, mu, prime, montP1->y) != MP_OKAY) || - (mp_mulmod(p1->z, mu, prime, montP1->z) != MP_OKAY)) { - WOLFSSL_MSG("mp_mulmod error"); - ret = 0; - } - /* Multiply each ordinate by the Montgomery normalizer. */ - if ((mp_mulmod(p2->x, mu, prime, montP2->x) != MP_OKAY) || - (mp_mulmod(p2->y, mu, prime, montP2->y) != MP_OKAY) || - (mp_mulmod(p2->z, mu, prime, montP2->z) != MP_OKAY)) { - WOLFSSL_MSG("mp_mulmod error"); - ret = 0; - } - } - - /* Perform point addition with internal EC point objects - Jacobian form - * result. - */ - if ((ret == 1) && (ecc_projective_add_point(montP1, montP2, r, a, prime, - mp) != MP_OKAY)) { - WOLFSSL_MSG("ecc_projective_add_point error"); - ret = 0; - } - - /* Map point back to affine coordinates. Converts from Montogomery form. */ - if ((ret == 1) && (ecc_map(r, prime, mp) != MP_OKAY)) { - WOLFSSL_MSG("ecc_map error"); - ret = 0; - } - - /* Dispose of allocated memory. */ - mp_clear(a); - mp_clear(prime); - mp_clear(mu); - wc_ecc_del_point_h(montP1, NULL); - wc_ecc_del_point_h(montP2, NULL); - WC_FREE_VAR_EX(a, NULL, DYNAMIC_TYPE_BIGINT); - WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); - WC_FREE_VAR_EX(mu, NULL, DYNAMIC_TYPE_BIGINT); - return ret; -} - -/* Add two points on the same curve together. - * - * @param [in] group EC group. - * @param [out] r EC point that is result of point addition. - * @param [in] p1 First EC point to add. - * @param [in] p2 Second EC point to add. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_add(const WOLFSSL_EC_GROUP* group, WOLFSSL_EC_POINT* r, - const WOLFSSL_EC_POINT* p1, const WOLFSSL_EC_POINT* p2, WOLFSSL_BN_CTX* ctx) -{ - int ret = 1; - - /* No BN operations performed. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (r == NULL) || (p1 == NULL) || (p2 == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_add error"); - ret = 0; - } - - /* Ensure the internal objects of the EC points are setup. */ - if ((ret == 1) && ((ec_point_setup(r) != 1) || (ec_point_setup(p1) != 1) || - (ec_point_setup(p2) != 1))) { - WOLFSSL_MSG("ec_point_setup error"); - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - int nid = wolfSSL_EC_GROUP_get_curve_name(group); - const char* curve = wolfSSL_OBJ_nid2ln(nid); - const char* nistName = wolfSSL_EC_curve_nid2nist(nid); - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add p1", p1); - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add p2", p2); - if (curve != NULL) - WOLFSSL_MSG_EX("curve name: %s", curve); - if (nistName != NULL) - WOLFSSL_MSG_EX("nist curve name: %s", nistName); - } -#endif - - if (ret == 1) { - /* Add points using wolfCrypt objects. */ - ret = wolfssl_ec_point_add(group->curve_idx, (ecc_point*)r->internal, - (ecc_point*)p1->internal, (ecc_point*)p2->internal); - } - - /* Copy internal EC point values out to external EC point. */ - if ((ret == 1) && (ec_point_external_set(r) != 1)) { - WOLFSSL_MSG("ec_point_external_set error"); - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add result", r); - } -#endif - - return ret; -} - -/* Sum the scalar multiplications of the base point and n, and q and m. - * - * r = base point * n + q * m - * - * @param [out] r EC point that is result of operation. - * @param [in] b Base point of curve. - * @param [in] n Scalar to multiply by base point. - * @param [in] q EC point to be scalar multiplied. - * @param [in] m Scalar to multiply q by. - * @param [in] a Parameter A of curve. - * @param [in] prime Prime (modulus) of curve. - * @return 1 on success. - * @return 0 on error. - */ -static int ec_mul2add(ecc_point* r, ecc_point* b, mp_int* n, ecc_point* q, - mp_int* m, mp_int* a, mp_int* prime) -{ - int ret = 1; -#if defined(ECC_SHAMIR) && !defined(WOLFSSL_KCAPI_ECC) - if (ecc_mul2add(b, n, q, m, r, a, prime, NULL) != MP_OKAY) { - WOLFSSL_MSG("ecc_mul2add error"); - ret = 0; - } -#else - ecc_point* tmp = NULL; - mp_digit mp = 0; - - /* Calculate Montgomery product. */ - if (mp_montgomery_setup(prime, &mp) != MP_OKAY) { - WOLFSSL_MSG("mp_montgomery_setup nqm error"); - ret = 0; - } - /* Create temporary point to hold: q * m */ - if ((ret == 1) && ((tmp = wc_ecc_new_point()) == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_new nqm error"); - ret = 0; - } - /* r = base point * n */ - if ((ret == 1) && (wc_ecc_mulmod(n, b, r, a, prime, 0) != - MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_mulmod nqm error"); - ret = 0; - } - /* tmp = q * m */ - if ((ret == 1) && (wc_ecc_mulmod(m, q, tmp, a, prime, 0) != MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_mulmod nqm error"); - ret = 0; - } - /* r = r + tmp */ - if ((ret == 1) && (ecc_projective_add_point(tmp, r, r, a, prime, mp) != - MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_mulmod nqm error"); - ret = 0; - } - /* Map point back to affine coordinates. Converts from Montogomery - * form. */ - if ((ret == 1) && (ecc_map(r, prime, mp) != MP_OKAY)) { - WOLFSSL_MSG("ecc_map nqm error"); - ret = 0; - } - - /* Dispose of allocated temporary point. */ - wc_ecc_del_point(tmp); -#endif - - return ret; -} - -/* Sum the scalar multiplications of the base point and n, and q and m. - * - * r = base point * n + q * m - * - * @param [in] curveIdx Index of curve in ecc_set. - * @param [out] r EC point that is result of operation. - * @param [in] n Scalar to multiply by base point. May be NULL. - * @param [in] q EC point to be scalar multiplied. May be NULL. - * @param [in] m Scalar to multiply q by. May be NULL. - * @return 1 on success. - * @return 0 on error. - */ -static int wolfssl_ec_point_mul(int curveIdx, ecc_point* r, mp_int* n, - ecc_point* q, mp_int* m) -{ - int ret = 1; -#ifdef WOLFSSL_SMALL_STACK - mp_int* a = NULL; - mp_int* prime = NULL; -#else - mp_int a[1], prime[1]; -#endif - -#ifdef WOLFSSL_SMALL_STACK - /* Allocate MP integer for curve parameter: a. */ - a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); - if (a == NULL) { - ret = 0; - } - if (ret == 1) { - /* Allocate MP integer for curve parameter: prime. */ - prime = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); - if (prime == NULL) { - ret = 0; - } - } -#endif - - /* Initialize the MP ints. */ - if ((ret == 1) && (mp_init_multi(prime, a, NULL, NULL, NULL, NULL) != - MP_OKAY)) { - WOLFSSL_MSG("mp_init_multi error"); - ret = 0; - } - - /* Read the curve parameter: prime. */ - if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix prime error"); - ret = 0; - } - - /* Read the curve parameter: a. */ - if ((ret == 1) && (mp_read_radix(a, ecc_sets[curveIdx].Af, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix a error"); - ret = 0; - } - - if ((ret == 1) && (n != NULL)) { - /* Get generator - base point. */ - #if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) - if ((ret == 1) && (wc_ecc_get_generator(r, curveIdx) != MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_get_generator error"); - ret = 0; - } - #else - /* wc_ecc_get_generator is not defined in the FIPS v2 module. */ - /* Read generator (base point) x-ordinate. */ - if ((ret == 1) && (mp_read_radix(r->x, ecc_sets[curveIdx].Gx, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix Gx error"); - ret = 0; - } - /* Read generator (base point) y-ordinate. */ - if ((ret == 1) && (mp_read_radix(r->y, ecc_sets[curveIdx].Gy, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix Gy error"); - ret = 0; - } - /* z-ordinate is one as point is affine. */ - if ((ret == 1) && (mp_set(r->z, 1) != MP_OKAY)) { - WOLFSSL_MSG("mp_set Gz error"); - ret = 0; - } - #endif /* NOPT_FIPS_VERSION == 2 */ - } - - if ((ret == 1) && (n != NULL) && (q != NULL) && (m != NULL)) { - /* r = base point * n + q * m */ - ret = ec_mul2add(r, r, n, q, m, a, prime); - } - /* Not all values present, see if we are only doing base point * n. */ - else if ((ret == 1) && (n != NULL)) { - /* r = base point * n */ - if (wc_ecc_mulmod(n, r, r, a, prime, 1) != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_mulmod gn error"); - ret = 0; - } - } - /* Not all values present, see if we are only doing q * m. */ - else if ((ret == 1) && (q != NULL) && (m != NULL)) { - /* r = q * m */ - if (wc_ecc_mulmod(m, q, r, a, prime, 1) != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_mulmod qm error"); - ret = 0; - } - } - /* No values to use. */ - else if (ret == 1) { - /* Set result to infinity as no values passed in. */ - mp_zero(r->x); - mp_zero(r->y); - mp_zero(r->z); - } - - mp_clear(a); - mp_clear(prime); - WC_FREE_VAR_EX(a, NULL, DYNAMIC_TYPE_BIGINT); - WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); - return ret; -} - -/* Sum the scalar multiplications of the base point and n, and q and m. - * - * r = base point * n + q * m - * - * Return code compliant with OpenSSL. - * - * @param [in] group EC group. - * @param [out] r EC point that is result of operation. - * @param [in] n Scalar to multiply by base point. May be NULL. - * @param [in] q EC point to be scalar multiplied. May be NULL. - * @param [in] m Scalar to multiply q by. May be NULL. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_mul(const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *r, - const WOLFSSL_BIGNUM *n, const WOLFSSL_EC_POINT *q, const WOLFSSL_BIGNUM *m, - WOLFSSL_BN_CTX *ctx) -{ - int ret = 1; - - /* No BN operations performed. */ - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_mul"); - - /* Validate parameters. */ - if ((group == NULL) || (r == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_mul NULL error"); - ret = 0; - } - - /* Ensure the internal representation of the EC point q is setup. */ - if ((ret == 1) && (q != NULL) && (ec_point_setup(q) != 1)) { - WOLFSSL_MSG("ec_point_setup error"); - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - int nid = wolfSSL_EC_GROUP_get_curve_name(group); - const char* curve = wolfSSL_OBJ_nid2ln(nid); - const char* nistName = wolfSSL_EC_curve_nid2nist(nid); - char* num; - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_mul input q", q); - num = wolfSSL_BN_bn2hex(n); - WOLFSSL_MSG_EX("\tn = %s", num); - XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); - num = wolfSSL_BN_bn2hex(m); - WOLFSSL_MSG_EX("\tm = %s", num); - XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); - if (curve != NULL) - WOLFSSL_MSG_EX("curve name: %s", curve); - if (nistName != NULL) - WOLFSSL_MSG_EX("nist curve name: %s", nistName); - } -#endif - - if (ret == 1) { - mp_int* ni = (n != NULL) ? (mp_int*)n->internal : NULL; - ecc_point* qi = (q != NULL) ? (ecc_point*)q->internal : NULL; - mp_int* mi = (m != NULL) ? (mp_int*)m->internal : NULL; - - /* Perform multiplication with wolfCrypt objects. */ - ret = wolfssl_ec_point_mul(group->curve_idx, (ecc_point*)r->internal, - ni, qi, mi); - } - - /* Only on success is the internal point guaranteed to be set. */ - if (r != NULL) { - r->inSet = (ret == 1); - } - /* Copy internal EC point values out to external EC point. */ - if ((ret == 1) && (ec_point_external_set(r) != 1)) { - WOLFSSL_MSG("ec_point_external_set error"); - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_mul result", r); - } -#endif - - return ret; -} -#endif /* !WOLFSSL_ATECC508A && !WOLFSSL_ATECC608A && !HAVE_SELFTEST && - * !WOLFSSL_SP_MATH */ - -/* Invert the point on the curve. - * (x, y) -> (x, -y) = (x, (prime - y) % prime) - * - * @param [in] curveIdx Index of curve in ecc_set. - * @param [in, out] point EC point to invert. - * @return 1 on success. - * @return 0 on error. - */ -static int wolfssl_ec_point_invert(int curveIdx, ecc_point* point) -{ - int ret = 1; - WC_DECLARE_VAR(prime, mp_int, 1, 0); - - /* Allocate memory for an MP int to hold the prime of the curve. */ - WC_ALLOC_VAR_EX(prime, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, ret=0); - - /* Initialize MP int. */ - if ((ret == 1) && (mp_init(prime) != MP_OKAY)) { - WOLFSSL_MSG("mp_init_multi error"); - ret = 0; - } - - /* Read the curve parameter: prime. */ - if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix prime error"); - ret = 0; - } - - /* y = (prime - y) mod prime. */ - if ((ret == 1) && (!mp_iszero(point->y)) && (mp_sub(prime, point->y, - point->y) != MP_OKAY)) { - WOLFSSL_MSG("mp_sub error"); - ret = 0; - } - - /* Dispose of memory associated with MP. */ - mp_free(prime); - WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); - return ret; -} - -/* Invert the point on the curve. - * (x, y) -> (x, -y) = (x, (prime - y) % prime) - * - * @param [in] group EC group. - * @param [in, out] point EC point to invert. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_invert(const WOLFSSL_EC_GROUP *group, - WOLFSSL_EC_POINT *point, WOLFSSL_BN_CTX *ctx) -{ - int ret = 1; - - /* No BN operations performed. */ - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_invert"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL) || (point->internal == NULL)) { - ret = 0; - } - - /* Ensure internal representation of point is setup. */ - if ((ret == 1) && (ec_point_setup(point) != 1)) { - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - int nid = wolfSSL_EC_GROUP_get_curve_name(group); - const char* curve = wolfSSL_OBJ_nid2ln(nid); - const char* nistName = wolfSSL_EC_curve_nid2nist(nid); - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_invert input", point); - if (curve != NULL) - WOLFSSL_MSG_EX("curve name: %s", curve); - if (nistName != NULL) - WOLFSSL_MSG_EX("nist curve name: %s", nistName); - - } -#endif - - if (ret == 1 && !wolfSSL_BN_is_one(point->Z)) { -#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) - if (ec_point_convert_to_affine(group, point) != 0) - ret = 0; -#else - WOLFSSL_MSG("wolfSSL_EC_POINT_invert called on non-affine point"); - ret = 0; -#endif - } - - if (ret == 1) { - /* Perform inversion using wolfCrypt objects. */ - ret = wolfssl_ec_point_invert(group->curve_idx, - (ecc_point*)point->internal); - } - - /* Set the external EC point representation based on internal. */ - if ((ret == 1) && (ec_point_external_set(point) != 1)) { - WOLFSSL_MSG("ec_point_external_set error"); - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_invert result", point); - } -#endif - - return ret; -} - -#ifdef WOLFSSL_EC_POINT_CMP_JACOBIAN -/* Compare two points on a the same curve. - * - * (Ax, Ay, Az) => (Ax / (Az ^ 2), Ay / (Az ^ 3)) - * (Bx, By, Bz) => (Bx / (Bz ^ 2), By / (Bz ^ 3)) - * When equal: - * (Ax / (Az ^ 2), Ay / (Az ^ 3)) = (Bx / (Bz ^ 2), By / (Bz ^ 3)) - * => (Ax * (Bz ^ 2), Ay * (Bz ^ 3)) = (Bx * (Az ^ 2), By * (Az ^ 3)) - * - * @param [in] group EC group. - * @param [in] a EC point to compare. - * @param [in] b EC point to compare. - * @return 0 when equal. - * @return 1 when different. - * @return -1 on error. - */ -static int ec_point_cmp_jacobian(const WOLFSSL_EC_GROUP* group, - const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, WOLFSSL_BN_CTX *ctx) -{ - int ret = 0; - BIGNUM* at = BN_new(); - BIGNUM* bt = BN_new(); - BIGNUM* az = BN_new(); - BIGNUM* bz = BN_new(); - BIGNUM* mod = BN_new(); - - /* Check that the big numbers were allocated. */ - if ((at == NULL) || (bt == NULL) || (az == NULL) || (bz == NULL) || - (mod == NULL)) { - ret = WOLFSSL_FATAL_ERROR; - } - /* Get the modulus for the curve. */ - if ((ret == 0) && - (BN_hex2bn(&mod, ecc_sets[group->curve_idx].prime) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - if (ret == 0) { - /* bt = Bx * (Az ^ 2). When Az is one then just copy. */ - if (BN_is_one(a->Z)) { - if (BN_copy(bt, b->X) == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* az = Az ^ 2 */ - else if ((BN_mod_mul(az, a->Z, a->Z, mod, ctx) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - /* bt = Bx * az = Bx * (Az ^ 2) */ - else if (BN_mod_mul(bt, b->X, az, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 0) { - /* at = Ax * (Bz ^ 2). When Bz is one then just copy. */ - if (BN_is_one(b->Z)) { - if (BN_copy(at, a->X) == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* bz = Bz ^ 2 */ - else if (BN_mod_mul(bz, b->Z, b->Z, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - /* at = Ax * bz = Ax * (Bz ^ 2) */ - else if (BN_mod_mul(at, a->X, bz, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* Compare x-ordinates. */ - if ((ret == 0) && (BN_cmp(at, bt) != 0)) { - ret = 1; - } - if (ret == 0) { - /* bt = By * (Az ^ 3). When Az is one then just copy. */ - if (BN_is_one(a->Z)) { - if (BN_copy(bt, b->Y) == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* az = az * Az = Az ^ 3 */ - else if ((BN_mod_mul(az, az, a->Z, mod, ctx) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - /* bt = By * az = By * (Az ^ 3) */ - else if (BN_mod_mul(bt, b->Y, az, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 0) { - /* at = Ay * (Bz ^ 3). When Bz is one then just copy. */ - if (BN_is_one(b->Z)) { - if (BN_copy(at, a->Y) == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* bz = bz * Bz = Bz ^ 3 */ - else if (BN_mod_mul(bz, bz, b->Z, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - /* at = Ay * bz = Ay * (Bz ^ 3) */ - else if (BN_mod_mul(at, a->Y, bz, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* Compare y-ordinates. */ - if ((ret == 0) && (BN_cmp(at, bt) != 0)) { - ret = 1; - } - - BN_free(mod); - BN_free(bz); - BN_free(az); - BN_free(bt); - BN_free(at); - return ret; -} -#endif - -/* Compare two points on a the same curve. - * - * Return code compliant with OpenSSL. - * - * @param [in] group EC group. - * @param [in] a EC point to compare. - * @param [in] b EC point to compare. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 0 when equal. - * @return 1 when different. - * @return -1 on error. - */ -int wolfSSL_EC_POINT_cmp(const WOLFSSL_EC_GROUP *group, - const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, WOLFSSL_BN_CTX *ctx) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_cmp"); - - /* Validate parameters. */ - if ((group == NULL) || (a == NULL) || (a->internal == NULL) || - (b == NULL) || (b->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_cmp Bad arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - if (ret != -1) { - #ifdef WOLFSSL_EC_POINT_CMP_JACOBIAN - /* If same Z ordinate then no need to convert to affine. */ - if (BN_cmp(a->Z, b->Z) == 0) { - /* Compare */ - ret = ((BN_cmp(a->X, b->X) != 0) || (BN_cmp(a->Y, b->Y) != 0)); - } - else { - ret = ec_point_cmp_jacobian(group, a, b, ctx); - } - #else - /* No BN operations performed. */ - (void)ctx; - - ret = (wc_ecc_cmp_point((ecc_point*)a->internal, - (ecc_point*)b->internal) != MP_EQ); - #endif - } - - return ret; -} - -/* Copy EC point. - * - * @param [out] dest EC point to copy into. - * @param [in] src EC point to copy. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_copy(WOLFSSL_EC_POINT *dest, const WOLFSSL_EC_POINT *src) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_copy"); - - /* Validate parameters. */ - if ((dest == NULL) || (src == NULL)) { - ret = 0; - } - - /* Ensure internal EC point of src is setup. */ - if ((ret == 1) && (ec_point_setup(src) != 1)) { - ret = 0; - } - - /* Copy internal EC points. */ - if ((ret == 1) && (wc_ecc_copy_point((ecc_point*)src->internal, - (ecc_point*)dest->internal) != MP_OKAY)) { - ret = 0; - } - - if (ret == 1) { - /* Destinatation internal point is set. */ - dest->inSet = 1; - - /* Set the external EC point of dest based on internal. */ - if (ec_point_external_set(dest) != 1) { - ret = 0; - } - } - - return ret; -} - -/* Checks whether point is at infinity. - * - * Return code compliant with OpenSSL. - * - * @param [in] group EC group. - * @param [in] point EC point to check. - * @return 1 when at infinity. - * @return 0 when not at infinity. - */ -int wolfSSL_EC_POINT_is_at_infinity(const WOLFSSL_EC_GROUP *group, - const WOLFSSL_EC_POINT *point) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_is_at_infinity"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL) || (point->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_is_at_infinity NULL error"); - ret = 0; - } - - /* Ensure internal EC point is setup. */ - if ((ret == 1) && (ec_point_setup(point) != 1)) { - ret = 0; - } - if (ret == 1) { - #ifndef WOLF_CRYPTO_CB_ONLY_ECC - /* Check for infinity. */ - ret = wc_ecc_point_is_at_infinity((ecc_point*)point->internal); - if (ret < 0) { - WOLFSSL_MSG("ecc_point_is_at_infinity failure"); - /* Error return is 0 by OpenSSL. */ - ret = 0; - } - #else - WOLFSSL_MSG("ecc_point_is_at_infinitiy compiled out"); - ret = 0; - #endif - } - - return ret; -} - -#endif /* OPENSSL_EXTRA */ - -/* End EC_POINT */ - -/* Start EC_KEY */ - -#ifdef OPENSSL_EXTRA - -/* - * EC key constructor/deconstructor APIs - */ - -/* Allocate a new EC key. - * - * Not OpenSSL API. - * - * @param [in] heap Heap hint for dynamic memory allocation. - * @param [in] devId Device identifier value. - * @return New, allocated EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_ex(void* heap, int devId) -{ - WOLFSSL_EC_KEY *key = NULL; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_new"); - - /* Allocate memory for EC key. */ - key = (WOLFSSL_EC_KEY*)XMALLOC(sizeof(WOLFSSL_EC_KEY), heap, - DYNAMIC_TYPE_ECC); - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_KEY failure"); - err = 1; - } - if (!err) { - /* Reset all fields to 0. */ - XMEMSET(key, 0, sizeof(WOLFSSL_EC_KEY)); - /* Cache heap hint. */ - key->heap = heap; - /* Initialize fields to defaults. */ - key->form = WC_POINT_CONVERSION_UNCOMPRESSED; - - /* Initialize reference count. */ - wolfSSL_RefInit(&key->ref, &err); -#ifdef WOLFSSL_REFCNT_ERROR_RETURN - } - if (!err) { -#endif - /* Allocate memory for internal EC key representation. */ - key->internal = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, - DYNAMIC_TYPE_ECC); - if (key->internal == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc ecc key failure"); - err = 1; - } - } - if (!err) { - /* Initialize wolfCrypt EC key. */ - if (wc_ecc_init_ex((ecc_key*)key->internal, heap, devId) != 0) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new init ecc key failure"); - err = 1; - } - } - - if (!err) { - /* Group unknown at creation */ - key->group = wolfSSL_EC_GROUP_new_by_curve_name(WC_NID_undef); - if (key->group == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_GROUP failure"); - err = 1; - } - } - - if (!err) { - /* Allocate a point as public key. */ - key->pub_key = wolfSSL_EC_POINT_new(key->group); - if (key->pub_key == NULL) { - WOLFSSL_MSG("wolfSSL_EC_POINT_new failure"); - err = 1; - } - } - - if (!err) { - /* Allocate a BN as private key. */ - key->priv_key = wolfSSL_BN_new(); - if (key->priv_key == NULL) { - WOLFSSL_MSG("wolfSSL_BN_new failure"); - err = 1; - } - } - - if (err) { - /* Dispose of EC key on error. */ - wolfSSL_EC_KEY_free(key); - key = NULL; - } - /* Return new EC key object. */ - return key; -} - -/* Allocate a new EC key. - * - * @return New, allocated EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new(void) -{ - return wolfSSL_EC_KEY_new_ex(NULL, INVALID_DEVID); -} - -/* Create new EC key with the group having the specified numeric ID. - * - * @param [in] nid Numeric ID. - * @return New, allocated EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_by_curve_name(int nid) -{ - WOLFSSL_EC_KEY *key; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_new_by_curve_name"); - - /* Allocate empty, EC key. */ - key = wolfSSL_EC_KEY_new(); - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new failure"); - err = 1; - } - - if (!err) { - /* Set group to be nid. */ - ec_group_set_nid(key->group, nid); - if (key->group->curve_idx == -1) { - wolfSSL_EC_KEY_free(key); - key = NULL; - } - } - - /* Return the new EC key object. */ - return key; -} - -/* Dispose of the EC key and allocated data. - * - * Cannot use key after this call. - * - * @param [in] key EC key to free. - */ -void wolfSSL_EC_KEY_free(WOLFSSL_EC_KEY *key) -{ - int doFree = 0; - int err; - - (void)err; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_free"); - - if (key != NULL) { - void* heap = key->heap; - - /* Decrement reference count. */ - wolfSSL_RefDec(&key->ref, &doFree, &err); - if (doFree) { - /* Dispose of allocated reference counting data. */ - wolfSSL_RefFree(&key->ref); - - /* Dispose of private key. */ - wolfSSL_BN_free(key->priv_key); - wolfSSL_EC_POINT_free(key->pub_key); - wolfSSL_EC_GROUP_free(key->group); - if (key->internal != NULL) { - /* Dispose of wolfCrypt representation of EC key. */ - wc_ecc_free((ecc_key*)key->internal); - XFREE(key->internal, heap, DYNAMIC_TYPE_ECC); - } - - /* Set back to NULLs for safety. */ - ForceZero(key, sizeof(*key)); - - /* Dispose of the memory associated with the EC key. */ - XFREE(key, heap, DYNAMIC_TYPE_ECC); - (void)heap; - } - } -} - -/* Increments ref count of EC key. - * - * @param [in, out] key EC key. - * @return 1 on success - * @return 0 on error - */ -int wolfSSL_EC_KEY_up_ref(WOLFSSL_EC_KEY* key) -{ - int err = 1; - - if (key != NULL) { - wolfSSL_RefInc(&key->ref, &err); - } - - return !err; -} - -#ifndef NO_CERTS - -#if defined(OPENSSL_ALL) -/* Copy the internal, wolfCrypt EC key. - * - * @param [in, out] dst Destination wolfCrypt EC key. - * @param [in] src Source wolfCrypt EC key. - * @return 0 on success. - * @return Negative on error. - */ -static int wolfssl_ec_key_int_copy(ecc_key* dst, const ecc_key* src) -{ - int ret; - - /* Copy public key. */ -#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) - ret = wc_ecc_copy_point(&src->pubkey, &dst->pubkey); -#else - ret = wc_ecc_copy_point((ecc_point*)&src->pubkey, &dst->pubkey); -#endif - if (ret != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_copy_point error"); - } - - if (ret == 0) { - /* Copy private key. */ - ret = mp_copy(wc_ecc_key_get_priv((ecc_key*)src), - wc_ecc_key_get_priv(dst)); - if (ret != MP_OKAY) { - WOLFSSL_MSG("mp_copy error"); - } - } - - if (ret == 0) { - /* Copy domain parameters. */ - if (src->dp) { - ret = wc_ecc_set_curve(dst, 0, src->dp->id); - if (ret != 0) { - WOLFSSL_MSG("wc_ecc_set_curve error"); - } - } - } - - if (ret == 0) { - /* Copy the other components. */ - dst->type = src->type; - dst->idx = src->idx; - dst->state = src->state; - dst->flags = src->flags; - } - - return ret; -} - -/* Copies ecc_key into new WOLFSSL_EC_KEY object - * - * Copies the internal representation as well. - * - * @param [in] src EC key to duplicate. - * - * @return EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY *wolfSSL_EC_KEY_dup(const WOLFSSL_EC_KEY *src) -{ - int err = 0; - WOLFSSL_EC_KEY* newKey = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_dup"); - - /* Validate EC key. */ - if ((src == NULL) || (src->internal == NULL) || (src->group == NULL) || - (src->pub_key == NULL) || (src->priv_key == NULL)) { - WOLFSSL_MSG("src NULL error"); - err = 1; - } - - if (!err) { - /* Create a new, empty key. */ - newKey = wolfSSL_EC_KEY_new(); - if (newKey == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); - err = 1; - } - } - - if (!err) { - /* Copy internal EC key. */ - if (wolfssl_ec_key_int_copy((ecc_key*)newKey->internal, - (ecc_key*)src->internal) != 0) { - WOLFSSL_MSG("Copying internal EC key error"); - err = 1; - } - } - if (!err) { - /* Internal key set. */ - newKey->inSet = 1; - - /* Copy group */ - err = wolfssl_ec_group_copy(newKey->group, src->group); - } - /* Copy public key. */ - if ((!err) && (wolfSSL_EC_POINT_copy(newKey->pub_key, src->pub_key) != 1)) { - WOLFSSL_MSG("Copying EC public key error"); - err = 1; - } - - if (!err) { - /* Set header size of private key in PKCS#8 format.*/ - newKey->pkcs8HeaderSz = src->pkcs8HeaderSz; - - /* Copy private key. */ - if (wolfSSL_BN_copy(newKey->priv_key, src->priv_key) == NULL) { - WOLFSSL_MSG("Copying EC private key error"); - err = 1; - } - } - - if (err) { - /* Dispose of EC key on error. */ - wolfSSL_EC_KEY_free(newKey); - newKey = NULL; - } - /* Return the new EC key. */ - return newKey; -} - -#endif /* OPENSSL_ALL */ - -#endif /* !NO_CERTS */ - -/* - * EC key to/from bin/octet APIs - */ - -/* Create an EC key from the octet encoded public key. - * - * Behaviour checked against OpenSSL. - * - * @param [out] key Reference to EC key. Must pass in a valid object with - * group set. - * @param [in, out] in On in, reference to buffer that contains data. - * On out, reference to buffer after public key data. - * @param [in] len Length of data in the buffer. Must be length of the - * encoded public key. - * @return Allocated EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY *wolfSSL_o2i_ECPublicKey(WOLFSSL_EC_KEY **key, - const unsigned char **in, long len) -{ - int err = 0; - WOLFSSL_EC_KEY* ret = NULL; - - WOLFSSL_ENTER("wolfSSL_o2i_ECPublicKey"); - - /* Validate parameters: EC group needed to perform import. */ - if ((key == NULL) || (*key == NULL) || ((*key)->group == NULL) || - (in == NULL) || (*in == NULL) || (len <= 0)) { - WOLFSSL_MSG("wolfSSL_o2i_ECPublicKey Bad arguments"); - err = 1; - } - - if (!err) { - /* Return the EC key object passed in. */ - ret = *key; - - /* Import point into public key field. */ - if (wolfSSL_EC_POINT_oct2point(ret->group, ret->pub_key, *in, - (size_t)len, NULL) != 1) { - WOLFSSL_MSG("wolfSSL_EC_POINT_oct2point error"); - ret = NULL; - err = 1; - } - } - if (!err) { - /* Assumed length passed in is all the data. */ - *in += len; - } - - return ret; -} - -/* Puts the encoded public key into out. - * - * Passing in NULL for out returns length only. - * Passing in NULL for *out has buffer allocated, encoded into and passed back. - * Passing non-NULL for *out has it encoded into and pointer moved past. - * - * @param [in] key EC key to encode. - * @param [in, out] out Reference to buffer to encode into. May be NULL or - * point to NULL. - * @return Length of encoding in bytes on success. - * @return 0 on error. - */ -int wolfSSL_i2o_ECPublicKey(const WOLFSSL_EC_KEY *key, unsigned char **out) -{ - int ret = 1; - size_t len = 0; - int form = WC_POINT_CONVERSION_UNCOMPRESSED; - - WOLFSSL_ENTER("wolfSSL_i2o_ECPublicKey"); - - /* Validate parameters. */ - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_i2o_ECPublicKey Bad arguments"); - ret = 0; - } - - /* Ensure the external key data is set from the internal EC key. */ - if ((ret == 1) && (!key->exSet) && (SetECKeyExternal((WOLFSSL_EC_KEY*) - key) != 1)) { - WOLFSSL_MSG("SetECKeyExternal failure"); - ret = 0; - } - - if (ret == 1) { - #ifdef HAVE_COMP_KEY - /* Default to compressed form if not set */ - form = (key->form == WC_POINT_CONVERSION_UNCOMPRESSED) ? - WC_POINT_CONVERSION_UNCOMPRESSED : - WC_POINT_CONVERSION_COMPRESSED; - #endif - - /* Calculate length of point encoding. */ - len = wolfSSL_EC_POINT_point2oct(key->group, key->pub_key, form, NULL, - 0, NULL); - } - /* Encode if length calculated and pointer supplied to update. */ - if ((ret == 1) && (len != 0) && (out != NULL)) { - unsigned char *tmp = NULL; - - /* Allocate buffer for encoding if no buffer supplied. */ - if (*out == NULL) { - tmp = (unsigned char*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); - if (tmp == NULL) { - WOLFSSL_MSG("malloc failed"); - ret = 0; - } - } - else { - /* Get buffer to encode into. */ - tmp = *out; - } - - /* Encode public key into buffer. */ - if ((ret == 1) && (wolfSSL_EC_POINT_point2oct(key->group, key->pub_key, - form, tmp, len, NULL) == 0)) { - ret = 0; - } - - if (ret == 1) { - /* Return buffer if allocated. */ - if (*out == NULL) { - *out = tmp; - } - else { - /* Step over encoded data if not allocated. */ - *out += len; - } - } - else if (*out == NULL) { - /* Dispose of allocated buffer. */ - XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); - } - } - - if (ret == 1) { - /* Return length on success. */ - ret = (int)len; - } - return ret; -} - -#ifdef HAVE_ECC_KEY_IMPORT -/* Create a EC key from the DER encoded private key. - * - * @param [out] key Reference to EC key. - * @param [in, out] in On in, reference to buffer that contains DER data. - * On out, reference to buffer after private key data. - * @param [in] long Length of data in the buffer. May be larger than the - * length of the encoded private key. - * @return Allocated EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY* wolfSSL_d2i_ECPrivateKey(WOLFSSL_EC_KEY** key, - const unsigned char** in, long len) -{ - int err = 0; - word32 idx = 0; - WOLFSSL_EC_KEY* ret = NULL; - - WOLFSSL_ENTER("wolfSSL_d2i_ECPrivateKey"); - - /* Validate parameters. */ - if ((in == NULL) || (*in == NULL) || (len <= 0)) { - WOLFSSL_MSG("wolfSSL_d2i_ECPrivateKey Bad arguments"); - err = 1; - } - - /* Create a new, empty EC key. */ - if ((!err) && ((ret = wolfSSL_EC_KEY_new()) == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); - err = 1; - } - - /* Decode the private key DER data into internal EC key. */ - if ((!err) && (wc_EccPrivateKeyDecode(*in, &idx, (ecc_key*)ret->internal, - (word32)len) != 0)) { - WOLFSSL_MSG("wc_EccPrivateKeyDecode error"); - err = 1; - } - - if (!err) { - /* Internal EC key setup. */ - ret->inSet = 1; - - /* Set the EC key from the internal values. */ - if (SetECKeyExternal(ret) != 1) { - WOLFSSL_MSG("SetECKeyExternal error"); - err = 1; - } - } - - if (!err) { - /* Move buffer on to next byte after data used. */ - *in += idx; - if (key) { - /* Return new EC key through reference. */ - *key = ret; - } - } - - if (err && (ret != NULL)) { - /* Dispose of allocated EC key. */ - wolfSSL_EC_KEY_free(ret); - ret = NULL; - } - return ret; -} -#endif /* HAVE_ECC_KEY_IMPORT */ - -/* Enecode the private key of the EC key into the buffer as DER. - * - * @param [in] key EC key to encode. - * @param [in, out] out On in, reference to buffer to place DER encoding into. - * On out, reference to buffer after the encoding. - * May be NULL. - * @return Length of DER encoding on success. - * @return 0 on error. - */ -int wolfSSL_i2d_ECPrivateKey(const WOLFSSL_EC_KEY *key, unsigned char **out) -{ - int err = 0; - word32 len = 0; - - WOLFSSL_ENTER("wolfSSL_i2d_ECPrivateKey"); - - /* Validate parameters. */ - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_i2d_ECPrivateKey Bad arguments"); - err = 1; - } - - /* Update the internal EC key if not set. */ - if ((!err) && (!key->inSet) && (SetECKeyInternal((WOLFSSL_EC_KEY*)key) != - 1)) { - WOLFSSL_MSG("SetECKeyInternal error"); - err = 1; - } - - /* Calculate the length of the private key DER encoding using internal EC - * key. */ - if ((!err) && ((int)(len = (word32)wc_EccKeyDerSize((ecc_key*)key->internal, - 0)) <= 0)) { - WOLFSSL_MSG("wc_EccKeyDerSize error"); - err = 1; - } - - /* Only return length when out is NULL. */ - if ((!err) && (out != NULL)) { - unsigned char* buf = NULL; - - /* Must have a buffer to encode into. */ - if (*out == NULL) { - /* Allocate a new buffer of appropriate length. */ - buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - /* Error and return 0. */ - err = 1; - len = 0; - } - else { - /* Return the allocated buffer. */ - *out = buf; - } - } - /* Encode the internal EC key as a private key in DER format. */ - if ((!err) && wc_EccPrivateKeyToDer((ecc_key*)key->internal, *out, - len) < 0) { - WOLFSSL_MSG("wc_EccPrivateKeyToDer error"); - err = 1; - } - else if (buf != *out) { - /* Move the reference to byte past encoded private key. */ - *out += len; - } - - /* Dispose of any allocated buffer on error. */ - if (err && (*out == buf)) { - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - *out = NULL; - } - } - - return (int)len; -} - -/* Load private key into EC key from DER encoding. - * - * Not an OpenSSL compatibility API. - * - * @param [in, out] key EC key to put private key values into. - * @param [in] derBuf Buffer holding DER encoding. - * @param [in] derSz Size of DER encoding in bytes. - * @return 1 on success. - * @return -1 on error. - */ -int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, - int derSz) -{ - return wolfSSL_EC_KEY_LoadDer_ex(key, derBuf, derSz, - WOLFSSL_EC_KEY_LOAD_PRIVATE); -} - -/* Load private/public key into EC key from DER encoding. - * - * Not an OpenSSL compatibility API. - * - * @param [in, out] key EC key to put private/public key values into. - * @param [in] derBuf Buffer holding DER encoding. - * @param [in] derSz Size of DER encoding in bytes. - * @param [in] opt Key type option. Valid values: - * WOLFSSL_EC_KEY_LOAD_PRIVATE, - * WOLFSSL_EC_KEY_LOAD_PUBLIC. - * @return 1 on success. - * @return -1 on error. - */ -int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, - int derSz, int opt) -{ - int res = 1; - int ret; - word32 idx = 0; - word32 algId; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_LoadDer"); - - /* Validate parameters. */ - if ((key == NULL) || (key->internal == NULL) || (derBuf == NULL) || - (derSz <= 0)) { - WOLFSSL_MSG("Bad function arguments"); - res = WOLFSSL_FATAL_ERROR; - } - if ((res == 1) && (opt != WOLFSSL_EC_KEY_LOAD_PRIVATE) && - (opt != WOLFSSL_EC_KEY_LOAD_PUBLIC)) { - res = WOLFSSL_FATAL_ERROR; - } - - if (res == 1) { - /* Assume no PKCS#8 header. */ - key->pkcs8HeaderSz = 0; - - /* Check if input buffer has PKCS8 header. In the case that it does not - * have a PKCS8 header then do not error out. - */ - if ((ret = ToTraditionalInline_ex((const byte*)derBuf, &idx, - (word32)derSz, &algId)) > 0) { - WOLFSSL_MSG("Found PKCS8 header"); - key->pkcs8HeaderSz = (word16)idx; - res = 1; - } - /* Error out on parsing error. */ - else if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) { - WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header"); - res = WOLFSSL_FATAL_ERROR; - } - } - - if (res == 1) { - /* Load into internal EC key based on key type option. */ - if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) { - ret = wc_EccPrivateKeyDecode(derBuf, &idx, (ecc_key*)key->internal, - (word32)derSz); - } - else { - ret = wc_EccPublicKeyDecode(derBuf, &idx, (ecc_key*)key->internal, - (word32)derSz); - if (ret < 0) { - ecc_key *tmp = (ecc_key*)XMALLOC(sizeof(ecc_key), - ((ecc_key*)key->internal)->heap, DYNAMIC_TYPE_ECC); - if (tmp == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - else { - /* We now try again as x.963 [point type][x][opt y]. */ - ret = wc_ecc_init_ex(tmp, ((ecc_key*)key->internal)->heap, - INVALID_DEVID); - if (ret == 0) { - ret = wc_ecc_import_x963(derBuf, (word32)derSz, tmp); - if (ret == 0) { - /* Take ownership of new key - set tmp to the old - * key which will then be freed below. */ - ecc_key *old = (ecc_key *)key->internal; - key->internal = tmp; - tmp = old; - - idx = (word32)derSz; - } - wc_ecc_free(tmp); - } - XFREE(tmp, ((ecc_key*)key->internal)->heap, - DYNAMIC_TYPE_ECC); - } - } - } - if (ret < 0) { - /* Error returned from wolfSSL. */ - if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) { - WOLFSSL_MSG("wc_EccPrivateKeyDecode failed"); - } - else { - WOLFSSL_MSG("wc_EccPublicKeyDecode failed"); - } - res = WOLFSSL_FATAL_ERROR; - } - - /* Internal key updated - update whether it is a valid key. */ - key->inSet = (res == 1); - } - - /* Set the external EC key based on value in internal. */ - if ((res == 1) && (SetECKeyExternal(key) != 1)) { - WOLFSSL_MSG("SetECKeyExternal failed"); - res = WOLFSSL_FATAL_ERROR; - } - - return res; -} - - -#ifndef NO_BIO - -WOLFSSL_EC_KEY *wolfSSL_d2i_EC_PUBKEY_bio(WOLFSSL_BIO *bio, - WOLFSSL_EC_KEY **out) -{ - char* data = NULL; - int dataSz = 0; - int memAlloced = 0; - WOLFSSL_EC_KEY* ec = NULL; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_d2i_EC_PUBKEY_bio"); - - if (bio == NULL) - return NULL; - - if (err == 0 && wolfssl_read_bio(bio, &data, &dataSz, &memAlloced) != 0) { - WOLFSSL_ERROR_MSG("wolfssl_read_bio failed"); - err = 1; - } - - if (err == 0 && (ec = wolfSSL_EC_KEY_new()) == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_EC_KEY_new failed"); - err = 1; - } - - /* Load the EC key with the public key from the DER encoding. */ - if (err == 0 && wolfSSL_EC_KEY_LoadDer_ex(ec, (const unsigned char*)data, - dataSz, WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1) { - WOLFSSL_ERROR_MSG("wolfSSL_EC_KEY_LoadDer_ex failed"); - err = 1; - } - - if (memAlloced) - XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (err) { /* on error */ - wolfSSL_EC_KEY_free(ec); - ec = NULL; - } - else { /* on success */ - if (out != NULL) - *out = ec; - } - - return ec; -} - -#endif /* !NO_BIO */ - -/* - * EC key PEM APIs - */ - -#ifdef HAVE_ECC_KEY_EXPORT -#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_FILESYSTEM) || !defined(NO_BIO)) -/* Encode the EC public key as DER. - * - * @param [in] key EC 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_ec_key_to_pubkey_der(WOLFSSL_EC_KEY* key, - unsigned char** der, void* heap) -{ - int sz; - unsigned char* buf = NULL; - - (void)heap; - - /* Calculate encoded size to allocate. */ - sz = wc_EccPublicKeyDerSize((ecc_key*)key->internal, 1); - if (sz <= 0) { - WOLFSSL_MSG("wc_EccPublicKeyDerSize failed"); - sz = 0; - } - if (sz > 0) { - /* 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_EccPublicKeyToDer((ecc_key*)key->internal, buf, (word32)sz, 1); - if (sz < 0) { - WOLFSSL_MSG("wc_EccPublicKeyToDer 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; -} -#endif - -#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_KEY_GEN) -/* - * Return code compliant with OpenSSL. - * - * @param [in] fp File pointer to write PEM encoding to. - * @param [in] key EC key to encode and write. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_PEM_write_EC_PUBKEY(XFILE fp, WOLFSSL_EC_KEY* key) -{ - int ret = 1; - unsigned char* derBuf = NULL; - int derSz = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_write_EC_PUBKEY"); - - /* Validate parameters. */ - if ((fp == XBADFILE) || (key == NULL)) { - WOLFSSL_MSG("Bad argument."); - return 0; - } - - /* Encode public key in EC key as DER. */ - derSz = wolfssl_ec_key_to_pubkey_der(key, &derBuf, key->heap); - if (derSz == 0) { - ret = 0; - } - - /* Write out to file the PEM encoding of the DER. */ - if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, - ECC_PUBLICKEY_TYPE, key->heap) != 1)) { - ret = 0; - } - - /* Dispose of any dynamically allocated data. */ - XFREE(derBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER); - - WOLFSSL_LEAVE("wolfSSL_PEM_write_EC_PUBKEY", ret); - - return ret; -} -#endif -#endif - -#ifndef NO_BIO -/* Read a PEM encoded EC public key from a BIO. - * - * @param [in] bio BIO to read EC public key from. - * @param [out] out Pointer to return EC key object through. May be NULL. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM - * encrypted. - * @return New EC key object on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_EC_PUBKEY(WOLFSSL_BIO* bio, - WOLFSSL_EC_KEY** out, wc_pem_password_cb* cb, void *pass) -{ - int err = 0; - WOLFSSL_EC_KEY* ec = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_EC_PUBKEY"); - - /* Validate parameters. */ - if (bio == NULL) { - err = 1; - } - - if (!err) { - /* Create an empty EC key. */ - ec = wolfSSL_EC_KEY_new(); - if (ec == NULL) { - err = 1; - } - } - /* Read a PEM key in to a new DER buffer. */ - if ((!err) && (pem_read_bio_key(bio, cb, pass, ECC_PUBLICKEY_TYPE, - &keyFormat, &der) <= 0)) { - err = 1; - } - /* Load the EC key with the public key from the DER encoding. */ - if ((!err) && (wolfSSL_EC_KEY_LoadDer_ex(ec, der->buffer, (int)der->length, - WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1)) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_KEY"); - err = 1; - } - - /* Dispose of dynamically allocated data not needed anymore. */ - FreeDer(&der); - if (err) { - wolfSSL_EC_KEY_free(ec); - ec = NULL; - } - - /* Return EC key through out if required. */ - if ((out != NULL) && (ec != NULL)) { - *out = ec; - } - return ec; -} - -/* Read a PEM encoded EC private key from a BIO. - * - * @param [in] bio BIO to read EC private key from. - * @param [out] out Pointer to return EC key object through. May be NULL. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM - * encrypted. - * @return New EC key object on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_ECPrivateKey(WOLFSSL_BIO* bio, - WOLFSSL_EC_KEY** out, wc_pem_password_cb* cb, void *pass) -{ - int err = 0; - WOLFSSL_EC_KEY* ec = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_ECPrivateKey"); - - /* Validate parameters. */ - if (bio == NULL) { - err = 1; - } - - if (!err) { - /* Create an empty EC key. */ - ec = wolfSSL_EC_KEY_new(); - if (ec == NULL) { - err = 1; - } - } - /* Read a PEM key in to a new DER buffer. - * To check ENC EC PRIVATE KEY, it uses PRIVATEKEY_TYPE to call - * pem_read_bio_key(), and then check key format if it is EC. - */ - if ((!err) && (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, - &keyFormat, &der) <= 0)) { - err = 1; - } - if (keyFormat != ECDSAk) { - WOLFSSL_ERROR_MSG("Error not EC key format"); - err = 1; - } - /* Load the EC key with the private key from the DER encoding. */ - if ((!err) && (wolfSSL_EC_KEY_LoadDer_ex(ec, der->buffer, (int)der->length, - WOLFSSL_EC_KEY_LOAD_PRIVATE) != 1)) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_KEY"); - err = 1; - } - - /* Dispose of dynamically allocated data not needed anymore. */ - FreeDer(&der); - if (err) { - wolfSSL_EC_KEY_free(ec); - ec = NULL; - } - - /* Return EC key through out if required. */ - if ((out != NULL) && (ec != NULL)) { - *out = ec; - } - return ec; -} -#endif /* !NO_BIO */ - -#if defined(WOLFSSL_KEY_GEN) && defined(HAVE_ECC_KEY_EXPORT) -#ifndef NO_BIO -/* Write out the EC public key as PEM to the BIO. - * - * @param [in] bio BIO to write PEM encoding to. - * @param [in] ec EC public key to encode. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_PEM_write_bio_EC_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec) -{ - int ret = 1; - unsigned char* derBuf = NULL; - int derSz = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_EC_PUBKEY"); - - /* Validate parameters. */ - if ((bio == NULL) || (ec == NULL)) { - WOLFSSL_MSG("Bad Function Arguments"); - return 0; - } - - /* Encode public key in EC key as DER. */ - derSz = wolfssl_ec_key_to_pubkey_der(ec, &derBuf, ec->heap); - if (derSz == 0) { - ret = 0; - } - - /* 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; - } - - /* Dispose of any dynamically allocated data. */ - XFREE(derBuf, ec->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} - -/* Write out the EC private key as PEM to the BIO. - * - * Return code compliant with OpenSSL. - * - * @param [in] bio BIO to write PEM encoding to. - * @param [in] ec EC private key to encode. - * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. - * @param [in] passwd Password string when PEM encrypted. May be NULL. - * @param [in] passwdSz Length of password string when PEM encrypted. - * @param [in] cb Password callback when PEM encrypted. Unused. - * @param [in] pass NUL terminated string for passphrase when PEM - * encrypted. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_PEM_write_bio_ECPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec, - const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, - wc_pem_password_cb* cb, void* arg) -{ - int ret = 1; - unsigned char* pem = NULL; - int pLen = 0; - - (void)cb; - (void)arg; - - /* Validate parameters. */ - if ((bio == NULL) || (ec == NULL)) { - ret = 0; - } - - /* Write EC private key to PEM. */ - if ((ret == 1) && (wolfSSL_PEM_write_mem_ECPrivateKey(ec, cipher, passwd, - passwdSz, &pem, &pLen) != 1)) { - ret = 0; - } - /* Write PEM to BIO. */ - if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) != pLen)) { - WOLFSSL_ERROR_MSG("EC private key BIO write failed"); - ret = 0; - } - - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); - - return ret; -} - -#endif /* !NO_BIO */ - -/* Encode the EC private key as PEM into buffer. - * - * Return code compliant with OpenSSL. - * Not an OpenSSL API. - * - * @param [in] ec EC private key to encode. - * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. - * @param [in] passwd Password string when PEM encrypted. May be NULL. - * @param [in] passwdSz Length of password string when PEM encrypted. - * @param [out] pem Newly allocated buffer holding PEM encoding. - * @param [out] pLen Length of PEM encoding in bytes. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* ec, - const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, - unsigned char **pem, int *pLen) -{ -#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) - int ret = 1; - byte* derBuf = NULL; - word32 der_max_len = 0; - int derSz = 0; - - WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey"); - - /* Validate parameters. */ - if ((pem == NULL) || (pLen == NULL) || (ec == NULL) || - (ec->internal == NULL)) { - WOLFSSL_MSG("Bad function arguments"); - ret = 0; - } - - /* Ensure internal EC key is set from external. */ - if ((ret == 1) && (ec->inSet == 0)) { - WOLFSSL_MSG("No ECC internal set, do it"); - - if (SetECKeyInternal(ec) != 1) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = 0; - } - } - - if (ret == 1) { - /* Calculate maximum size of DER encoding. - * 4 > size of pub, priv + ASN.1 additional information */ - der_max_len = 4 * (word32)wc_ecc_size((ecc_key*)ec->internal) + - WC_AES_BLOCK_SIZE; - - /* Allocate buffer big enough to hold encoding. */ - derBuf = (byte*)XMALLOC((size_t)der_max_len, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (derBuf == NULL) { - WOLFSSL_MSG("malloc failed"); - ret = 0; - } - } - - if (ret == 1) { - /* Encode EC private key as DER. */ - derSz = wc_EccKeyToDer((ecc_key*)ec->internal, derBuf, der_max_len); - if (derSz < 0) { - WOLFSSL_MSG("wc_EccKeyToDer failed"); - XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); - ret = 0; - } - } - - /* Convert DER to PEM - possibly encrypting. */ - if ((ret == 1) && (der_to_enc_pem_alloc(derBuf, derSz, cipher, passwd, - passwdSz, ECC_PRIVATEKEY_TYPE, NULL, pem, pLen) != 1)) { - WOLFSSL_ERROR_MSG("der_to_enc_pem_alloc failed"); - ret = 0; - } - - return ret; -#else - (void)ec; - (void)cipher; - (void)passwd; - (void)passwdSz; - (void)pem; - (void)pLen; - return 0; -#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ -} - -#ifndef NO_FILESYSTEM -/* Write out the EC private key as PEM to file. - * - * Return code compliant with OpenSSL. - * - * @param [in] fp File pointer to write PEM encoding to. - * @param [in] ec EC private key to encode. - * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. - * @param [in] passwd Password string when PEM encrypted. May be NULL. - * @param [in] passwdSz Length of password string when PEM encrypted. - * @param [in] cb Password callback when PEM encrypted. Unused. - * @param [in] pass NUL terminated string for passphrase when PEM - * encrypted. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_PEM_write_ECPrivateKey(XFILE fp, WOLFSSL_EC_KEY *ec, - const WOLFSSL_EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz, - wc_pem_password_cb *cb, void *pass) -{ - int ret = 1; - byte *pem = NULL; - int pLen = 0; - - (void)cb; - (void)pass; - - WOLFSSL_MSG("wolfSSL_PEM_write_ECPrivateKey"); - - /* Validate parameters. */ - if ((fp == XBADFILE) || (ec == NULL) || (ec->internal == NULL)) { - WOLFSSL_MSG("Bad function arguments"); - ret = 0; - } - - /* Write EC private key to PEM. */ - if ((ret == 1) && (wolfSSL_PEM_write_mem_ECPrivateKey(ec, cipher, passwd, - passwdSz, &pem, &pLen) != 1)) { - WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey failed"); - ret = 0; - } - - /* Write out to file the PEM encoding of the EC private key. */ - if ((ret == 1) && ((int)XFWRITE(pem, 1, (size_t)pLen, fp) != pLen)) { - WOLFSSL_MSG("ECC private key file write failed"); - ret = 0; - } - - /* Dispose of any dynamically allocated data. */ - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); - - return ret; -} - -#endif /* NO_FILESYSTEM */ -#endif /* WOLFSSL_KEY_GEN && HAVE_ECC_KEY_EXPORT */ - -/* - * EC key print APIs - */ - -#ifndef NO_CERTS - -#if defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \ - !defined(NO_STDIO_FILESYSTEM) -/* Print the EC key to a file pointer as text. - * - * @param [in] fp File pointer. - * @param [in] key EC key to print. - * @param [in] indent Number of spaces to place before each line printed. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_EC_KEY_print_fp(XFILE fp, WOLFSSL_EC_KEY* key, int indent) -{ - int ret = 1; - int bits = 0; - int priv = 0; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_print_fp"); - - /* Validate parameters. */ - if ((fp == XBADFILE) || (key == NULL) || (key->group == NULL) || - (indent < 0)) { - ret = 0; - } - - if (ret == 1) { - /* Get EC groups order size in bits. */ - bits = wolfSSL_EC_GROUP_order_bits(key->group); - if (bits <= 0) { - WOLFSSL_MSG("Failed to get group order bits."); - ret = 0; - } - } - if (ret == 1) { - const char* keyType; - - /* Determine whether this is a private or public key. */ - if ((key->priv_key != NULL) && (!wolfSSL_BN_is_zero(key->priv_key))) { - keyType = "Private-Key"; - priv = 1; - } - else { - keyType = "Public-Key"; - } - - /* Print key header. */ - if (XFPRINTF(fp, "%*s%s: (%d bit)\n", indent, "", keyType, bits) < 0) { - ret = 0; - } - } - if ((ret == 1) && priv) { - /* Print the private key BN. */ - ret = pk_bn_field_print_fp(fp, indent, "priv", key->priv_key); - } - /* Check for public key data in EC key. */ - if ((ret == 1) && (key->pub_key != NULL) && (key->pub_key->exSet)) { - /* Get the public key point as one BN. */ - WOLFSSL_BIGNUM* pubBn = wolfSSL_EC_POINT_point2bn(key->group, - key->pub_key, WC_POINT_CONVERSION_UNCOMPRESSED, NULL, NULL); - if (pubBn == NULL) { - WOLFSSL_MSG("wolfSSL_EC_POINT_point2bn failed."); - ret = 0; - } - else { - /* Print the public key in a BN. */ - ret = pk_bn_field_print_fp(fp, indent, "pub", pubBn); - wolfSSL_BN_free(pubBn); - } - } - if (ret == 1) { - /* Get the NID of the group. */ - int nid = wolfSSL_EC_GROUP_get_curve_name(key->group); - if (nid > 0) { - /* Convert the NID into a long name and NIST name. */ - const char* curve = wolfSSL_OBJ_nid2ln(nid); - const char* nistName = wolfSSL_EC_curve_nid2nist(nid); - - /* Print OID name if known. */ - if ((curve != NULL) && - (XFPRINTF(fp, "%*sASN1 OID: %s\n", indent, "", curve) < 0)) { - ret = 0; - } - /* Print NIST curve name if known. */ - if ((nistName != NULL) && - (XFPRINTF(fp, "%*sNIST CURVE: %s\n", indent, "", - nistName) < 0)) { - ret = 0; - } - } - } - - - WOLFSSL_LEAVE("wolfSSL_EC_KEY_print_fp", ret); - - return ret; -} -#endif /* XFPRINTF && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ - -#endif /* !NO_CERTS */ - -/* - * EC_KEY get/set/test APIs - */ - -/* Set data of internal, wolfCrypt EC key object into EC key. - * - * EC_KEY wolfSSL -> OpenSSL - * - * @param [in, out] p EC key to update. - * @return 1 on success. - * @return -1 on failure. - */ -int SetECKeyExternal(WOLFSSL_EC_KEY* eckey) -{ - int ret = 1; - - WOLFSSL_ENTER("SetECKeyExternal"); - - /* Validate parameter. */ - if ((eckey == NULL) || (eckey->internal == NULL)) { - WOLFSSL_MSG("ec key NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - else { - ecc_key* key = (ecc_key*)eckey->internal; - - /* Set group (OID, nid and idx) from wolfCrypt EC key. */ - eckey->group->curve_oid = (int)key->dp->oidSum; - eckey->group->curve_nid = EccEnumToNID(key->dp->id); - eckey->group->curve_idx = key->idx; - - if (eckey->pub_key->internal != NULL) { - /* Copy internal public point from internal key's public point. */ - if (wc_ecc_copy_point(&key->pubkey, - (ecc_point*)eckey->pub_key->internal) != MP_OKAY) { - WOLFSSL_MSG("SetECKeyExternal ecc_copy_point failed"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Set external public key from internal wolfCrypt, public key. */ - if ((ret == 1) && (ec_point_external_set(eckey->pub_key) != 1)) { - WOLFSSL_MSG("SetECKeyExternal ec_point_external_set failed"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - /* set the external privkey */ - if ((ret == 1) && (key->type == ECC_PRIVATEKEY) && - (wolfssl_bn_set_value(&eckey->priv_key, - wc_ecc_key_get_priv(key)) != 1)) { - WOLFSSL_MSG("ec priv key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* External values set when operations succeeded. */ - eckey->exSet = (ret == 1); - } - - return ret; -} - -/* Set data of EC key into internal, wolfCrypt EC key object. - * - * EC_KEY Openssl -> WolfSSL - * - * @param [in, out] p EC key to update. - * @return 1 on success. - * @return -1 on failure. - */ -int SetECKeyInternal(WOLFSSL_EC_KEY* eckey) -{ - int ret = 1; - - WOLFSSL_ENTER("SetECKeyInternal"); - - /* Validate parameter. */ - if ((eckey == NULL) || (eckey->internal == NULL) || - (eckey->group == NULL)) { - WOLFSSL_MSG("ec key NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - else { - ecc_key* key = (ecc_key*)eckey->internal; - int pubSet = 0; - - /* Validate group. */ - if ((eckey->group->curve_idx < 0) || - (wc_ecc_is_valid_idx(eckey->group->curve_idx) == 0)) { - WOLFSSL_MSG("invalid curve idx"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 1) { - /* Set group (idx of curve and corresponding domain parameters). */ - key->idx = eckey->group->curve_idx; - key->dp = &ecc_sets[key->idx]; - pubSet = (eckey->pub_key != NULL); - } - /* Set public key (point). */ - if ((ret == 1) && pubSet) { - if (ec_point_internal_set(eckey->pub_key) != 1) { - WOLFSSL_MSG("ec key pub error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Copy public point to key. */ - if ((ret == 1) && (wc_ecc_copy_point( - (ecc_point*)eckey->pub_key->internal, &key->pubkey) != - MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_copy_point error"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 1) { - /* Set that the internal key is a public key */ - key->type = ECC_PUBLICKEY; - } - } - - /* set privkey */ - if ((ret == 1) && (eckey->priv_key != NULL)) { - if (wolfssl_bn_get_value(eckey->priv_key, - wc_ecc_key_get_priv(key)) != 1) { - WOLFSSL_MSG("ec key priv error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* private key */ - if ((ret == 1) && (!mp_iszero(wc_ecc_key_get_priv(key)))) { - if (pubSet) { - key->type = ECC_PRIVATEKEY; - } - else { - key->type = ECC_PRIVATEKEY_ONLY; - } - } - } - - /* Internal values set when operations succeeded. */ - eckey->inSet = (ret == 1); - } - - return ret; -} - -/* Get point conversion format of EC key. - * - * @param [in] key EC key. - * @return Point conversion format on success. - * @return -1 on error. - */ -wc_point_conversion_form_t wolfSSL_EC_KEY_get_conv_form( - const WOLFSSL_EC_KEY* key) -{ - if (key == NULL) - return WOLFSSL_FATAL_ERROR; - return key->form; -} - -/* Set point conversion format into EC key. - * - * @param [in, out] key EC key to set format into. - * @param [in] form Point conversion format. Valid values: - * WC_POINT_CONVERSION_UNCOMPRESSED, - * WC_POINT_CONVERSION_COMPRESSED (when HAVE_COMP_KEY) - */ -void wolfSSL_EC_KEY_set_conv_form(WOLFSSL_EC_KEY *key, int form) -{ - if (key == NULL) { - WOLFSSL_MSG("Key passed in NULL"); - } - else if (form == WC_POINT_CONVERSION_UNCOMPRESSED -#ifdef HAVE_COMP_KEY - || form == WC_POINT_CONVERSION_COMPRESSED -#endif - ) { - key->form = (unsigned char)form; - } - else { - WOLFSSL_MSG("Incorrect form or HAVE_COMP_KEY not compiled in"); - } -} - -/* Get the EC group object that is in EC key. - * - * @param [in] key EC key. - * @return EC group object on success. - * @return NULL when key is NULL. - */ -const WOLFSSL_EC_GROUP *wolfSSL_EC_KEY_get0_group(const WOLFSSL_EC_KEY *key) -{ - WOLFSSL_EC_GROUP* group = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_group"); - - if (key != NULL) { - group = key->group; - } - - return group; -} - -/* Set the group in WOLFSSL_EC_KEY - * - * @param [in, out] key EC key to update. - * @param [in] group EC group to copy. - * @return 1 on success - * @return 0 on failure. - */ -int wolfSSL_EC_KEY_set_group(WOLFSSL_EC_KEY *key, WOLFSSL_EC_GROUP *group) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_set_group"); - - /* Validate parameters. */ - if ((key == NULL) || (group == NULL)) { - ret = 0; - } - - if (ret == 1) { - /* Dispose of the current group. */ - if (key->group != NULL) { - wolfSSL_EC_GROUP_free(key->group); - } - /* Duplicate the passed in group into EC key. */ - key->group = wolfSSL_EC_GROUP_dup(group); - if (key->group == NULL) { - ret = 0; - } - } - - return ret; -} - -/* Get the BN object that is the private key in the EC key. - * - * @param [in] key EC key. - * @return BN object on success. - * @return NULL when key is NULL or private key is not set. - */ -WOLFSSL_BIGNUM *wolfSSL_EC_KEY_get0_private_key(const WOLFSSL_EC_KEY *key) -{ - WOLFSSL_BIGNUM* priv_key = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_private_key"); - - /* Validate parameter. */ - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_get0_private_key Bad arguments"); - } - /* Only return private key if it is not 0. */ - else if (!wolfSSL_BN_is_zero(key->priv_key)) { - priv_key = key->priv_key; - } - - return priv_key; -} - -/* Sets the private key value into EC key. - * - * Return code compliant with OpenSSL. - * - * @param [in, out] key EC key to set. - * @param [in] priv_key Private key value in a BN. - * @return 1 on success - * @return 0 on failure. - */ -int wolfSSL_EC_KEY_set_private_key(WOLFSSL_EC_KEY *key, - const WOLFSSL_BIGNUM *priv_key) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_set_private_key"); - - /* Validate parameters. */ - if ((key == NULL) || (priv_key == NULL)) { - WOLFSSL_MSG("Bad arguments"); - ret = 0; - } - - /* Check for obvious invalid values. */ - if (wolfSSL_BN_is_negative(priv_key) || wolfSSL_BN_is_zero(priv_key) || - wolfSSL_BN_is_one(priv_key)) { - WOLFSSL_MSG("Invalid private key value"); - ret = 0; - } - - if (ret == 1) { - /* Free key if previously set. */ - if (key->priv_key != NULL) { - wolfSSL_BN_free(key->priv_key); - } - - /* Duplicate the BN passed in. */ - key->priv_key = wolfSSL_BN_dup(priv_key); - if (key->priv_key == NULL) { - WOLFSSL_MSG("key ecc priv key NULL"); - ret = 0; - } - } - /* Set the external values into internal EC key. */ - if ((ret == 1) && (SetECKeyInternal(key) != 1)) { - WOLFSSL_MSG("SetECKeyInternal failed"); - /* Dispose of new private key on error. */ - wolfSSL_BN_free(key->priv_key); - key->priv_key = NULL; - ret = 0; - } - - return ret; -} - -/* Get the public key EC point object that is in EC key. - * - * @param [in] key EC key. - * @return EC point object that is the public key on success. - * @return NULL when key is NULL. - */ -WOLFSSL_EC_POINT* wolfSSL_EC_KEY_get0_public_key(const WOLFSSL_EC_KEY *key) -{ - WOLFSSL_EC_POINT* pub_key = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_public_key"); - - if (key != NULL) { - pub_key = key->pub_key; - } - - return pub_key; -} - -/* - * Return code compliant with OpenSSL. - * - * @param [in, out] key EC key. - * @param [in] pub Public key as an EC point. - * @return 1 on success - * @return 0 on failure. - */ -int wolfSSL_EC_KEY_set_public_key(WOLFSSL_EC_KEY *key, - const WOLFSSL_EC_POINT *pub) -{ - int ret = 1; - ecc_point *pub_p = NULL; - ecc_point *key_p = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_set_public_key"); - - /* Validate parameters. */ - if ((key == NULL) || (key->internal == NULL) || (pub == NULL) || - (pub->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_KEY_set_public_key Bad arguments"); - ret = 0; - } - - /* Ensure the internal EC key is set. */ - if ((ret == 1) && (key->inSet == 0) && (SetECKeyInternal(key) != 1)) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = 0; - } - - /* Ensure the internal EC point of pub is setup. */ - if ((ret == 1) && (ec_point_setup(pub) != 1)) { - ret = 0; - } - - if (ret == 1) { - /* Get the internal point of pub and the public key in key. */ - pub_p = (ecc_point*)pub->internal; - key_p = (ecc_point*)key->pub_key->internal; - - /* Create new point if required. */ - if (key_p == NULL) { - key_p = wc_ecc_new_point(); - key->pub_key->internal = (void*)key_p; - } - /* Check point available. */ - if (key_p == NULL) { - WOLFSSL_MSG("key ecc point NULL"); - ret = 0; - } - } - - /* Copy the internal pub point into internal key point. */ - if ((ret == 1) && (wc_ecc_copy_point(pub_p, key_p) != MP_OKAY)) { - WOLFSSL_MSG("ecc_copy_point failure"); - ret = 0; - } - - /* Copy the internal point data into external. */ - if ((ret == 1) && (ec_point_external_set(key->pub_key) != 1)) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = 0; - } - - /* Copy the internal key into external. */ - if ((ret == 1) && (SetECKeyInternal(key) != 1)) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = 0; - } - - if (ret == 1) { - /* Dump out the point and the key's public key for debug. */ - wolfSSL_EC_POINT_dump("pub", pub); - wolfSSL_EC_POINT_dump("key->pub_key", key->pub_key); - } - - return ret; -} - -#ifndef NO_WOLFSSL_STUB -/* Set the ASN.1 encoding flag against the EC key. - * - * No implementation as only named curves supported for encoding. - * - * @param [in, out] key EC key. - * @param [in] flag ASN.1 flag to set. Valid values: - * OPENSSL_EC_EXPLICIT_CURVE, OPENSSL_EC_NAMED_CURVE - */ -void wolfSSL_EC_KEY_set_asn1_flag(WOLFSSL_EC_KEY *key, int asn1_flag) -{ - (void)key; - (void)asn1_flag; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_set_asn1_flag"); - WOLFSSL_STUB("EC_KEY_set_asn1_flag"); -} -#endif - -/* - * EC key generate key APIs - */ - -/* Generate an EC key. - * - * Uses the internal curve index set in the EC key or the default. - * - * @param [in, out] key EC key. - * @return 1 on success - * @return 0 on failure. - */ -int wolfSSL_EC_KEY_generate_key(WOLFSSL_EC_KEY *key) -{ - int res = 1; - int initTmpRng = 0; - WC_RNG* rng = NULL; - WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - - WOLFSSL_ENTER("wolfSSL_EC_KEY_generate_key"); - - /* Validate parameters. */ - if ((key == NULL) || (key->internal == NULL) || (key->group == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key Bad arguments"); - res = 0; - } - if (res == 1) { - /* Check if we know which internal curve index to use. */ - if (key->group->curve_idx < 0) { - /* Generate key using the default curve. */ -#if FIPS_VERSION3_GE(6,0,0) - key->group->curve_idx = ECC_SECP256R1; /* FIPS default to 256 */ -#else - key->group->curve_idx = ECC_CURVE_DEF; -#endif - } - - /* 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; - } - } - if (res == 1) { - /* NIDToEccEnum returns -1 for invalid NID so if key->group->curve_nid - * is 0 then pass ECC_CURVE_DEF as arg */ - int eccEnum = key->group->curve_nid ? -#if FIPS_VERSION3_GE(6,0,0) - NIDToEccEnum(key->group->curve_nid) : ECC_SECP256R1; -#else - NIDToEccEnum(key->group->curve_nid) : ECC_CURVE_DEF; -#endif - /* Get the internal EC key. */ - ecc_key* ecKey = (ecc_key*)key->internal; - /* Make the key using internal API. */ - int ret = 0; - -#if FIPS_VERSION3_GE(6,0,0) - /* In the case of FIPS only allow key generation with approved curves */ - if (eccEnum != ECC_SECP256R1 && eccEnum != ECC_SECP224R1 && - eccEnum != ECC_SECP384R1 && eccEnum != ECC_SECP521R1) { - WOLFSSL_MSG("Unsupported curve selected in FIPS mode"); - res = 0; - } - if (res == 1) { -#endif - ret = wc_ecc_make_key_ex(rng, 0, ecKey, eccEnum); -#if FIPS_VERSION3_GE(6,0,0) - } -#endif - - #if defined(WOLFSSL_ASYNC_CRYPT) - /* Wait on asynchronouse operation. */ - ret = wc_AsyncWait(ret, &ecKey->asyncDev, WC_ASYNC_FLAG_NONE); - #endif - if (ret != 0) { - WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key wc_ecc_make_key failed"); - res = 0; - } - } - - /* Dispose of local random number generator if initialized. */ - if (initTmpRng) { - wc_FreeRng(rng); - WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); - } - - /* Set the external key from new internal key values. */ - if ((res == 1) && (SetECKeyExternal(key) != 1)) { - WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key SetECKeyExternal failed"); - res = 0; - } - - return res; -} - -/* - * EC key check key APIs - */ - -/* Check that the EC key is valid. - * - * @param [in] key EC key. - * @return 1 on valid. - * @return 0 on invalid or error. - */ -int wolfSSL_EC_KEY_check_key(const WOLFSSL_EC_KEY *key) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_check_key"); - - /* Validate parameter. */ - if ((key == NULL) || (key->internal == NULL)) { - WOLFSSL_MSG("Bad parameter"); - ret = 0; - } - - /* Set the external EC key values into internal if not already. */ - if ((ret == 1) && (key->inSet == 0) && (SetECKeyInternal( - (WOLFSSL_EC_KEY*)key) != 1)) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = 0; - } - - if (ret == 1) { - /* Have internal EC implementation check key. */ - ret = wc_ecc_check_key((ecc_key*)key->internal) == 0; - } - - return ret; -} - -/* End EC_KEY */ - -#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) -/* Get the supported, built-in EC curves - * - * @param [in, out] curves Pre-allocated list to put supported curves into. - * @param [in] len Maximum number of items to place in list. - * @return Number of built-in EC curves when curves is NULL or len is 0. - * @return Number of items placed in list otherwise. - */ -size_t wolfSSL_EC_get_builtin_curves(WOLFSSL_EC_BUILTIN_CURVE *curves, - size_t len) -{ - size_t i; - size_t cnt; -#ifdef HAVE_SELFTEST - /* Defined in ecc.h when available. */ - size_t ecc_sets_count; - - /* Count the pre-defined curves since global not available. */ - for (i = 0; ecc_sets[i].size != 0 && ecc_sets[i].name != NULL; i++) { - /* Do nothing. */ - } - ecc_sets_count = i; -#endif - - /* Assume we are going to return total count. */ - cnt = ecc_sets_count; - /* Check we have a list that can hold data. */ - if ((curves != NULL) && (len != 0)) { - /* Limit count to length of list. */ - if (cnt > len) { - cnt = len; - } - - /* Put in built-in EC curve nid and short name. */ - for (i = 0; i < cnt; i++) { - curves[i].nid = EccEnumToNID(ecc_sets[i].id); - curves[i].comment = wolfSSL_OBJ_nid2sn(curves[i].nid); - } - } - - return cnt; -} -#endif /* !HAVE_FIPS || FIPS_VERSION_GT(2,0) */ - -/* Start ECDSA_SIG */ - -/* Allocate a new ECDSA signature object. - * - * @return New, allocated ECDSA signature object on success. - * @return NULL on error. - */ -WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_SIG_new(void) -{ - int err = 0; - WOLFSSL_ECDSA_SIG *sig; - - WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_new"); - - /* Allocate memory for ECDSA signature object. */ - sig = (WOLFSSL_ECDSA_SIG*)XMALLOC(sizeof(WOLFSSL_ECDSA_SIG), NULL, - DYNAMIC_TYPE_ECC); - if (sig == NULL) { - WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA signature failure"); - err = 1; - } - - if (!err) { - /* Set s to NULL in case of error. */ - sig->s = NULL; - /* Allocate BN into r. */ - sig->r = wolfSSL_BN_new(); - if (sig->r == NULL) { - WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA r failure"); - err = 1; - } - } - if (!err) { - /* Allocate BN into s. */ - sig->s = wolfSSL_BN_new(); - if (sig->s == NULL) { - WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA s failure"); - err = 1; - } - } - - if (err && (sig != NULL)) { - /* Dispose of allocated memory. */ - wolfSSL_ECDSA_SIG_free(sig); - sig = NULL; - } - return sig; -} - -/* Dispose of ECDSA signature object. - * - * Cannot use object after this call. - * - * @param [in] sig ECDSA signature object to free. - */ -void wolfSSL_ECDSA_SIG_free(WOLFSSL_ECDSA_SIG *sig) -{ - WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_free"); - - if (sig != NULL) { - /* Dispose of BNs allocated for r and s. */ - wolfSSL_BN_free(sig->r); - wolfSSL_BN_free(sig->s); - - /* Dispose of memory associated with ECDSA signature object. */ - XFREE(sig, NULL, DYNAMIC_TYPE_ECC); - } -} - -/* Create an ECDSA signature from the DER encoding. - * - * @param [in, out] sig Reference to ECDSA signature object. May be NULL. - * @param [in, out] pp On in, reference to buffer containing DER encoding. - * On out, reference to buffer after signature data. - * @param [in] len Length of the data in the buffer. May be more than - * the length of the signature. - * @return ECDSA signature object on success. - * @return NULL on error. - */ -WOLFSSL_ECDSA_SIG* wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG** sig, - const unsigned char** pp, long len) -{ - int err = 0; - /* ECDSA signature object to return. */ - WOLFSSL_ECDSA_SIG *s = NULL; - - /* Validate parameter. */ - if (pp == NULL) { - err = 1; - } - if (!err) { - if (sig != NULL) { - /* Use the ECDSA signature object passed in. */ - s = *sig; - } - if (s == NULL) { - /* No ECDSA signature object passed in - create a new one. */ - s = wolfSSL_ECDSA_SIG_new(); - if (s == NULL) { - err = 1; - } - } - } - if (!err) { - /* DecodeECC_DSA_Sig calls mp_init, so free these. */ - mp_free((mp_int*)s->r->internal); - mp_free((mp_int*)s->s->internal); - - /* Decode the signature into internal r and s fields. */ - if (DecodeECC_DSA_Sig(*pp, (word32)len, (mp_int*)s->r->internal, - (mp_int*)s->s->internal) != MP_OKAY) { - err = 1; - } - } - - if (!err) { - /* Move pointer passed signature data successfully decoded. */ - *pp += wolfssl_der_length(*pp, (int)len); - if (sig != NULL) { - /* Update reference to ECDSA signature object. */ - *sig = s; - } - } - - /* Dispose of newly allocated object on error. */ - if (err) { - if ((s != NULL) && ((sig == NULL) || (*sig != s))) { - wolfSSL_ECDSA_SIG_free(s); - } - /* Return NULL for object on error. */ - s = NULL; - } - return s; -} - -/* Encode the ECDSA signature as DER. - * - * @param [in] sig ECDSA signature object. - * @param [in, out] pp On in, reference to buffer in which to place encoding. - * On out, reference to buffer after encoding. - * May be NULL or point to NULL in which case no encoding - * is done. - * @return Length of encoding on success. - * @return 0 on error. - */ -int wolfSSL_i2d_ECDSA_SIG(const WOLFSSL_ECDSA_SIG *sig, unsigned char **pp) -{ - word32 len = 0; - int update_p = 1; - - /* Validate parameter. */ - if (sig != NULL) { - /* ASN.1: SEQ + INT + INT - * ASN.1 Integer must be a positive value - prepend zero if number has - * top bit set. - */ - /* Get total length of r including any prepended zero. */ - word32 rLen = (word32)(mp_leading_bit((mp_int*)sig->r->internal) + - mp_unsigned_bin_size((mp_int*)sig->r->internal)); - /* Get total length of s including any prepended zero. */ - word32 sLen = (word32)(mp_leading_bit((mp_int*)sig->s->internal) + - mp_unsigned_bin_size((mp_int*)sig->s->internal)); - /* Calculate length of data in sequence. */ - len = (word32)1 + ASN_LEN_SIZE(rLen) + rLen + - (word32)1 + ASN_LEN_SIZE(sLen) + sLen; - /* Add in the length of the SEQUENCE. */ - len += (word32)1 + ASN_LEN_SIZE(len); - - #ifdef WOLFSSL_I2D_ECDSA_SIG_ALLOC - if ((pp != NULL) && (*pp == NULL)) { - *pp = (unsigned char *)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); - if (*pp != NULL) { - WOLFSSL_MSG("malloc error"); - return 0; - } - update_p = 0; - } - #endif - - /* Encode only if there is a buffer to encode into. */ - if ((pp != NULL) && (*pp != NULL)) { - /* Encode using the internal representations of r and s. */ - if (StoreECC_DSA_Sig(*pp, &len, (mp_int*)sig->r->internal, - (mp_int*)sig->s->internal) != MP_OKAY) { - /* No bytes encoded. */ - len = 0; - } - else if (update_p) { - /* Update pointer to after encoding. */ - *pp += len; - } - } - } - - return (int)len; -} - -/* Get the pointer to the fields of the ECDSA signature. - * - * r and s untouched when sig is NULL. - * - * @param [in] sig ECDSA signature object. - * @param [out] r R field of ECDSA signature as a BN. May be NULL. - * @param [out] s S field of ECDSA signature as a BN. May be NULL. - */ -void wolfSSL_ECDSA_SIG_get0(const WOLFSSL_ECDSA_SIG* sig, - const WOLFSSL_BIGNUM** r, const WOLFSSL_BIGNUM** s) -{ - /* Validate parameter. */ - if (sig != NULL) { - /* Return the r BN when pointer to return through. */ - if (r != NULL) { - *r = sig->r; - } - /* Return the s BN when pointer to return through. */ - if (s != NULL) { - *s = sig->s; - } - } -} - -/* Set the pointers to the fields of the ECDSA signature. - * - * @param [in, out] sig ECDSA signature object to update. - * @param [in] r R field of ECDSA signature as a BN. - * @param [in] s S field of ECDSA signature as a BN. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_ECDSA_SIG_set0(WOLFSSL_ECDSA_SIG* sig, WOLFSSL_BIGNUM* r, - WOLFSSL_BIGNUM* s) -{ - int ret = 1; - - /* Validate parameters. */ - if ((sig == NULL) || (r == NULL) || (s == NULL)) { - ret = 0; - } - - if (ret == 1) { - /* Dispose of old BN objects. */ - wolfSSL_BN_free(sig->r); - wolfSSL_BN_free(sig->s); - - /* Assign new BN objects. */ - sig->r = r; - sig->s = s; - } - - return ret; -} - -/* End ECDSA_SIG */ - -/* Start ECDSA */ - -/* Calculate maximum size of the DER encoded ECDSA signature for the curve. - * - * @param [in] key EC key. - * @return Size of DER encoded signature on success. - * @return 0 on error. - */ -int wolfSSL_ECDSA_size(const WOLFSSL_EC_KEY *key) -{ - int err = 0; - int len = 0; - const WOLFSSL_EC_GROUP *group = NULL; - int bits = 0; - - /* Validate parameter. */ - if (key == NULL) { - err = 1; - } - - /* Get group from key to get order bits. */ - if ((!err) && ((group = wolfSSL_EC_KEY_get0_group(key)) == NULL)) { - err = 1; - } - /* Get order bits of group. */ - if ((!err) && ((bits = wolfSSL_EC_GROUP_order_bits(group)) == 0)) { - /* Group is not set. */ - err = 1; - } - - if (!err) { - /* r and s are mod order. */ - int bytes = (bits + 7) / 8; /* Bytes needed to hold bits. */ - len = SIG_HEADER_SZ + /* 2*ASN_TAG + 2*LEN(ENUM) */ - ECC_MAX_PAD_SZ + /* possible leading zeroes in r and s */ - bytes + bytes; /* max r and s in bytes */ - } - - return len; -} - -/* Create ECDSA signature by signing digest with key. - * - * @param [in] dgst Digest to sign. - * @param [in] dLen Length of digest in bytes. - * @param [in] key EC key to sign with. - * @return ECDSA signature object on success. - * @return NULL on error. - */ -WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_do_sign(const unsigned char *dgst, int dLen, - WOLFSSL_EC_KEY *key) -{ - int err = 0; - WOLFSSL_ECDSA_SIG *sig = NULL; - WC_DECLARE_VAR(out, byte, ECC_BUFSIZE, 0); - unsigned int outLen = ECC_BUFSIZE; - - WOLFSSL_ENTER("wolfSSL_ECDSA_do_sign"); - - /* Validate parameters. */ - if ((dgst == NULL) || (key == NULL) || (key->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_ECDSA_do_sign Bad arguments"); - err = 1; - } - - /* Ensure internal EC key is set from external. */ - if ((!err) && (key->inSet == 0)) { - WOLFSSL_MSG("wolfSSL_ECDSA_do_sign No EC key internal set, do it"); - - if (SetECKeyInternal(key) != 1) { - WOLFSSL_MSG("wolfSSL_ECDSA_do_sign SetECKeyInternal failed"); - err = 1; - } - } - -#ifdef WOLFSSL_SMALL_STACK - if (!err) { - /* Allocate buffer to hold encoded signature. */ - out = (byte*)XMALLOC(outLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (out == NULL) { - err = 1; - } - } -#endif - - /* Sign the digest with the key to create encoded ECDSA signature. */ - if ((!err) && (wolfSSL_ECDSA_sign(0, dgst, dLen, out, &outLen, key) != 1)) { - err = 1; - } - - if (!err) { - const byte* p = out; - /* Decode the ECDSA signature into a new object. */ - sig = wolfSSL_d2i_ECDSA_SIG(NULL, &p, outLen); - } - - WC_FREE_VAR_EX(out, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - return sig; -} - -/* Verify ECDSA signature in the object using digest and key. - * - * Return code compliant with OpenSSL. - * - * @param [in] dgst Digest to verify. - * @param [in] dLen Length of the digest in bytes. - * @param [in] sig ECDSA signature object. - * @param [in] key EC key containing public key. - * @return 1 when signature is valid. - * @return 0 when signature is invalid. - * @return -1 on error. - */ -int wolfSSL_ECDSA_do_verify(const unsigned char *dgst, int dLen, - const WOLFSSL_ECDSA_SIG *sig, WOLFSSL_EC_KEY *key) -{ - int ret = 1; - int verified = 0; -#ifdef WOLF_CRYPTO_CB_ONLY_ECC - byte signature[ECC_MAX_SIG_SIZE]; - int signatureLen; - byte* p = signature; -#endif - - WOLFSSL_ENTER("wolfSSL_ECDSA_do_verify"); - - /* Validate parameters. */ - if ((dgst == NULL) || (sig == NULL) || (key == NULL) || - (key->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_ECDSA_do_verify Bad arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Ensure internal EC key is set from external. */ - if ((ret == 1) && (key->inSet == 0)) { - WOLFSSL_MSG("No EC key internal set, do it"); - - if (SetECKeyInternal(key) != 1) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 1) { -#ifndef WOLF_CRYPTO_CB_ONLY_ECC - /* Verify hash using digest, r and s as MP ints and internal EC key. */ - if (wc_ecc_verify_hash_ex((mp_int*)sig->r->internal, - (mp_int*)sig->s->internal, dgst, (word32)dLen, &verified, - (ecc_key *)key->internal) != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_verify_hash failed"); - ret = WOLFSSL_FATAL_ERROR; - } - else if (verified == 0) { - WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected"); - ret = 0; - } -#else - signatureLen = i2d_ECDSA_SIG(sig, &p); - if (signatureLen > 0) { - /* verify hash. expects to call wc_CryptoCb_EccVerify internally */ - ret = wc_ecc_verify_hash(signature, signatureLen, dgst, - (word32)dLen, &verified, (ecc_key*)key->internal); - if (ret != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_verify_hash failed"); - ret = WOLFSSL_FATAL_ERROR; - } - else if (verified == 0) { - WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected"); - ret = 0; - } - } -#endif /* WOLF_CRYPTO_CB_ONLY_ECC */ - } - - return ret; -} - -/* Sign the digest with the key to produce a DER encode signature. - * - * @param [in] type Digest algorithm used to create digest. Unused. - * @param [in] digest Digest of the message to sign. - * @param [in] digestSz Size of the digest in bytes. - * @param [out] sig Buffer to hold signature. - * @param [in, out] sigSz On in, size of buffer in bytes. - * On out, size of signatre in bytes. - * @param [in] key EC key containing private key. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_ECDSA_sign(int type, const unsigned char *digest, int digestSz, - unsigned char *sig, unsigned int *sigSz, WOLFSSL_EC_KEY *key) -{ - int ret = 1; - WC_RNG* rng = NULL; - WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - int initTmpRng = 0; - - WOLFSSL_ENTER("wolfSSL_ECDSA_sign"); - - /* Digest algorithm not used in DER encoding. */ - (void)type; - - /* Validate parameters. */ - if (key == NULL) { - ret = 0; - } - - if (ret == 1) { - /* Make an RNG - create local or get global. */ - rng = wolfssl_make_rng(tmpRng, &initTmpRng); - if (rng == NULL) { - ret = 0; - } - } - /* Sign the digest with the key using the RNG and put signature into buffer - * update sigSz to be actual length. - */ - if ((ret == 1) && (wc_ecc_sign_hash(digest, (word32)digestSz, sig, sigSz, - rng, (ecc_key*)key->internal) != 0)) { - ret = 0; - } - - if (initTmpRng) { - wc_FreeRng(rng); - WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); - } - - return ret; -} - -/* Verify the signature with the digest and key. - * - * @param [in] type Digest algorithm used to create digest. Unused. - * @param [in] digest Digest of the message to verify. - * @param [in] digestSz Size of the digest in bytes. - * @param [in] sig Buffer holding signature. - * @param [in] sigSz Size of signature data in bytes. - * @param [in] key EC key containing public key. - * @return 1 when signature is valid. - * @return 0 when signature is invalid or error. - */ -int wolfSSL_ECDSA_verify(int type, const unsigned char *digest, int digestSz, - const unsigned char *sig, int sigSz, WOLFSSL_EC_KEY *key) -{ - int ret = 1; - int verify = 0; - - WOLFSSL_ENTER("wolfSSL_ECDSA_verify"); - - /* Digest algorithm not used in DER encoding. */ - (void)type; - - /* Validate parameters. */ - if (key == NULL) { - ret = 0; - } - - /* Verify signature using digest and key. */ - if ((ret == 1) && (wc_ecc_verify_hash(sig, (word32)sigSz, digest, - (word32)digestSz, &verify, (ecc_key*)key->internal) != 0)) { - ret = 0; - } - /* When no error, verification may still have failed - check now. */ - if ((ret == 1) && (verify != 1)) { - WOLFSSL_MSG("wolfSSL_ECDSA_verify failed"); - ret = 0; - } - - return ret; -} - -/* End ECDSA */ - -/* Start ECDH */ - -#ifndef WOLF_CRYPTO_CB_ONLY_ECC -/* Compute the shared secret (key) using ECDH. - * - * KDF not supported. - * - * Return code compliant with OpenSSL. - * - * @param [out] out Buffer to hold key. - * @param [in] outLen Length of buffer in bytes. - * @param [in] pubKey Public key as an EC point. - * @param [in] privKey EC key holding a private key. - * @param [in] kdf Key derivation function to apply to secret. - * @return Length of computed key on success - * @return 0 on error. - */ -int wolfSSL_ECDH_compute_key(void *out, size_t outLen, - const WOLFSSL_EC_POINT *pubKey, WOLFSSL_EC_KEY *privKey, - void *(*kdf) (const void *in, size_t inlen, void *out, size_t *outLen)) -{ - int err = 0; - word32 len = 0; - ecc_key* key = NULL; -#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) - int setGlobalRNG = 0; -#endif - - /* TODO: support using the KDF. */ - (void)kdf; - - WOLFSSL_ENTER("wolfSSL_ECDH_compute_key"); - - /* Validate parameters. */ - if ((out == NULL) || (pubKey == NULL) || (pubKey->internal == NULL) || - (privKey == NULL) || (privKey->internal == NULL)) { - WOLFSSL_MSG("Bad function arguments"); - err = 1; - } - - /* Ensure internal EC key is set from external. */ - if ((!err) && (privKey->inSet == 0)) { - WOLFSSL_MSG("No EC key internal set, do it"); - - if (SetECKeyInternal(privKey) != 1) { - WOLFSSL_MSG("SetECKeyInternal failed"); - err = 1; - } - } - - if (!err) { - int ret; - - /* Get the internal key. */ - key = (ecc_key*)privKey->internal; - /* Set length into variable of type suitable for wolfSSL API. */ - len = (word32)outLen; - - #if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) - /* An RNG is needed. */ - if (key->rng == NULL) { - key->rng = wolfssl_make_global_rng(); - /* RNG set and needs to be unset. */ - setGlobalRNG = 1; - } - #endif - - PRIVATE_KEY_UNLOCK(); - /* Create secret using wolfSSL. */ - ret = wc_ecc_shared_secret_ex(key, (ecc_point*)pubKey->internal, - (byte *)out, &len); - PRIVATE_KEY_LOCK(); - if (ret != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_shared_secret failed"); - err = 1; - } - } - -#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) - /* Remove global from key. */ - if (setGlobalRNG) { - key->rng = NULL; - } -#endif - - if (err) { - /* Make returned value zero. */ - len = 0; - } - return (int)len; -} -#endif /* WOLF_CRYPTO_CB_ONLY_ECC */ - -/* End ECDH */ - -#ifndef NO_WOLFSSL_STUB -const WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_OpenSSL(void) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_OpenSSL"); - - return NULL; -} - -WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_METHOD_new( - const WOLFSSL_EC_KEY_METHOD *meth) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_new"); - - (void)meth; - - return NULL; -} - -void wolfSSL_EC_KEY_METHOD_free(WOLFSSL_EC_KEY_METHOD *meth) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_free"); - - (void)meth; -} - -void wolfSSL_EC_KEY_METHOD_set_init(WOLFSSL_EC_KEY_METHOD *meth, - void* a1, void* a2, void* a3, void* a4, void* a5, void* a6) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_set_init"); - - (void)meth; - (void)a1; - (void)a2; - (void)a3; - (void)a4; - (void)a5; - (void)a6; -} - -void wolfSSL_EC_KEY_METHOD_set_sign(WOLFSSL_EC_KEY_METHOD *meth, - void* a1, void* a2, void* a3) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_set_sign"); - - (void)meth; - (void)a1; - (void)a2; - (void)a3; -} - -const WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_get_method( - const WOLFSSL_EC_KEY *key) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_get_method"); - - (void)key; - - return NULL; -} - -int wolfSSL_EC_KEY_set_method(WOLFSSL_EC_KEY *key, - const WOLFSSL_EC_KEY_METHOD *meth) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_set_method"); - - (void)key; - (void)meth; - - return 0; -} - -#endif /* !NO_WOLFSSL_STUB */ - -#endif /* OPENSSL_EXTRA */ - -#endif /* HAVE_ECC */ - -/******************************************************************************* - * END OF EC API - ******************************************************************************/ /******************************************************************************* * START OF EC25519 API @@ -16529,7 +7113,8 @@ static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, if (res == 1) { /* Guestimate key size and PEM size. */ - if (pkcs8_encode(pkey, NULL, &keySz) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { + if (pkcs8_encode(pkey, NULL, &keySz) != + WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { res = 0; } } diff --git a/src/pk_ec.c b/src/pk_ec.c new file mode 100644 index 0000000000..7502030e24 --- /dev/null +++ b/src/pk_ec.c @@ -0,0 +1,5558 @@ +/* pk_ec.c + * + * Copyright (C) 2006-2025 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 3 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 + */ + +#include + +#include +#ifndef WC_NO_RNG + #include +#endif + +#ifdef HAVE_ECC + #include + #ifdef HAVE_SELFTEST + /* point compression types. */ + #define ECC_POINT_COMP_EVEN 0x02 + #define ECC_POINT_COMP_ODD 0x03 + #define ECC_POINT_UNCOMP 0x04 + #endif +#endif +#ifndef WOLFSSL_HAVE_ECC_KEY_GET_PRIV + /* FIPS build has replaced ecc.h. */ + #define wc_ecc_key_get_priv(key) (&((key)->k)) + #define WOLFSSL_HAVE_ECC_KEY_GET_PRIV +#endif + +#if !defined(WOLFSSL_PK_EC_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning pk_ec.c does not need to be compiled separately from ssl.c + #endif +#else + +/******************************************************************************* + * START OF EC API + ******************************************************************************/ + +#ifdef HAVE_ECC + +#if defined(OPENSSL_EXTRA) + +/* Start EC_curve */ + +/* Get the NIST name for the numeric ID. + * + * @param [in] nid Numeric ID of an EC curve. + * @return String representing NIST name of EC curve on success. + * @return NULL on error. + */ +const char* wolfSSL_EC_curve_nid2nist(int nid) +{ + const char* name = NULL; + const WOLF_EC_NIST_NAME* nist_name; + + /* Attempt to find the curve info matching the NID passed in. */ + for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { + if (nist_name->nid == nid) { + /* NID found - return name. */ + name = nist_name->name; + break; + } + } + + return name; +} + +/* Get the numeric ID for the NIST name. + * + * @param [in] name NIST name of EC curve. + * @return NID matching NIST name on success. + * @return 0 on error. + */ +int wolfSSL_EC_curve_nist2nid(const char* name) +{ + int nid = 0; + const WOLF_EC_NIST_NAME* nist_name; + + /* Attempt to find the curve info matching the NIST name passed in. */ + for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { + if (XSTRCMP(nist_name->name, name) == 0) { + /* Name found - return NID. */ + nid = nist_name->nid; + break; + } + } + + return nid; +} + +#endif /* OPENSSL_EXTRA */ + +/* End EC_curve */ + +/* Start EC_METHOD */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Get the EC method of the EC group object. + * + * wolfSSL doesn't use method tables. Implementation used is dependent upon + * the NID. + * + * @param [in] group EC group object. + * @return EC method. + */ +const WOLFSSL_EC_METHOD* wolfSSL_EC_GROUP_method_of( + const WOLFSSL_EC_GROUP *group) +{ + /* No method table used so just return the same object. */ + return group; +} + +/* Get field type for method. + * + * Only prime fields are supported. + * + * @param [in] meth EC method. + * @return X9.63 prime field NID on success. + * @return 0 on error. + */ +int wolfSSL_EC_METHOD_get_field_type(const WOLFSSL_EC_METHOD *meth) +{ + int nid = 0; + + if (meth != NULL) { + /* Only field type supported by code base. */ + nid = WC_NID_X9_62_prime_field; + } + + return nid; +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +/* End EC_METHOD */ + +/* Start EC_GROUP */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Converts ECC curve enum values in ecc_curve_id to the associated OpenSSL NID + * value. + * + * @param [in] n ECC curve id. + * @return ECC curve NID (OpenSSL compatible value). + */ +int EccEnumToNID(int n) +{ + WOLFSSL_ENTER("EccEnumToNID"); + + switch(n) { + case ECC_SECP192R1: + return WC_NID_X9_62_prime192v1; + case ECC_PRIME192V2: + return WC_NID_X9_62_prime192v2; + case ECC_PRIME192V3: + return WC_NID_X9_62_prime192v3; + case ECC_PRIME239V1: + return WC_NID_X9_62_prime239v1; + case ECC_PRIME239V2: + return WC_NID_X9_62_prime239v2; + case ECC_PRIME239V3: + return WC_NID_X9_62_prime239v3; + case ECC_SECP256R1: + return WC_NID_X9_62_prime256v1; + case ECC_SECP112R1: + return WC_NID_secp112r1; + case ECC_SECP112R2: + return WC_NID_secp112r2; + case ECC_SECP128R1: + return WC_NID_secp128r1; + case ECC_SECP128R2: + return WC_NID_secp128r2; + case ECC_SECP160R1: + return WC_NID_secp160r1; + case ECC_SECP160R2: + return WC_NID_secp160r2; + case ECC_SECP224R1: + return WC_NID_secp224r1; + case ECC_SECP384R1: + return WC_NID_secp384r1; + case ECC_SECP521R1: + return WC_NID_secp521r1; + case ECC_SECP160K1: + return WC_NID_secp160k1; + case ECC_SECP192K1: + return WC_NID_secp192k1; + case ECC_SECP224K1: + return WC_NID_secp224k1; + case ECC_SECP256K1: + return WC_NID_secp256k1; + case ECC_BRAINPOOLP160R1: + return WC_NID_brainpoolP160r1; + case ECC_BRAINPOOLP192R1: + return WC_NID_brainpoolP192r1; + case ECC_BRAINPOOLP224R1: + return WC_NID_brainpoolP224r1; + case ECC_BRAINPOOLP256R1: + return WC_NID_brainpoolP256r1; + case ECC_BRAINPOOLP320R1: + return WC_NID_brainpoolP320r1; + case ECC_BRAINPOOLP384R1: + return WC_NID_brainpoolP384r1; + case ECC_BRAINPOOLP512R1: + return WC_NID_brainpoolP512r1; + #ifdef WOLFSSL_SM2 + case ECC_SM2P256V1: + return WC_NID_sm2; + #endif + default: + WOLFSSL_MSG("NID not found"); + return WOLFSSL_FATAL_ERROR; + } +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/* Converts OpenSSL NID of EC curve to the enum value in ecc_curve_id + * + * Used by ecc_sets[]. + * + * @param [in] n OpenSSL NID of EC curve. + * @return wolfCrypt EC curve id. + * @return -1 on error. + */ +int NIDToEccEnum(int nid) +{ + int id; + + WOLFSSL_ENTER("NIDToEccEnum"); + + switch (nid) { + case WC_NID_X9_62_prime192v1: + id = ECC_SECP192R1; + break; + case WC_NID_X9_62_prime192v2: + id = ECC_PRIME192V2; + break; + case WC_NID_X9_62_prime192v3: + id = ECC_PRIME192V3; + break; + case WC_NID_X9_62_prime239v1: + id = ECC_PRIME239V1; + break; + case WC_NID_X9_62_prime239v2: + id = ECC_PRIME239V2; + break; + case WC_NID_X9_62_prime239v3: + id = ECC_PRIME239V3; + break; + case WC_NID_X9_62_prime256v1: + id = ECC_SECP256R1; + break; + case WC_NID_secp112r1: + id = ECC_SECP112R1; + break; + case WC_NID_secp112r2: + id = ECC_SECP112R2; + break; + case WC_NID_secp128r1: + id = ECC_SECP128R1; + break; + case WC_NID_secp128r2: + id = ECC_SECP128R2; + break; + case WC_NID_secp160r1: + id = ECC_SECP160R1; + break; + case WC_NID_secp160r2: + id = ECC_SECP160R2; + break; + case WC_NID_secp224r1: + id = ECC_SECP224R1; + break; + case WC_NID_secp384r1: + id = ECC_SECP384R1; + break; + case WC_NID_secp521r1: + id = ECC_SECP521R1; + break; + case WC_NID_secp160k1: + id = ECC_SECP160K1; + break; + case WC_NID_secp192k1: + id = ECC_SECP192K1; + break; + case WC_NID_secp224k1: + id = ECC_SECP224K1; + break; + case WC_NID_secp256k1: + id = ECC_SECP256K1; + break; + case WC_NID_brainpoolP160r1: + id = ECC_BRAINPOOLP160R1; + break; + case WC_NID_brainpoolP192r1: + id = ECC_BRAINPOOLP192R1; + break; + case WC_NID_brainpoolP224r1: + id = ECC_BRAINPOOLP224R1; + break; + case WC_NID_brainpoolP256r1: + id = ECC_BRAINPOOLP256R1; + break; + case WC_NID_brainpoolP320r1: + id = ECC_BRAINPOOLP320R1; + break; + case WC_NID_brainpoolP384r1: + id = ECC_BRAINPOOLP384R1; + break; + case WC_NID_brainpoolP512r1: + id = ECC_BRAINPOOLP512R1; + break; + default: + WOLFSSL_MSG("NID not found"); + /* -1 on error. */ + id = WOLFSSL_FATAL_ERROR; + } + + return id; +} + +/* Set the fields of the EC group based on numeric ID. + * + * @param [in, out] group EC group. + * @param [in] nid Numeric ID of an EC curve. + */ +static void ec_group_set_nid(WOLFSSL_EC_GROUP* group, int nid) +{ + int eccEnum; + int realNid; + + /* Convert ecc_curve_id enum to NID. */ + if ((realNid = EccEnumToNID(nid)) != -1) { + /* ecc_curve_id enum passed in - have real NID value set. */ + eccEnum = nid; + } + else { + /* NID passed in is OpenSSL type. */ + realNid = nid; + /* Convert NID to ecc_curve_id enum. */ + eccEnum = NIDToEccEnum(nid); + } + + /* Set the numeric ID of the curve */ + group->curve_nid = realNid; + /* Initialize index to -1 (i.e. wolfCrypt doesn't support curve). */ + group->curve_idx = -1; + + /* Find index and OID sum for curve if wolfCrypt supports it. */ + if (eccEnum != -1) { + int i; + + /* Find id and set the internal curve idx and OID sum. */ + for (i = 0; ecc_sets[i].size != 0; i++) { + if (ecc_sets[i].id == eccEnum) { + /* Found id in wolfCrypt supported EC curves. */ + group->curve_idx = i; + group->curve_oid = (int)ecc_sets[i].oidSum; + break; + } + } + } +} + +/* Create a new EC group with the numeric ID for an EC curve. + * + * @param [in] nid Numeric ID of an EC curve. + * @return New, allocated EC group on success. + * @return NULL on error. + */ +WOLFSSL_EC_GROUP* wolfSSL_EC_GROUP_new_by_curve_name(int nid) +{ + int err = 0; + WOLFSSL_EC_GROUP* group; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_new_by_curve_name"); + + /* Allocate EC group. */ + group = (WOLFSSL_EC_GROUP*)XMALLOC(sizeof(WOLFSSL_EC_GROUP), NULL, + DYNAMIC_TYPE_ECC); + if (group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_new_by_curve_name malloc failure"); + err = 1; + } + + if (!err) { + /* Reset all fields. */ + XMEMSET(group, 0, sizeof(WOLFSSL_EC_GROUP)); + + /* Set the fields of group based on the numeric ID. */ + ec_group_set_nid(group, nid); + } + + return group; +} +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Dispose of the EC group. + * + * Cannot use group after this call. + * + * @param [in] group EC group to free. + */ +void wolfSSL_EC_GROUP_free(WOLFSSL_EC_GROUP *group) +{ + WOLFSSL_ENTER("wolfSSL_EC_GROUP_free"); + + /* Dispose of EC group. */ + XFREE(group, NULL, DYNAMIC_TYPE_ECC); +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#ifdef OPENSSL_EXTRA +#ifndef NO_BIO + +/* Creates an EC group from the DER encoding. + * + * Only named curves supported. + * + * @param [out] group Reference to EC group object. + * @param [in] in Buffer holding DER encoding of curve. + * @param [in] inSz Length of data in buffer. + * @return EC group on success. + * @return NULL on error. + */ +static WOLFSSL_EC_GROUP* wolfssl_ec_group_d2i(WOLFSSL_EC_GROUP** group, + const unsigned char** in_pp, long inSz) +{ + int err = 0; + WOLFSSL_EC_GROUP* ret = NULL; + word32 idx = 0; + word32 oid = 0; + int id = 0; + const unsigned char* in; + + if (in_pp == NULL || *in_pp == NULL) + return NULL; + + in = *in_pp; + + /* Use the group passed in. */ + if ((group != NULL) && (*group != NULL)) { + ret = *group; + } + + /* Only support named curves. */ + if (in[0] != ASN_OBJECT_ID) { + WOLFSSL_ERROR_MSG("Invalid or unsupported encoding"); + err = 1; + } + /* Decode the OBJECT ID - expecting an EC curve OID. */ + if ((!err) && (GetObjectId(in, &idx, &oid, oidCurveType, (word32)inSz) != + 0)) { + err = 1; + } + if (!err) { + /* Get the internal ID for OID. */ + id = wc_ecc_get_oid(oid, NULL, NULL); + if (id < 0) { + err = 1; + } + } + if (!err) { + /* Get the NID for the internal ID. */ + int nid = EccEnumToNID(id); + if (ret == NULL) { + /* Create a new EC group with the numeric ID. */ + ret = wolfSSL_EC_GROUP_new_by_curve_name(nid); + if (ret == NULL) { + err = 1; + } + } + else { + ec_group_set_nid(ret, nid); + } + } + if ((!err) && (group != NULL)) { + /* Return the EC group through reference. */ + *group = ret; + } + + if (err) { + if ((ret != NULL) && (ret != *group)) { + wolfSSL_EC_GROUP_free(ret); + } + ret = NULL; + } + else { + *in_pp += idx; + } + return ret; +} + +/* Creates a new EC group from the PEM encoding in the BIO. + * + * @param [in] bio BIO to read PEM encoding from. + * @param [out] group Reference to EC group object. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * @return EC group on success. + * @return NULL on error. + */ +WOLFSSL_EC_GROUP* wolfSSL_PEM_read_bio_ECPKParameters(WOLFSSL_BIO* bio, + WOLFSSL_EC_GROUP** group, wc_pem_password_cb* cb, void* pass) +{ + int err = 0; + WOLFSSL_EC_GROUP* ret = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + if (bio == NULL) { + err = 1; + } + + /* Read parameters from BIO and convert PEM to DER. */ + if ((!err) && (pem_read_bio_key(bio, cb, pass, ECC_PARAM_TYPE, + &keyFormat, &der) < 0)) { + err = 1; + } + if (!err) { + /* Create EC group from DER encoding. */ + const byte** p = (const byte**)&der->buffer; + ret = wolfssl_ec_group_d2i(group, p, der->length); + if (ret == NULL) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_GROUP"); + } + } + + /* Dispose of any allocated data. */ + FreeDer(&der); + return ret; +} + +WOLFSSL_EC_GROUP *wolfSSL_d2i_ECPKParameters(WOLFSSL_EC_GROUP **out, + const unsigned char **in, long len) +{ + return wolfssl_ec_group_d2i(out, in, len); +} + +int wolfSSL_i2d_ECPKParameters(const WOLFSSL_EC_GROUP* grp, unsigned char** pp) +{ + unsigned char* out = NULL; + int len = 0; + int idx; + const byte* oid = NULL; + word32 oidSz = 0; + + if (grp == NULL || !wc_ecc_is_valid_idx(grp->curve_idx) || + grp->curve_idx < 0) + return WOLFSSL_FATAL_ERROR; + + /* Get the actual DER encoding of the OID. ecc_sets[grp->curve_idx].oid + * is just the numerical representation. */ + if (wc_ecc_get_oid((word32)grp->curve_oid, &oid, &oidSz) < 0) + return WOLFSSL_FATAL_ERROR; + + len = SetObjectId((int)oidSz, NULL) + (int)oidSz; + + if (pp == NULL) + return len; + + if (*pp == NULL) { + out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1); + if (out == NULL) + return WOLFSSL_FATAL_ERROR; + } + else { + out = *pp; + } + + idx = SetObjectId((int)oidSz, out); + XMEMCPY(out + idx, oid, oidSz); + if (*pp == NULL) + *pp = out; + else + *pp += len; + + return len; +} +#endif /* !NO_BIO */ + +#if defined(OPENSSL_ALL) && !defined(NO_CERTS) +/* Copy an EC group. + * + * Only used by wolfSSL_EC_KEY_dup at this time. + * + * @param [in, out] dst Destination EC group. + * @param [in] src Source EC group. + * @return 0 on success. + */ +static int wolfssl_ec_group_copy(WOLFSSL_EC_GROUP* dst, + const WOLFSSL_EC_GROUP* src) +{ + /* Copy the fields. */ + dst->curve_idx = src->curve_idx; + dst->curve_nid = src->curve_nid; + dst->curve_oid = src->curve_oid; + + return 0; +} +#endif /* OPENSSL_ALL && !NO_CERTS */ + +/* Copies ecc_key into new WOLFSSL_EC_GROUP object + * + * @param [in] src EC group to duplicate. + * + * @return EC group on success. + * @return NULL on error. + */ +WOLFSSL_EC_GROUP* wolfSSL_EC_GROUP_dup(const WOLFSSL_EC_GROUP *src) +{ + WOLFSSL_EC_GROUP* newGroup = NULL; + + if (src != NULL) { + /* Create new group base on NID in original EC group. */ + newGroup = wolfSSL_EC_GROUP_new_by_curve_name(src->curve_nid); + } + + return newGroup; +} + +/* Compare two EC groups. + * + * Return code compliant with OpenSSL. + * + * @param [in] a First EC group. + * @param [in] b Second EC group. + * @param [in] ctx Big number context to use when comparing fields. Unused. + * + * @return 0 if equal. + * @return 1 if not equal. + * @return -1 on error. + */ +int wolfSSL_EC_GROUP_cmp(const WOLFSSL_EC_GROUP *a, const WOLFSSL_EC_GROUP *b, + WOLFSSL_BN_CTX *ctx) +{ + int ret; + + /* No BN operations performed. */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_cmp"); + + /* Validate parameters. */ + if ((a == NULL) || (b == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_cmp Bad arguments"); + /* Return error value. */ + ret = WOLFSSL_FATAL_ERROR; + } + /* Compare NID and wolfSSL curve index. */ + else { + /* 0 when same, 1 when not. */ + ret = ((a->curve_nid == b->curve_nid) && + (a->curve_idx == b->curve_idx)) ? 0 : 1; + } + + return ret; +} + +#ifndef NO_WOLFSSL_STUB +/* Set the ASN.1 flag that indicate encoding of curve. + * + * Stub function - flag not used elsewhere. + * Always encoded as named curve. + * + * @param [in] group EC group to modify. + * @param [in] flag ASN.1 flag to set. Valid values: + * OPENSSL_EC_EXPLICIT_CURVE, OPENSSL_EC_NAMED_CURVE + */ +void wolfSSL_EC_GROUP_set_asn1_flag(WOLFSSL_EC_GROUP *group, int flag) +{ + (void)group; + (void)flag; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_set_asn1_flag"); + WOLFSSL_STUB("EC_GROUP_set_asn1_flag"); +} +#endif + +/* Get the curve NID of the group. + * + * Return code compliant with OpenSSL. + * + * @param [in] group EC group. + * @return Curve NID on success. + * @return 0 on error. + */ +int wolfSSL_EC_GROUP_get_curve_name(const WOLFSSL_EC_GROUP *group) +{ + int nid = 0; + WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_curve_name"); + + if (group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_curve_name Bad arguments"); + } + else { + nid = group->curve_nid; + } + + return nid; +} + +/* Get the degree (curve size in bits) of the EC group. + * + * Return code compliant with OpenSSL. + * + * @return Degree of the curve on success. + * @return 0 on error. + */ +int wolfSSL_EC_GROUP_get_degree(const WOLFSSL_EC_GROUP *group) +{ + int degree = 0; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_degree"); + + if (group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_degree Bad arguments"); + } + else { + switch (group->curve_nid) { + case WC_NID_secp112r1: + case WC_NID_secp112r2: + degree = 112; + break; + case WC_NID_secp128r1: + case WC_NID_secp128r2: + degree = 128; + break; + case WC_NID_secp160k1: + case WC_NID_secp160r1: + case WC_NID_secp160r2: + case WC_NID_brainpoolP160r1: + degree = 160; + break; + case WC_NID_secp192k1: + case WC_NID_brainpoolP192r1: + case WC_NID_X9_62_prime192v1: + case WC_NID_X9_62_prime192v2: + case WC_NID_X9_62_prime192v3: + degree = 192; + break; + case WC_NID_secp224k1: + case WC_NID_secp224r1: + case WC_NID_brainpoolP224r1: + degree = 224; + break; + case WC_NID_X9_62_prime239v1: + case WC_NID_X9_62_prime239v2: + case WC_NID_X9_62_prime239v3: + degree = 239; + break; + case WC_NID_secp256k1: + case WC_NID_brainpoolP256r1: + case WC_NID_X9_62_prime256v1: + degree = 256; + break; + case WC_NID_brainpoolP320r1: + degree = 320; + break; + case WC_NID_secp384r1: + case WC_NID_brainpoolP384r1: + degree = 384; + break; + case WC_NID_brainpoolP512r1: + degree = 512; + break; + case WC_NID_secp521r1: + degree = 521; + break; + } + } + + return degree; +} +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/* Get the length of the order in bits of the EC group. + * + * TODO: consider switch statement or calculating directly from hex string + * array instead of using mp_int. + * + * @param [in] group EC group. + * @return Length of order in bits on success. + * @return 0 on error. + */ +int wolfSSL_EC_GROUP_order_bits(const WOLFSSL_EC_GROUP *group) +{ + int ret = 0; + WC_DECLARE_VAR(order, mp_int, 1, 0); + + /* Validate parameter. */ + if ((group == NULL) || (group->curve_idx < 0)) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_order_bits NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 0) { + /* Allocate memory for mp_int that will hold order value. */ + order = (mp_int *)XMALLOC(sizeof(*order), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (order == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } +#endif + + if (ret == 0) { + /* Initialize mp_int. */ + ret = mp_init(order); + } + + if (ret == 0) { + /* Read hex string of order from wolfCrypt array of curves. */ + ret = mp_read_radix(order, ecc_sets[group->curve_idx].order, + MP_RADIX_HEX); + if (ret == 0) { + /* Get bits of order. */ + ret = mp_count_bits(order); + } + /* Clear and free mp_int. */ + mp_clear(order); + } + + WC_FREE_VAR_EX(order, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + /* Convert error code to length of 0. */ + if (ret < 0) { + ret = 0; + } + + return ret; +} +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + +#if defined(OPENSSL_EXTRA) +/* Get the order of the group as a BN. + * + * Return code compliant with OpenSSL. + * + * @param [in] group EC group. + * @param [in, out] order BN to hold order value. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_GROUP_get_order(const WOLFSSL_EC_GROUP *group, + WOLFSSL_BIGNUM *order, WOLFSSL_BN_CTX *ctx) +{ + int ret = 1; + mp_int* mp = NULL; + + /* No BN operations performed - done with mp_int in BN. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (order == NULL) || (order->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order NULL error"); + ret = 0; + } + + if (ret == 1 && + (group->curve_idx < 0 || !wc_ecc_is_valid_idx(group->curve_idx))) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order Bad group idx"); + ret = 0; + } + + if (ret == 1) { + mp = (mp_int*)order->internal; + } + /* Initialize */ + if ((ret == 1) && (mp_init(mp) != MP_OKAY)) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_init failure"); + ret = 0; + } + /* Read hex string of order from wolfCrypt array of curves. */ + if ((ret == 1) && (mp_read_radix(mp, ecc_sets[group->curve_idx].order, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_read order failure"); + /* Zero out any partial value but don't free. */ + mp_zero(mp); + ret = 0; + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +/* End EC_GROUP */ + +/* Start EC_POINT */ + +#if defined(OPENSSL_EXTRA) + +/* Set data of EC point into internal, wolfCrypt EC point object. + * + * EC_POINT Openssl -> WolfSSL + * + * @param [in, out] p EC point to update. + * @return 1 on success. + * @return -1 on failure. + */ +static int ec_point_internal_set(WOLFSSL_EC_POINT *p) +{ + int ret = 1; + + WOLFSSL_ENTER("ec_point_internal_set"); + + /* Validate parameter. */ + if ((p == NULL) || (p->internal == NULL)) { + WOLFSSL_MSG("ECPoint NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + /* Get internal point as a wolfCrypt EC point. */ + ecc_point* point = (ecc_point*)p->internal; + + /* Set X ordinate if available. */ + if ((p->X != NULL) && (wolfssl_bn_get_value(p->X, point->x) != 1)) { + WOLFSSL_MSG("ecc point X error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Set Y ordinate if available. */ + if ((ret == 1) && (p->Y != NULL) && (wolfssl_bn_get_value(p->Y, + point->y) != 1)) { + WOLFSSL_MSG("ecc point Y error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Set Z ordinate if available. */ + if ((ret == 1) && (p->Z != NULL) && (wolfssl_bn_get_value(p->Z, + point->z) != 1)) { + WOLFSSL_MSG("ecc point Z error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Internal values set when operations succeeded. */ + p->inSet = (ret == 1); + } + + return ret; +} + +/* Set data of internal, wolfCrypt EC point object into EC point. + * + * EC_POINT WolfSSL -> OpenSSL + * + * @param [in, out] p EC point to update. + * @return 1 on success. + * @return -1 on failure. + */ +static int ec_point_external_set(WOLFSSL_EC_POINT *p) +{ + int ret = 1; + + WOLFSSL_ENTER("ec_point_external_set"); + + /* Validate parameter. */ + if ((p == NULL) || (p->internal == NULL)) { + WOLFSSL_MSG("ECPoint NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + /* Get internal point as a wolfCrypt EC point. */ + ecc_point* point = (ecc_point*)p->internal; + + /* Set X ordinate. */ + if (wolfssl_bn_set_value(&p->X, point->x) != 1) { + WOLFSSL_MSG("ecc point X error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Set Y ordinate. */ + if ((ret == 1) && (wolfssl_bn_set_value(&p->Y, point->y) != 1)) { + WOLFSSL_MSG("ecc point Y error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Set Z ordinate. */ + if ((ret == 1) && (wolfssl_bn_set_value(&p->Z, point->z) != 1)) { + WOLFSSL_MSG("ecc point Z error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* External values set when operations succeeded. */ + p->exSet = (ret == 1); + } + + return ret; +} + +/* Setup internals of EC point. + * + * Assumes point is not NULL. + * + * @param [in, out] point EC point to update. + * @return 1 on success. + * @return 0 on failure. + */ +static int ec_point_setup(const WOLFSSL_EC_POINT *point) { + int ret = 1; + + /* Check if internal values need setting. */ + if (!point->inSet) { + WOLFSSL_MSG("No ECPoint internal set, do it"); + + /* Forcing to non-constant type to update internals. */ + if (ec_point_internal_set((WOLFSSL_EC_POINT *)point) != 1) { + WOLFSSL_MSG("ec_point_internal_set failed"); + ret = 0; + } + } + + return ret; +} + +/* Create a new EC point from the group. + * + * @param [in] group EC group. + * @return EC point on success. + * @return NULL on error. + */ +WOLFSSL_EC_POINT* wolfSSL_EC_POINT_new(const WOLFSSL_EC_GROUP* group) +{ + int err = 0; + WOLFSSL_EC_POINT* point = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_new"); + + /* Validate parameter. */ + if (group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new NULL error"); + err = 1; + } + + if (!err) { + /* Allocate memory for new EC point. */ + point = (WOLFSSL_EC_POINT*)XMALLOC(sizeof(WOLFSSL_EC_POINT), NULL, + DYNAMIC_TYPE_ECC); + if (point == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new malloc ecc point failure"); + err = 1; + } + } + if (!err) { + /* Clear fields of EC point. */ + XMEMSET(point, 0, sizeof(WOLFSSL_EC_POINT)); + + /* Allocate internal EC point. */ + point->internal = wc_ecc_new_point(); + if (point->internal == NULL) { + WOLFSSL_MSG("ecc_new_point failure"); + err = 1; + } + } + + if (err) { + XFREE(point, NULL, DYNAMIC_TYPE_ECC); + point = NULL; + } + return point; +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Dispose of the EC point. + * + * Cannot use point after this call. + * + * @param [in, out] point EC point to free. + */ +void wolfSSL_EC_POINT_free(WOLFSSL_EC_POINT *point) +{ + WOLFSSL_ENTER("wolfSSL_EC_POINT_free"); + + if (point != NULL) { + if (point->internal != NULL) { + wc_ecc_del_point((ecc_point*)point->internal); + point->internal = NULL; + } + + /* Free ordinates. */ + wolfSSL_BN_free(point->X); + wolfSSL_BN_free(point->Y); + wolfSSL_BN_free(point->Z); + /* Clear fields. */ + point->X = NULL; + point->Y = NULL; + point->Z = NULL; + point->inSet = 0; + point->exSet = 0; + + /* Dispose of EC point. */ + XFREE(point, NULL, DYNAMIC_TYPE_ECC); + } +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#ifdef OPENSSL_EXTRA + +/* Clear and dispose of the EC point. + * + * Cannot use point after this call. + * + * @param [in, out] point EC point to free. + */ +void wolfSSL_EC_POINT_clear_free(WOLFSSL_EC_POINT *point) +{ + WOLFSSL_ENTER("wolfSSL_EC_POINT_clear_free"); + + if (point != NULL) { + if (point->internal != NULL) { + /* Force internal point to be zeros. */ + #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + wc_ecc_forcezero_point((ecc_point*)point->internal); + #else + ecc_point* p = (ecc_point*)point->internal; + mp_forcezero(p->x); + mp_forcezero(p->y); + mp_forcezero(p->z); + #endif + wc_ecc_del_point((ecc_point*)point->internal); + point->internal = NULL; + } + + /* Clear the ordinates before freeing. */ + wolfSSL_BN_clear_free(point->X); + wolfSSL_BN_clear_free(point->Y); + wolfSSL_BN_clear_free(point->Z); + /* Clear fields. */ + point->X = NULL; + point->Y = NULL; + point->Z = NULL; + point->inSet = 0; + point->exSet = 0; + + /* Dispose of EC point. */ + XFREE(point, NULL, DYNAMIC_TYPE_ECC); + } +} + +/* Print out the internals of EC point in debug and when logging callback set. + * + * Not an OpenSSL API. + * + * TODO: Use WOLFSSL_MSG_EX()? + * + * @param [in] msg Message to prepend. + * @param [in] point EC point to print. + */ +void wolfSSL_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT *point) +{ +#if defined(DEBUG_WOLFSSL) + char *num; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_dump"); + + /* Only print when debugging on. */ + if (WOLFSSL_IS_DEBUG_ON()) { + if (point == NULL) { + /* No point passed in so just put out "NULL". */ + WOLFSSL_MSG_EX("%s = NULL\n", msg); + } + else { + /* Put out message and status of internal/external data set. */ + WOLFSSL_MSG_EX("%s:\n\tinSet=%d, exSet=%d\n", msg, point->inSet, + point->exSet); + /* Get x-ordinate as a hex string and print. */ + num = wolfSSL_BN_bn2hex(point->X); + WOLFSSL_MSG_EX("\tX = %s\n", num); + XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); + /* Get x-ordinate as a hex string and print. */ + num = wolfSSL_BN_bn2hex(point->Y); + WOLFSSL_MSG_EX("\tY = %s\n", num); + XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); + /* Get z-ordinate as a hex string and print. */ + num = wolfSSL_BN_bn2hex(point->Z); + WOLFSSL_MSG_EX("\tZ = %s\n", num); + XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); + } + } +#else + (void)msg; + (void)point; +#endif +} + +/* Convert EC point to hex string that as either uncompressed or compressed. + * + * ECC point compression types were not included in selftest ecc.h + * + * @param [in] group EC group for point. + * @param [in] point EC point to encode. + * @param [in] form Format of encoding. Valid values: + * POINT_CONVERSION_UNCOMPRESSED, POINT_CONVERSION_COMPRESSED + * @param [in] ctx Context to use for BN operations. Unused. + * @return Allocated hex string on success. + * @return NULL on error. + */ +char* wolfSSL_EC_POINT_point2hex(const WOLFSSL_EC_GROUP* group, + const WOLFSSL_EC_POINT* point, int form, WOLFSSL_BN_CTX* ctx) +{ + static const char* hexDigit = "0123456789ABCDEF"; + char* hex = NULL; + int i; + int sz = 0; + int len = 0; + int err = 0; + + /* No BN operations performed. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL)) { + err = 1; + } + /* Get curve id expects a positive index. */ + if ((!err) && (group->curve_idx < 0)) { + err = 1; + } + + if (!err) { + /* Get curve id to look up ordinate size. */ + int id = wc_ecc_get_curve_id(group->curve_idx); + /* Get size of ordinate. */ + if ((sz = wc_ecc_get_curve_size_from_id(id)) < 0) { + err = 1; + } + } + if (!err) { + /* [] */ + len = sz + 1; + if (form == WC_POINT_CONVERSION_UNCOMPRESSED) { + /* Include y ordinate when uncompressed. */ + len += sz; + } + + /* Hex string: allocate 2 bytes to represent each byte plus 1 for '\0'. + */ + hex = (char*)XMALLOC((size_t)(2 * len + 1), NULL, DYNAMIC_TYPE_ECC); + if (hex == NULL) { + err = 1; + } + } + if (!err) { + /* Make bytes all zeros to allow for ordinate values less than max size. + */ + XMEMSET(hex, 0, (size_t)(2 * len + 1)); + + /* Calculate offset as leading zeros not encoded. */ + i = sz - mp_unsigned_bin_size((mp_int*)point->X->internal) + 1; + /* Put in x-ordinate after format byte. */ + if (mp_to_unsigned_bin((mp_int*)point->X->internal, (byte*)(hex + i)) < + 0) { + err = 1; + } + } + if (!err) { + if (form == WC_POINT_CONVERSION_COMPRESSED) { + /* Compressed format byte value dependent on whether y-ordinate is + * odd. + */ + hex[0] = mp_isodd((mp_int*)point->Y->internal) ? + ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN; + /* No y-ordinate. */ + } + else { + /* Put in uncompressed format byte. */ + hex[0] = ECC_POINT_UNCOMP; + /* Calculate offset as leading zeros not encoded. */ + i = 1 + 2 * sz - mp_unsigned_bin_size((mp_int*)point->Y->internal); + /* Put in y-ordinate after x-ordinate. */ + if (mp_to_unsigned_bin((mp_int*)point->Y->internal, + (byte*)(hex + i)) < 0) { + err = 1; + } + } + } + if (!err) { + /* Convert binary encoding to hex string. */ + /* Start at end so as not to overwrite. */ + for (i = len-1; i >= 0; i--) { + /* Get byte value and store has hex string. */ + byte b = (byte)hex[i]; + hex[i * 2 + 1] = hexDigit[b & 0xf]; + hex[i * 2 ] = hexDigit[b >> 4]; + } + /* Memset put trailing zero or '\0' on end of string. */ + } + + if (err && (hex != NULL)) { + /* Dispose of allocated data not being returned. */ + XFREE(hex, NULL, DYNAMIC_TYPE_ECC); + hex = NULL; + } + /* Return hex string encoding. */ + return hex; +} + +static size_t hex_to_bytes(const char *hex, unsigned char *output, size_t sz) +{ + word32 i; + for (i = 0; i < sz; i++) { + signed char ch1, ch2; + ch1 = HexCharToByte(hex[i * 2]); + ch2 = HexCharToByte(hex[i * 2 + 1]); + if ((ch1 < 0) || (ch2 < 0)) { + WOLFSSL_MSG("hex_to_bytes: syntax error"); + return 0; + } + output[i] = (unsigned char)((ch1 << 4) + ch2); + } + return sz; +} + +WOLFSSL_EC_POINT* wolfSSL_EC_POINT_hex2point(const WOLFSSL_EC_GROUP *group, + const char *hex, WOLFSSL_EC_POINT*p, WOLFSSL_BN_CTX *ctx) +{ + /* for uncompressed mode */ + size_t str_sz; + WOLFSSL_BIGNUM *Gx = NULL; + WOLFSSL_BIGNUM *Gy = NULL; + char strGx[MAX_ECC_BYTES * 2 + 1]; + + /* for compressed mode */ + int key_sz; + byte *octGx = (byte *)strGx; /* octGx[MAX_ECC_BYTES] */ + + int p_alloc = 0; + int ret; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_hex2point"); + + if (group == NULL || hex == NULL || ctx == NULL) + return NULL; + + if (p == NULL) { + if ((p = wolfSSL_EC_POINT_new(group)) == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new"); + goto err; + } + p_alloc = 1; + } + + key_sz = (wolfSSL_EC_GROUP_get_degree(group) + 7) / 8; + if (hex[0] == '0' && hex[1] == '4') { /* uncompressed mode */ + str_sz = (size_t)key_sz * 2; + + XMEMSET(strGx, 0x0, str_sz + 1); + XMEMCPY(strGx, hex + 2, str_sz); + + if (wolfSSL_BN_hex2bn(&Gx, strGx) == 0) + goto err; + + if (wolfSSL_BN_hex2bn(&Gy, hex + 2 + str_sz) == 0) + goto err; + + ret = wolfSSL_EC_POINT_set_affine_coordinates_GFp + (group, p, Gx, Gy, ctx); + + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp"); + goto err; + } + } + else if (hex[0] == '0' && (hex[1] == '2' || hex[1] == '3')) { + size_t sz = XSTRLEN(hex + 2) / 2; + /* compressed mode */ + octGx[0] = ECC_POINT_COMP_ODD; + if (hex_to_bytes(hex + 2, octGx + 1, sz) != sz) { + goto err; + } + if (wolfSSL_ECPoint_d2i(octGx, (word32)key_sz + 1, group, p) + != WOLFSSL_SUCCESS) { + goto err; + } + } + else + goto err; + + wolfSSL_BN_free(Gx); + wolfSSL_BN_free(Gy); + return p; + +err: + wolfSSL_BN_free(Gx); + wolfSSL_BN_free(Gy); + if (p_alloc) { + wolfSSL_EC_POINT_free(p); + } + return NULL; + +} + +/* Encode the EC point as an uncompressed point in DER. + * + * Return code compliant with OpenSSL. + * Not OpenSSL API. + * + * @param [in] group EC group point belongs to. + * @param [in] point EC point to encode. + * @param [out] out Buffer to encode into. May be NULL. + * @param [in, out] len On in, length of buffer in bytes. + * On out, length of encoding in bytes. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_ECPoint_i2d(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *point, unsigned char *out, unsigned int *len) +{ + int res = 1; + + WOLFSSL_ENTER("wolfSSL_ECPoint_i2d"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL) || (len == NULL)) { + WOLFSSL_MSG("wolfSSL_ECPoint_i2d NULL error"); + res = 0; + } + + /* Ensure points internals are set up. */ + if ((res == 1) && (ec_point_setup(point) != 1)) { + res = 0; + } + + /* Dump the point if encoding. */ + if ((res == 1) && (out != NULL)) { + wolfSSL_EC_POINT_dump("i2d p", point); + } + + if (res == 1) { + /* DER encode point in uncompressed format. */ + int ret = wc_ecc_export_point_der(group->curve_idx, + (ecc_point*)point->internal, out, len); + /* Check return. When out is NULL, return will be length only error. */ + if ((ret != MP_OKAY) && ((out != NULL) || + (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)))) { + WOLFSSL_MSG("wolfSSL_ECPoint_i2d wc_ecc_export_point_der failed"); + res = 0; + } + } + + return res; +} + +/* Decode the uncompressed point in DER into EC point. + * + * Return code compliant with OpenSSL. + * Not OpenSSL API. + * + * @param [in] in Buffer containing DER encoded point. + * @param [in] len Length of data in bytes. + * @param [in] group EC group associated with point. + * @param [in, out] point EC point to set data into. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_ECPoint_d2i(const unsigned char *in, unsigned int len, + const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *point) +{ + int ret = 1; + WOLFSSL_BIGNUM* x = NULL; + WOLFSSL_BIGNUM* y = NULL; + + WOLFSSL_ENTER("wolfSSL_ECPoint_d2i"); + + /* Validate parameters. */ + if ((in == NULL) || (group == NULL) || (point == NULL) || + (point->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_ECPoint_d2i NULL error"); + ret = 0; + } + + if (ret == 1) { + #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + /* Import point into internal EC point. */ + if (wc_ecc_import_point_der_ex(in, len, group->curve_idx, + (ecc_point*)point->internal, 0) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_import_point_der_ex failed"); + ret = 0; + } + #else + /* ECC_POINT_UNCOMP is not defined CAVP self test so use magic number */ + if (in[0] == 0x04) { + /* Import point into internal EC point. */ + if (wc_ecc_import_point_der((unsigned char *)in, len, + group->curve_idx, (ecc_point*)point->internal) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_import_point_der failed"); + ret = 0; + } + } + else { + WOLFSSL_MSG("Only uncompressed points supported with " + "HAVE_SELFTEST"); + ret = 0; + } + #endif + } + + if (ret == 1) + point->inSet = 1; + + /* Set new external point. */ + if (ret == 1 && ec_point_external_set(point) != 1) { + WOLFSSL_MSG("ec_point_external_set failed"); + ret = 0; + } + + if (ret == 1 && !wolfSSL_BN_is_one(point->Z)) { +#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) + x = wolfSSL_BN_new(); + y = wolfSSL_BN_new(); + if (x == NULL || y == NULL) + ret = 0; + + if (ret == 1 && wolfSSL_EC_POINT_get_affine_coordinates_GFp(group, + point, x, y, NULL) != 1) { + WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp failed"); + ret = 0; + } + + /* wolfSSL_EC_POINT_set_affine_coordinates_GFp check that the point is + * on the curve. */ + if (ret == 1 && wolfSSL_EC_POINT_set_affine_coordinates_GFp(group, + point, x, y, NULL) != 1) { + WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp failed"); + ret = 0; + } +#else + WOLFSSL_MSG("Importing non-affine point. This may cause issues in math " + "operations later on."); +#endif + } + + if (ret == 1) { + /* Dump new point. */ + wolfSSL_EC_POINT_dump("d2i p", point); + } + + wolfSSL_BN_free(x); + wolfSSL_BN_free(y); + + return ret; +} + +/* Encode point as octet string. + * + * HYBRID not supported. + * + * @param [in] group EC group that point belongs to. + * @param [in] point EC point to encode. + * @param [in] form Format of encoding. Valid values: + * POINT_CONVERSION_UNCOMPRESSED,POINT_CONVERSION_COMPRESSED + * @param [out] buf Buffer to write encoding into. + * @param [in] len Length of buffer. + * @param [in] ctx Context to use for BN operations. Unused. + * @return Length of encoded data on success. + * @return 0 on error. + */ +size_t wolfSSL_EC_POINT_point2oct(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *point, int form, byte *buf, size_t len, + WOLFSSL_BN_CTX *ctx) +{ + int err = 0; + word32 enc_len = (word32)len; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + int compressed = ((form == WC_POINT_CONVERSION_COMPRESSED) ? 1 : 0); +#endif /* !HAVE_SELFTEST */ + + WOLFSSL_ENTER("wolfSSL_EC_POINT_point2oct"); + + /* No BN operations performed. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL)) { + err = 1; + } + + /* Ensure points internals are set up. */ + if ((!err) && (ec_point_setup(point) != 1)) { + err = 1; + } + + /* Special case when point is infinity. */ + if ((!err) && wolfSSL_EC_POINT_is_at_infinity(group, point)) { + /* Encoding is a single octet: 0x00. */ + enc_len = 1; + if (buf != NULL) { + /* Check whether buffer has space. */ + if (len < 1) { + wolfSSL_ECerr(WOLFSSL_EC_F_EC_GFP_SIMPLE_POINT2OCT, BUFFER_E); + err = 1; + } + else { + /* Put in encoding of infinity. */ + buf[0] = 0x00; + } + } + } + /* Not infinity. */ + else if (!err) { + /* Validate format. */ + if (form != WC_POINT_CONVERSION_UNCOMPRESSED + #ifndef HAVE_SELFTEST + && form != WC_POINT_CONVERSION_COMPRESSED + #endif /* !HAVE_SELFTEST */ + ) { + WOLFSSL_MSG("Unsupported point form"); + err = 1; + } + + if (!err) { + int ret; + + #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + /* Encode as compressed or uncompressed. */ + ret = wc_ecc_export_point_der_ex(group->curve_idx, + (ecc_point*)point->internal, buf, &enc_len, compressed); + #else + /* Encode uncompressed point in DER format. */ + ret = wc_ecc_export_point_der(group->curve_idx, + (ecc_point*)point->internal, buf, &enc_len); + #endif /* !HAVE_SELFTEST */ + /* Check return. When buf is NULL, return will be length only + * error. + */ + if (ret != ((buf != NULL) ? MP_OKAY : + WC_NO_ERR_TRACE(LENGTH_ONLY_E))) { + err = 1; + } + } + } + +#if defined(DEBUG_WOLFSSL) + if (!err) { + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_point2oct point", point); + WOLFSSL_MSG("\twolfSSL_EC_POINT_point2oct output:"); + WOLFSSL_BUFFER(buf, enc_len); + } +#endif + + /* On error, return encoding length of 0. */ + if (err) { + enc_len = 0; + } + return (size_t)enc_len; +} + + +/* Convert octet string to EC point. + * + * @param [in] group EC group. + * @param [in, out] point EC point to set data into. + * @param [in] buf Buffer holding octet string. + * @param [in] len Length of data in buffer in bytes. + * @param [in] ctx Context to use for BN operations. Unused. + */ +int wolfSSL_EC_POINT_oct2point(const WOLFSSL_EC_GROUP *group, + WOLFSSL_EC_POINT *point, const unsigned char *buf, size_t len, + WOLFSSL_BN_CTX *ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point"); + + /* No BN operations performed. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL)) { + ret = 0; + } + else { + /* Decode DER encoding into EC point. */ + ret = wolfSSL_ECPoint_d2i((unsigned char*)buf, (unsigned int)len, group, + point); + } + + return ret; +} + +/* Convert an EC point to a single BN. + * + * @param [in] group EC group. + * @param [in] point EC point. + * @param [in] form Format of encoding. Valid values: + * WC_POINT_CONVERSION_UNCOMPRESSED, + * WC_POINT_CONVERSION_COMPRESSED. + * @param [in, out] bn BN to hold point value. + * When NULL a new BN is allocated otherwise this is + * returned on success. + * @param [in] ctx Context to use for BN operations. Unused. + * @return BN object with point as a value on success. + * @return NULL on error. + */ +WOLFSSL_BIGNUM *wolfSSL_EC_POINT_point2bn(const WOLFSSL_EC_GROUP* group, + const WOLFSSL_EC_POINT* point, int form, WOLFSSL_BIGNUM* bn, + WOLFSSL_BN_CTX* ctx) +{ + int err = 0; + size_t len = 0; + byte *buf = NULL; + WOLFSSL_BIGNUM *ret = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL)) { + err = 1; + } + + /* Calculate length of octet encoding. */ + if ((!err) && ((len = wolfSSL_EC_POINT_point2oct(group, point, form, NULL, + 0, ctx)) == 0)) { + err = 1; + } + /* Allocate buffer to hold octet encoding. */ + if ((!err) && ((buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER)) == + NULL)) { + WOLFSSL_MSG("malloc failed"); + err = 1; + } + /* Encode EC point as an octet string. */ + if ((!err) && (wolfSSL_EC_POINT_point2oct(group, point, form, buf, len, + ctx) != len)) { + err = 1; + } + /* Load BN with octet string data. */ + if (!err) { + ret = wolfSSL_BN_bin2bn(buf, (int)len, bn); + } + + /* Dispose of any allocated data. */ + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) +/* Check if EC point is on the the curve defined by the EC group. + * + * @param [in] group EC group defining curve. + * @param [in] point EC point to check. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 when point is on curve. + * @return 0 when point is not on curve or error. + */ +int wolfSSL_EC_POINT_is_on_curve(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *point, WOLFSSL_BN_CTX *ctx) +{ + int err = 0; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_is_on_curve"); + + /* No BN operations performed. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL)) { + WOLFSSL_MSG("Invalid arguments"); + err = 1; + } + + /* Ensure internal EC point set. */ + if ((!err) && (!point->inSet) && ec_point_internal_set( + (WOLFSSL_EC_POINT*)point) != 1) { + WOLFSSL_MSG("ec_point_internal_set error"); + err = 1; + } + + /* Check point is on curve from group. */ + if ((!err) && (wc_ecc_point_is_on_curve((ecc_point*)point->internal, + group->curve_idx) != MP_OKAY)) { + err = 1; + } + + /* Return boolean of on curve. No error means on curve. */ + return !err; +} +#endif /* USE_ECC_B_PARAM && !HAVE_SELFTEST && !(FIPS_VERSION <= 2) */ + +#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) +/* Convert Jacobian ordinates to affine. + * + * @param [in] group EC group. + * @param [in] point EC point to get coordinates from. + * @return 1 on success. + * @return 0 on error. + */ +int ec_point_convert_to_affine(const WOLFSSL_EC_GROUP *group, + WOLFSSL_EC_POINT *point) +{ + int err = 0; + mp_digit mp = 0; + WC_DECLARE_VAR(modulus, mp_int, 1, 0); + + /* Allocate memory for curve's prime modulus. */ + WC_ALLOC_VAR_EX(modulus, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, err=1); + /* Initialize the MP integer. */ + if ((!err) && (mp_init(modulus) != MP_OKAY)) { + WOLFSSL_MSG("mp_init failed"); + err = 1; + } + + if (!err) { + /* Get the modulus from the hex string in the EC curve set. */ + if (mp_read_radix(modulus, ecc_sets[group->curve_idx].prime, + MP_RADIX_HEX) != MP_OKAY) { + WOLFSSL_MSG("mp_read_radix failed"); + err = 1; + } + /* Get Montgomery multiplier for the modulus as ordinates in + * Montgomery form. + */ + if ((!err) && (mp_montgomery_setup(modulus, &mp) != MP_OKAY)) { + WOLFSSL_MSG("mp_montgomery_setup failed"); + err = 1; + } + /* Map internal EC point from Jacobian to affine. */ + if ((!err) && (ecc_map((ecc_point*)point->internal, modulus, mp) != + MP_OKAY)) { + WOLFSSL_MSG("ecc_map failed"); + err = 1; + } + /* Set new ordinates into external EC point. */ + if ((!err) && (ec_point_external_set((WOLFSSL_EC_POINT *)point) != 1)) { + WOLFSSL_MSG("ec_point_external_set failed"); + err = 1; + } + + point->exSet = !err; + mp_clear(modulus); + } + + WC_FREE_VAR_EX(modulus, NULL, DYNAMIC_TYPE_BIGINT); + + return err; +} + +/* Get the affine coordinates of the EC point on a Prime curve. + * + * When z-ordinate is not one then coordinates are Jacobian and need to be + * converted to affine before storing in BNs. + * + * Return code compliant with OpenSSL. + * + * TODO: OpenSSL doesn't change point when Jacobian. Do the same? + * + * @param [in] group EC group. + * @param [in] point EC point to get coordinates from. + * @param [in, out] x BN to hold x-ordinate. + * @param [in, out] y BN to hold y-ordinate. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_get_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group, + const WOLFSSL_EC_POINT* point, WOLFSSL_BIGNUM* x, WOLFSSL_BIGNUM* y, + WOLFSSL_BN_CTX* ctx) +{ + int ret = 1; + + /* BN operations don't need context. */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_get_affine_coordinates_GFp"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL) || (point->internal == NULL) || + (x == NULL) || (y == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp NULL error"); + ret = 0; + } + /* Don't return point at infinity. */ + if ((ret == 1) && wolfSSL_EC_POINT_is_at_infinity(group, point)) { + ret = 0; + } + + /* Ensure internal EC point has values of external EC point. */ + if ((ret == 1) && (ec_point_setup(point) != 1)) { + ret = 0; + } + + /* Check whether ordinates are in Jacobian form. */ + if ((ret == 1) && (!wolfSSL_BN_is_one(point->Z))) { + /* Convert from Jacobian to affine. */ + if (ec_point_convert_to_affine(group, (WOLFSSL_EC_POINT*)point) == 1) { + ret = 0; + } + } + + /* Copy the externally set x and y ordinates. */ + if ((ret == 1) && (wolfSSL_BN_copy(x, point->X) == NULL)) { + ret = 0; + } + if ((ret == 1) && (wolfSSL_BN_copy(y, point->Y) == NULL)) { + ret = 0; + } + + return ret; +} +#endif /* !WOLFSSL_SP_MATH && !WOLF_CRYPTO_CB_ONLY_ECC */ + +/* Sets the affine coordinates that belong on a prime curve. + * + * @param [in] group EC group. + * @param [in, out] point EC point to set coordinates into. + * @param [in] x BN holding x-ordinate. + * @param [in] y BN holding y-ordinate. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_set_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group, + WOLFSSL_EC_POINT* point, const WOLFSSL_BIGNUM* x, const WOLFSSL_BIGNUM* y, + WOLFSSL_BN_CTX* ctx) +{ + int ret = 1; + + /* BN operations don't need context. */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_set_affine_coordinates_GFp"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL) || (point->internal == NULL) || + (x == NULL) || (y == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp NULL error"); + ret = 0; + } + + /* Ensure we have a object for x-ordinate. */ + if ((ret == 1) && (point->X == NULL) && + ((point->X = wolfSSL_BN_new()) == NULL)) { + WOLFSSL_MSG("wolfSSL_BN_new failed"); + ret = 0; + } + /* Ensure we have a object for y-ordinate. */ + if ((ret == 1) && (point->Y == NULL) && + ((point->Y = wolfSSL_BN_new()) == NULL)) { + WOLFSSL_MSG("wolfSSL_BN_new failed"); + ret = 0; + } + /* Ensure we have a object for z-ordinate. */ + if ((ret == 1) && (point->Z == NULL) && + ((point->Z = wolfSSL_BN_new()) == NULL)) { + WOLFSSL_MSG("wolfSSL_BN_new failed"); + ret = 0; + } + + /* Copy the x-ordinate. */ + if ((ret == 1) && ((wolfSSL_BN_copy(point->X, x)) == NULL)) { + WOLFSSL_MSG("wolfSSL_BN_copy failed"); + ret = 0; + } + /* Copy the y-ordinate. */ + if ((ret == 1) && ((wolfSSL_BN_copy(point->Y, y)) == NULL)) { + WOLFSSL_MSG("wolfSSL_BN_copy failed"); + ret = 0; + } + /* z-ordinate is one for affine coordinates. */ + if ((ret == 1) && ((wolfSSL_BN_one(point->Z)) == 0)) { + WOLFSSL_MSG("wolfSSL_BN_one failed"); + ret = 0; + } + + /* Copy the new point data to internal object. */ + if ((ret == 1) && (ec_point_internal_set((WOLFSSL_EC_POINT *)point) != 1)) { + WOLFSSL_MSG("ec_point_internal_set failed"); + ret = 0; + } + +#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + /* Check that the point is valid. */ + if ((ret == 1) && (wolfSSL_EC_POINT_is_on_curve(group, + (WOLFSSL_EC_POINT *)point, ctx) != 1)) { + WOLFSSL_MSG("EC_POINT_is_on_curve failed"); + ret = 0; + } +#endif + + return ret; +} + +#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \ + !defined(HAVE_SELFTEST) && !defined(WOLFSSL_SP_MATH) && \ + !defined(WOLF_CRYPTO_CB_ONLY_ECC) +/* Add two points on the same together. + * + * @param [in] curveIdx Index of curve in ecc_set. + * @param [out] r Result point. + * @param [in] p1 First point to add. + * @param [in] p2 Second point to add. + * @return 1 on success. + * @return 0 on error. + */ +static int wolfssl_ec_point_add(int curveIdx, ecc_point* r, ecc_point* p1, + ecc_point* p2) +{ + int ret = 1; +#ifdef WOLFSSL_SMALL_STACK + mp_int* a = NULL; + mp_int* prime = NULL; + mp_int* mu = NULL; +#else + mp_int a[1]; + mp_int prime[1]; + mp_int mu[1]; +#endif + mp_digit mp = 0; + ecc_point* montP1 = NULL; + ecc_point* montP2 = NULL; + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 1) { + /* Allocate memory for curve parameter: a. */ + a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (a == NULL) { + WOLFSSL_MSG("Failed to allocate memory for mp_int a"); + ret = 0; + } + } + if (ret == 1) { + /* Allocate memory for curve parameter: prime. */ + prime = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (prime == NULL) { + WOLFSSL_MSG("Failed to allocate memory for mp_int prime"); + ret = 0; + } + } + if (ret == 1) { + /* Allocate memory for mu (Montgomery normalizer). */ + mu = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (mu == NULL) { + WOLFSSL_MSG("Failed to allocate memory for mp_int mu"); + ret = 0; + } + } + if (ret == 1) { + /* Zero out all MP int data in case initialization fails. */ + XMEMSET(a, 0, sizeof(mp_int)); + XMEMSET(prime, 0, sizeof(mp_int)); + XMEMSET(mu, 0, sizeof(mp_int)); + } +#endif + + /* Initialize the MP ints. */ + if ((ret == 1) && (mp_init_multi(prime, a, mu, NULL, NULL, NULL) != + MP_OKAY)) { + WOLFSSL_MSG("mp_init_multi error"); + ret = 0; + } + + /* Read the curve parameter: a. */ + if ((ret == 1) && (mp_read_radix(a, ecc_sets[curveIdx].Af, MP_RADIX_HEX) != + MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix a error"); + ret = 0; + } + + /* Read the curve parameter: prime. */ + if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix prime error"); + ret = 0; + } + + /* Calculate the Montgomery product. */ + if ((ret == 1) && (mp_montgomery_setup(prime, &mp) != MP_OKAY)) { + WOLFSSL_MSG("mp_montgomery_setup nqm error"); + ret = 0; + } + + /* TODO: use the heap filed of one of the points? */ + /* Allocate new points to hold the Montgomery form values. */ + if ((ret == 1) && (((montP1 = wc_ecc_new_point_h(NULL)) == NULL) || + ((montP2 = wc_ecc_new_point_h(NULL)) == NULL))) { + WOLFSSL_MSG("wc_ecc_new_point_h nqm error"); + ret = 0; + } + + /* Calculate the Montgomery normalizer. */ + if ((ret == 1) && (mp_montgomery_calc_normalization(mu, prime) != + MP_OKAY)) { + WOLFSSL_MSG("mp_montgomery_calc_normalization error"); + ret = 0; + } + + /* Convert to Montgomery form. */ + if ((ret == 1) && (mp_cmp_d(mu, 1) == MP_EQ)) { + /* Copy the points if the normalizer is 1. */ + if ((wc_ecc_copy_point(p1, montP1) != MP_OKAY) || + (wc_ecc_copy_point(p2, montP2) != MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_copy_point error"); + ret = 0; + } + } + else if (ret == 1) { + /* Multiply each ordinate by the Montgomery normalizer. */ + if ((mp_mulmod(p1->x, mu, prime, montP1->x) != MP_OKAY) || + (mp_mulmod(p1->y, mu, prime, montP1->y) != MP_OKAY) || + (mp_mulmod(p1->z, mu, prime, montP1->z) != MP_OKAY)) { + WOLFSSL_MSG("mp_mulmod error"); + ret = 0; + } + /* Multiply each ordinate by the Montgomery normalizer. */ + if ((mp_mulmod(p2->x, mu, prime, montP2->x) != MP_OKAY) || + (mp_mulmod(p2->y, mu, prime, montP2->y) != MP_OKAY) || + (mp_mulmod(p2->z, mu, prime, montP2->z) != MP_OKAY)) { + WOLFSSL_MSG("mp_mulmod error"); + ret = 0; + } + } + + /* Perform point addition with internal EC point objects - Jacobian form + * result. + */ + if ((ret == 1) && (ecc_projective_add_point(montP1, montP2, r, a, prime, + mp) != MP_OKAY)) { + WOLFSSL_MSG("ecc_projective_add_point error"); + ret = 0; + } + + /* Map point back to affine coordinates. Converts from Montogomery form. */ + if ((ret == 1) && (ecc_map(r, prime, mp) != MP_OKAY)) { + WOLFSSL_MSG("ecc_map error"); + ret = 0; + } + + /* Dispose of allocated memory. */ + mp_clear(a); + mp_clear(prime); + mp_clear(mu); + wc_ecc_del_point_h(montP1, NULL); + wc_ecc_del_point_h(montP2, NULL); + WC_FREE_VAR_EX(a, NULL, DYNAMIC_TYPE_BIGINT); + WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); + WC_FREE_VAR_EX(mu, NULL, DYNAMIC_TYPE_BIGINT); + return ret; +} + +/* Add two points on the same curve together. + * + * @param [in] group EC group. + * @param [out] r EC point that is result of point addition. + * @param [in] p1 First EC point to add. + * @param [in] p2 Second EC point to add. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_add(const WOLFSSL_EC_GROUP* group, WOLFSSL_EC_POINT* r, + const WOLFSSL_EC_POINT* p1, const WOLFSSL_EC_POINT* p2, WOLFSSL_BN_CTX* ctx) +{ + int ret = 1; + + /* No BN operations performed. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (r == NULL) || (p1 == NULL) || (p2 == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_add error"); + ret = 0; + } + + /* Ensure the internal objects of the EC points are setup. */ + if ((ret == 1) && ((ec_point_setup(r) != 1) || (ec_point_setup(p1) != 1) || + (ec_point_setup(p2) != 1))) { + WOLFSSL_MSG("ec_point_setup error"); + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + int nid = wolfSSL_EC_GROUP_get_curve_name(group); + const char* curve = wolfSSL_OBJ_nid2ln(nid); + const char* nistName = wolfSSL_EC_curve_nid2nist(nid); + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add p1", p1); + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add p2", p2); + if (curve != NULL) + WOLFSSL_MSG_EX("curve name: %s", curve); + if (nistName != NULL) + WOLFSSL_MSG_EX("nist curve name: %s", nistName); + } +#endif + + if (ret == 1) { + /* Add points using wolfCrypt objects. */ + ret = wolfssl_ec_point_add(group->curve_idx, (ecc_point*)r->internal, + (ecc_point*)p1->internal, (ecc_point*)p2->internal); + } + + /* Copy internal EC point values out to external EC point. */ + if ((ret == 1) && (ec_point_external_set(r) != 1)) { + WOLFSSL_MSG("ec_point_external_set error"); + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add result", r); + } +#endif + + return ret; +} + +/* Sum the scalar multiplications of the base point and n, and q and m. + * + * r = base point * n + q * m + * + * @param [out] r EC point that is result of operation. + * @param [in] b Base point of curve. + * @param [in] n Scalar to multiply by base point. + * @param [in] q EC point to be scalar multiplied. + * @param [in] m Scalar to multiply q by. + * @param [in] a Parameter A of curve. + * @param [in] prime Prime (modulus) of curve. + * @return 1 on success. + * @return 0 on error. + */ +static int ec_mul2add(ecc_point* r, ecc_point* b, mp_int* n, ecc_point* q, + mp_int* m, mp_int* a, mp_int* prime) +{ + int ret = 1; +#if defined(ECC_SHAMIR) && !defined(WOLFSSL_KCAPI_ECC) + if (ecc_mul2add(b, n, q, m, r, a, prime, NULL) != MP_OKAY) { + WOLFSSL_MSG("ecc_mul2add error"); + ret = 0; + } +#else + ecc_point* tmp = NULL; + mp_digit mp = 0; + + /* Calculate Montgomery product. */ + if (mp_montgomery_setup(prime, &mp) != MP_OKAY) { + WOLFSSL_MSG("mp_montgomery_setup nqm error"); + ret = 0; + } + /* Create temporary point to hold: q * m */ + if ((ret == 1) && ((tmp = wc_ecc_new_point()) == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new nqm error"); + ret = 0; + } + /* r = base point * n */ + if ((ret == 1) && (wc_ecc_mulmod(n, b, r, a, prime, 0) != + MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_mulmod nqm error"); + ret = 0; + } + /* tmp = q * m */ + if ((ret == 1) && (wc_ecc_mulmod(m, q, tmp, a, prime, 0) != MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_mulmod nqm error"); + ret = 0; + } + /* r = r + tmp */ + if ((ret == 1) && (ecc_projective_add_point(tmp, r, r, a, prime, mp) != + MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_mulmod nqm error"); + ret = 0; + } + /* Map point back to affine coordinates. Converts from Montogomery + * form. */ + if ((ret == 1) && (ecc_map(r, prime, mp) != MP_OKAY)) { + WOLFSSL_MSG("ecc_map nqm error"); + ret = 0; + } + + /* Dispose of allocated temporary point. */ + wc_ecc_del_point(tmp); +#endif + + return ret; +} + +/* Sum the scalar multiplications of the base point and n, and q and m. + * + * r = base point * n + q * m + * + * @param [in] curveIdx Index of curve in ecc_set. + * @param [out] r EC point that is result of operation. + * @param [in] n Scalar to multiply by base point. May be NULL. + * @param [in] q EC point to be scalar multiplied. May be NULL. + * @param [in] m Scalar to multiply q by. May be NULL. + * @return 1 on success. + * @return 0 on error. + */ +static int wolfssl_ec_point_mul(int curveIdx, ecc_point* r, mp_int* n, + ecc_point* q, mp_int* m) +{ + int ret = 1; +#ifdef WOLFSSL_SMALL_STACK + mp_int* a = NULL; + mp_int* prime = NULL; +#else + mp_int a[1], prime[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + /* Allocate MP integer for curve parameter: a. */ + a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (a == NULL) { + ret = 0; + } + if (ret == 1) { + /* Allocate MP integer for curve parameter: prime. */ + prime = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (prime == NULL) { + ret = 0; + } + } +#endif + + /* Initialize the MP ints. */ + if ((ret == 1) && (mp_init_multi(prime, a, NULL, NULL, NULL, NULL) != + MP_OKAY)) { + WOLFSSL_MSG("mp_init_multi error"); + ret = 0; + } + + /* Read the curve parameter: prime. */ + if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix prime error"); + ret = 0; + } + + /* Read the curve parameter: a. */ + if ((ret == 1) && (mp_read_radix(a, ecc_sets[curveIdx].Af, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix a error"); + ret = 0; + } + + if ((ret == 1) && (n != NULL)) { + /* Get generator - base point. */ + #if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) + if ((ret == 1) && (wc_ecc_get_generator(r, curveIdx) != MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_get_generator error"); + ret = 0; + } + #else + /* wc_ecc_get_generator is not defined in the FIPS v2 module. */ + /* Read generator (base point) x-ordinate. */ + if ((ret == 1) && (mp_read_radix(r->x, ecc_sets[curveIdx].Gx, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix Gx error"); + ret = 0; + } + /* Read generator (base point) y-ordinate. */ + if ((ret == 1) && (mp_read_radix(r->y, ecc_sets[curveIdx].Gy, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix Gy error"); + ret = 0; + } + /* z-ordinate is one as point is affine. */ + if ((ret == 1) && (mp_set(r->z, 1) != MP_OKAY)) { + WOLFSSL_MSG("mp_set Gz error"); + ret = 0; + } + #endif /* NOPT_FIPS_VERSION == 2 */ + } + + if ((ret == 1) && (n != NULL) && (q != NULL) && (m != NULL)) { + /* r = base point * n + q * m */ + ret = ec_mul2add(r, r, n, q, m, a, prime); + } + /* Not all values present, see if we are only doing base point * n. */ + else if ((ret == 1) && (n != NULL)) { + /* r = base point * n */ + if (wc_ecc_mulmod(n, r, r, a, prime, 1) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_mulmod gn error"); + ret = 0; + } + } + /* Not all values present, see if we are only doing q * m. */ + else if ((ret == 1) && (q != NULL) && (m != NULL)) { + /* r = q * m */ + if (wc_ecc_mulmod(m, q, r, a, prime, 1) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_mulmod qm error"); + ret = 0; + } + } + /* No values to use. */ + else if (ret == 1) { + /* Set result to infinity as no values passed in. */ + mp_zero(r->x); + mp_zero(r->y); + mp_zero(r->z); + } + + mp_clear(a); + mp_clear(prime); + WC_FREE_VAR_EX(a, NULL, DYNAMIC_TYPE_BIGINT); + WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); + return ret; +} + +/* Sum the scalar multiplications of the base point and n, and q and m. + * + * r = base point * n + q * m + * + * Return code compliant with OpenSSL. + * + * @param [in] group EC group. + * @param [out] r EC point that is result of operation. + * @param [in] n Scalar to multiply by base point. May be NULL. + * @param [in] q EC point to be scalar multiplied. May be NULL. + * @param [in] m Scalar to multiply q by. May be NULL. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_mul(const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *r, + const WOLFSSL_BIGNUM *n, const WOLFSSL_EC_POINT *q, const WOLFSSL_BIGNUM *m, + WOLFSSL_BN_CTX *ctx) +{ + int ret = 1; + + /* No BN operations performed. */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_mul"); + + /* Validate parameters. */ + if ((group == NULL) || (r == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_mul NULL error"); + ret = 0; + } + + /* Ensure the internal representation of the EC point q is setup. */ + if ((ret == 1) && (q != NULL) && (ec_point_setup(q) != 1)) { + WOLFSSL_MSG("ec_point_setup error"); + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + int nid = wolfSSL_EC_GROUP_get_curve_name(group); + const char* curve = wolfSSL_OBJ_nid2ln(nid); + const char* nistName = wolfSSL_EC_curve_nid2nist(nid); + char* num; + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_mul input q", q); + num = wolfSSL_BN_bn2hex(n); + WOLFSSL_MSG_EX("\tn = %s", num); + XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); + num = wolfSSL_BN_bn2hex(m); + WOLFSSL_MSG_EX("\tm = %s", num); + XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); + if (curve != NULL) + WOLFSSL_MSG_EX("curve name: %s", curve); + if (nistName != NULL) + WOLFSSL_MSG_EX("nist curve name: %s", nistName); + } +#endif + + if (ret == 1) { + mp_int* ni = (n != NULL) ? (mp_int*)n->internal : NULL; + ecc_point* qi = (q != NULL) ? (ecc_point*)q->internal : NULL; + mp_int* mi = (m != NULL) ? (mp_int*)m->internal : NULL; + + /* Perform multiplication with wolfCrypt objects. */ + ret = wolfssl_ec_point_mul(group->curve_idx, (ecc_point*)r->internal, + ni, qi, mi); + } + + /* Only on success is the internal point guaranteed to be set. */ + if (r != NULL) { + r->inSet = (ret == 1); + } + /* Copy internal EC point values out to external EC point. */ + if ((ret == 1) && (ec_point_external_set(r) != 1)) { + WOLFSSL_MSG("ec_point_external_set error"); + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_mul result", r); + } +#endif + + return ret; +} +#endif /* !WOLFSSL_ATECC508A && !WOLFSSL_ATECC608A && !HAVE_SELFTEST && + * !WOLFSSL_SP_MATH */ + +/* Invert the point on the curve. + * (x, y) -> (x, -y) = (x, (prime - y) % prime) + * + * @param [in] curveIdx Index of curve in ecc_set. + * @param [in, out] point EC point to invert. + * @return 1 on success. + * @return 0 on error. + */ +static int wolfssl_ec_point_invert(int curveIdx, ecc_point* point) +{ + int ret = 1; + WC_DECLARE_VAR(prime, mp_int, 1, 0); + + /* Allocate memory for an MP int to hold the prime of the curve. */ + WC_ALLOC_VAR_EX(prime, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, ret=0); + + /* Initialize MP int. */ + if ((ret == 1) && (mp_init(prime) != MP_OKAY)) { + WOLFSSL_MSG("mp_init_multi error"); + ret = 0; + } + + /* Read the curve parameter: prime. */ + if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix prime error"); + ret = 0; + } + + /* y = (prime - y) mod prime. */ + if ((ret == 1) && (!mp_iszero(point->y)) && (mp_sub(prime, point->y, + point->y) != MP_OKAY)) { + WOLFSSL_MSG("mp_sub error"); + ret = 0; + } + + /* Dispose of memory associated with MP. */ + mp_free(prime); + WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); + return ret; +} + +/* Invert the point on the curve. + * (x, y) -> (x, -y) = (x, (prime - y) % prime) + * + * @param [in] group EC group. + * @param [in, out] point EC point to invert. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_invert(const WOLFSSL_EC_GROUP *group, + WOLFSSL_EC_POINT *point, WOLFSSL_BN_CTX *ctx) +{ + int ret = 1; + + /* No BN operations performed. */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_invert"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL) || (point->internal == NULL)) { + ret = 0; + } + + /* Ensure internal representation of point is setup. */ + if ((ret == 1) && (ec_point_setup(point) != 1)) { + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + int nid = wolfSSL_EC_GROUP_get_curve_name(group); + const char* curve = wolfSSL_OBJ_nid2ln(nid); + const char* nistName = wolfSSL_EC_curve_nid2nist(nid); + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_invert input", point); + if (curve != NULL) + WOLFSSL_MSG_EX("curve name: %s", curve); + if (nistName != NULL) + WOLFSSL_MSG_EX("nist curve name: %s", nistName); + + } +#endif + + if (ret == 1 && !wolfSSL_BN_is_one(point->Z)) { +#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) + if (ec_point_convert_to_affine(group, point) != 0) + ret = 0; +#else + WOLFSSL_MSG("wolfSSL_EC_POINT_invert called on non-affine point"); + ret = 0; +#endif + } + + if (ret == 1) { + /* Perform inversion using wolfCrypt objects. */ + ret = wolfssl_ec_point_invert(group->curve_idx, + (ecc_point*)point->internal); + } + + /* Set the external EC point representation based on internal. */ + if ((ret == 1) && (ec_point_external_set(point) != 1)) { + WOLFSSL_MSG("ec_point_external_set error"); + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_invert result", point); + } +#endif + + return ret; +} + +#ifdef WOLFSSL_EC_POINT_CMP_JACOBIAN +/* Compare two points on a the same curve. + * + * (Ax, Ay, Az) => (Ax / (Az ^ 2), Ay / (Az ^ 3)) + * (Bx, By, Bz) => (Bx / (Bz ^ 2), By / (Bz ^ 3)) + * When equal: + * (Ax / (Az ^ 2), Ay / (Az ^ 3)) = (Bx / (Bz ^ 2), By / (Bz ^ 3)) + * => (Ax * (Bz ^ 2), Ay * (Bz ^ 3)) = (Bx * (Az ^ 2), By * (Az ^ 3)) + * + * @param [in] group EC group. + * @param [in] a EC point to compare. + * @param [in] b EC point to compare. + * @return 0 when equal. + * @return 1 when different. + * @return -1 on error. + */ +static int ec_point_cmp_jacobian(const WOLFSSL_EC_GROUP* group, + const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, WOLFSSL_BN_CTX *ctx) +{ + int ret = 0; + BIGNUM* at = BN_new(); + BIGNUM* bt = BN_new(); + BIGNUM* az = BN_new(); + BIGNUM* bz = BN_new(); + BIGNUM* mod = BN_new(); + + /* Check that the big numbers were allocated. */ + if ((at == NULL) || (bt == NULL) || (az == NULL) || (bz == NULL) || + (mod == NULL)) { + ret = WOLFSSL_FATAL_ERROR; + } + /* Get the modulus for the curve. */ + if ((ret == 0) && + (BN_hex2bn(&mod, ecc_sets[group->curve_idx].prime) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + if (ret == 0) { + /* bt = Bx * (Az ^ 2). When Az is one then just copy. */ + if (BN_is_one(a->Z)) { + if (BN_copy(bt, b->X) == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* az = Az ^ 2 */ + else if ((BN_mod_mul(az, a->Z, a->Z, mod, ctx) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + /* bt = Bx * az = Bx * (Az ^ 2) */ + else if (BN_mod_mul(bt, b->X, az, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 0) { + /* at = Ax * (Bz ^ 2). When Bz is one then just copy. */ + if (BN_is_one(b->Z)) { + if (BN_copy(at, a->X) == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* bz = Bz ^ 2 */ + else if (BN_mod_mul(bz, b->Z, b->Z, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + /* at = Ax * bz = Ax * (Bz ^ 2) */ + else if (BN_mod_mul(at, a->X, bz, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* Compare x-ordinates. */ + if ((ret == 0) && (BN_cmp(at, bt) != 0)) { + ret = 1; + } + if (ret == 0) { + /* bt = By * (Az ^ 3). When Az is one then just copy. */ + if (BN_is_one(a->Z)) { + if (BN_copy(bt, b->Y) == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* az = az * Az = Az ^ 3 */ + else if ((BN_mod_mul(az, az, a->Z, mod, ctx) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + /* bt = By * az = By * (Az ^ 3) */ + else if (BN_mod_mul(bt, b->Y, az, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 0) { + /* at = Ay * (Bz ^ 3). When Bz is one then just copy. */ + if (BN_is_one(b->Z)) { + if (BN_copy(at, a->Y) == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* bz = bz * Bz = Bz ^ 3 */ + else if (BN_mod_mul(bz, bz, b->Z, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + /* at = Ay * bz = Ay * (Bz ^ 3) */ + else if (BN_mod_mul(at, a->Y, bz, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* Compare y-ordinates. */ + if ((ret == 0) && (BN_cmp(at, bt) != 0)) { + ret = 1; + } + + BN_free(mod); + BN_free(bz); + BN_free(az); + BN_free(bt); + BN_free(at); + return ret; +} +#endif + +/* Compare two points on a the same curve. + * + * Return code compliant with OpenSSL. + * + * @param [in] group EC group. + * @param [in] a EC point to compare. + * @param [in] b EC point to compare. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 0 when equal. + * @return 1 when different. + * @return -1 on error. + */ +int wolfSSL_EC_POINT_cmp(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, WOLFSSL_BN_CTX *ctx) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_cmp"); + + /* Validate parameters. */ + if ((group == NULL) || (a == NULL) || (a->internal == NULL) || + (b == NULL) || (b->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_cmp Bad arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + if (ret != -1) { + #ifdef WOLFSSL_EC_POINT_CMP_JACOBIAN + /* If same Z ordinate then no need to convert to affine. */ + if (BN_cmp(a->Z, b->Z) == 0) { + /* Compare */ + ret = ((BN_cmp(a->X, b->X) != 0) || (BN_cmp(a->Y, b->Y) != 0)); + } + else { + ret = ec_point_cmp_jacobian(group, a, b, ctx); + } + #else + /* No BN operations performed. */ + (void)ctx; + + ret = (wc_ecc_cmp_point((ecc_point*)a->internal, + (ecc_point*)b->internal) != MP_EQ); + #endif + } + + return ret; +} + +/* Copy EC point. + * + * @param [out] dest EC point to copy into. + * @param [in] src EC point to copy. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_copy(WOLFSSL_EC_POINT *dest, const WOLFSSL_EC_POINT *src) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_copy"); + + /* Validate parameters. */ + if ((dest == NULL) || (src == NULL)) { + ret = 0; + } + + /* Ensure internal EC point of src is setup. */ + if ((ret == 1) && (ec_point_setup(src) != 1)) { + ret = 0; + } + + /* Copy internal EC points. */ + if ((ret == 1) && (wc_ecc_copy_point((ecc_point*)src->internal, + (ecc_point*)dest->internal) != MP_OKAY)) { + ret = 0; + } + + if (ret == 1) { + /* Destinatation internal point is set. */ + dest->inSet = 1; + + /* Set the external EC point of dest based on internal. */ + if (ec_point_external_set(dest) != 1) { + ret = 0; + } + } + + return ret; +} + +/* Checks whether point is at infinity. + * + * Return code compliant with OpenSSL. + * + * @param [in] group EC group. + * @param [in] point EC point to check. + * @return 1 when at infinity. + * @return 0 when not at infinity. + */ +int wolfSSL_EC_POINT_is_at_infinity(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *point) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_is_at_infinity"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL) || (point->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_is_at_infinity NULL error"); + ret = 0; + } + + /* Ensure internal EC point is setup. */ + if ((ret == 1) && (ec_point_setup(point) != 1)) { + ret = 0; + } + if (ret == 1) { + #ifndef WOLF_CRYPTO_CB_ONLY_ECC + /* Check for infinity. */ + ret = wc_ecc_point_is_at_infinity((ecc_point*)point->internal); + if (ret < 0) { + WOLFSSL_MSG("ecc_point_is_at_infinity failure"); + /* Error return is 0 by OpenSSL. */ + ret = 0; + } + #else + WOLFSSL_MSG("ecc_point_is_at_infinitiy compiled out"); + ret = 0; + #endif + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +/* End EC_POINT */ + +/* Start EC_KEY */ + +#ifdef OPENSSL_EXTRA + +/* + * EC key constructor/deconstructor APIs + */ + +/* Allocate a new EC key. + * + * Not OpenSSL API. + * + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] devId Device identifier value. + * @return New, allocated EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_ex(void* heap, int devId) +{ + WOLFSSL_EC_KEY *key = NULL; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_new"); + + /* Allocate memory for EC key. */ + key = (WOLFSSL_EC_KEY*)XMALLOC(sizeof(WOLFSSL_EC_KEY), heap, + DYNAMIC_TYPE_ECC); + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_KEY failure"); + err = 1; + } + if (!err) { + /* Reset all fields to 0. */ + XMEMSET(key, 0, sizeof(WOLFSSL_EC_KEY)); + /* Cache heap hint. */ + key->heap = heap; + /* Initialize fields to defaults. */ + key->form = WC_POINT_CONVERSION_UNCOMPRESSED; + + /* Initialize reference count. */ + wolfSSL_RefInit(&key->ref, &err); +#ifdef WOLFSSL_REFCNT_ERROR_RETURN + } + if (!err) { +#endif + /* Allocate memory for internal EC key representation. */ + key->internal = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, + DYNAMIC_TYPE_ECC); + if (key->internal == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc ecc key failure"); + err = 1; + } + } + if (!err) { + /* Initialize wolfCrypt EC key. */ + if (wc_ecc_init_ex((ecc_key*)key->internal, heap, devId) != 0) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new init ecc key failure"); + err = 1; + } + } + + if (!err) { + /* Group unknown at creation */ + key->group = wolfSSL_EC_GROUP_new_by_curve_name(WC_NID_undef); + if (key->group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_GROUP failure"); + err = 1; + } + } + + if (!err) { + /* Allocate a point as public key. */ + key->pub_key = wolfSSL_EC_POINT_new(key->group); + if (key->pub_key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new failure"); + err = 1; + } + } + + if (!err) { + /* Allocate a BN as private key. */ + key->priv_key = wolfSSL_BN_new(); + if (key->priv_key == NULL) { + WOLFSSL_MSG("wolfSSL_BN_new failure"); + err = 1; + } + } + + if (err) { + /* Dispose of EC key on error. */ + wolfSSL_EC_KEY_free(key); + key = NULL; + } + /* Return new EC key object. */ + return key; +} + +/* Allocate a new EC key. + * + * @return New, allocated EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new(void) +{ + return wolfSSL_EC_KEY_new_ex(NULL, INVALID_DEVID); +} + +/* Create new EC key with the group having the specified numeric ID. + * + * @param [in] nid Numeric ID. + * @return New, allocated EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_by_curve_name(int nid) +{ + WOLFSSL_EC_KEY *key; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_new_by_curve_name"); + + /* Allocate empty, EC key. */ + key = wolfSSL_EC_KEY_new(); + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new failure"); + err = 1; + } + + if (!err) { + /* Set group to be nid. */ + ec_group_set_nid(key->group, nid); + if (key->group->curve_idx == -1) { + wolfSSL_EC_KEY_free(key); + key = NULL; + } + } + + /* Return the new EC key object. */ + return key; +} + +/* Dispose of the EC key and allocated data. + * + * Cannot use key after this call. + * + * @param [in] key EC key to free. + */ +void wolfSSL_EC_KEY_free(WOLFSSL_EC_KEY *key) +{ + int doFree = 0; + int err; + + (void)err; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_free"); + + if (key != NULL) { + void* heap = key->heap; + + /* Decrement reference count. */ + wolfSSL_RefDec(&key->ref, &doFree, &err); + if (doFree) { + /* Dispose of allocated reference counting data. */ + wolfSSL_RefFree(&key->ref); + + /* Dispose of private key. */ + wolfSSL_BN_free(key->priv_key); + wolfSSL_EC_POINT_free(key->pub_key); + wolfSSL_EC_GROUP_free(key->group); + if (key->internal != NULL) { + /* Dispose of wolfCrypt representation of EC key. */ + wc_ecc_free((ecc_key*)key->internal); + XFREE(key->internal, heap, DYNAMIC_TYPE_ECC); + } + + /* Set back to NULLs for safety. */ + ForceZero(key, sizeof(*key)); + + /* Dispose of the memory associated with the EC key. */ + XFREE(key, heap, DYNAMIC_TYPE_ECC); + (void)heap; + } + } +} + +/* Increments ref count of EC key. + * + * @param [in, out] key EC key. + * @return 1 on success + * @return 0 on error + */ +int wolfSSL_EC_KEY_up_ref(WOLFSSL_EC_KEY* key) +{ + int err = 1; + + if (key != NULL) { + wolfSSL_RefInc(&key->ref, &err); + } + + return !err; +} + +#ifndef NO_CERTS + +#if defined(OPENSSL_ALL) +/* Copy the internal, wolfCrypt EC key. + * + * @param [in, out] dst Destination wolfCrypt EC key. + * @param [in] src Source wolfCrypt EC key. + * @return 0 on success. + * @return Negative on error. + */ +static int wolfssl_ec_key_int_copy(ecc_key* dst, const ecc_key* src) +{ + int ret; + + /* Copy public key. */ +#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) + ret = wc_ecc_copy_point(&src->pubkey, &dst->pubkey); +#else + ret = wc_ecc_copy_point((ecc_point*)&src->pubkey, &dst->pubkey); +#endif + if (ret != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_copy_point error"); + } + + if (ret == 0) { + /* Copy private key. */ + ret = mp_copy(wc_ecc_key_get_priv((ecc_key*)src), + wc_ecc_key_get_priv(dst)); + if (ret != MP_OKAY) { + WOLFSSL_MSG("mp_copy error"); + } + } + + if (ret == 0) { + /* Copy domain parameters. */ + if (src->dp) { + ret = wc_ecc_set_curve(dst, 0, src->dp->id); + if (ret != 0) { + WOLFSSL_MSG("wc_ecc_set_curve error"); + } + } + } + + if (ret == 0) { + /* Copy the other components. */ + dst->type = src->type; + dst->idx = src->idx; + dst->state = src->state; + dst->flags = src->flags; + } + + return ret; +} + +/* Copies ecc_key into new WOLFSSL_EC_KEY object + * + * Copies the internal representation as well. + * + * @param [in] src EC key to duplicate. + * + * @return EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_dup(const WOLFSSL_EC_KEY *src) +{ + int err = 0; + WOLFSSL_EC_KEY* newKey = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_dup"); + + /* Validate EC key. */ + if ((src == NULL) || (src->internal == NULL) || (src->group == NULL) || + (src->pub_key == NULL) || (src->priv_key == NULL)) { + WOLFSSL_MSG("src NULL error"); + err = 1; + } + + if (!err) { + /* Create a new, empty key. */ + newKey = wolfSSL_EC_KEY_new(); + if (newKey == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); + err = 1; + } + } + + if (!err) { + /* Copy internal EC key. */ + if (wolfssl_ec_key_int_copy((ecc_key*)newKey->internal, + (ecc_key*)src->internal) != 0) { + WOLFSSL_MSG("Copying internal EC key error"); + err = 1; + } + } + if (!err) { + /* Internal key set. */ + newKey->inSet = 1; + + /* Copy group */ + err = wolfssl_ec_group_copy(newKey->group, src->group); + } + /* Copy public key. */ + if ((!err) && (wolfSSL_EC_POINT_copy(newKey->pub_key, src->pub_key) != 1)) { + WOLFSSL_MSG("Copying EC public key error"); + err = 1; + } + + if (!err) { + /* Set header size of private key in PKCS#8 format.*/ + newKey->pkcs8HeaderSz = src->pkcs8HeaderSz; + + /* Copy private key. */ + if (wolfSSL_BN_copy(newKey->priv_key, src->priv_key) == NULL) { + WOLFSSL_MSG("Copying EC private key error"); + err = 1; + } + } + + if (err) { + /* Dispose of EC key on error. */ + wolfSSL_EC_KEY_free(newKey); + newKey = NULL; + } + /* Return the new EC key. */ + return newKey; +} + +#endif /* OPENSSL_ALL */ + +#endif /* !NO_CERTS */ + +/* + * EC key to/from bin/octet APIs + */ + +/* Create an EC key from the octet encoded public key. + * + * Behaviour checked against OpenSSL. + * + * @param [out] key Reference to EC key. Must pass in a valid object with + * group set. + * @param [in, out] in On in, reference to buffer that contains data. + * On out, reference to buffer after public key data. + * @param [in] len Length of data in the buffer. Must be length of the + * encoded public key. + * @return Allocated EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY *wolfSSL_o2i_ECPublicKey(WOLFSSL_EC_KEY **key, + const unsigned char **in, long len) +{ + int err = 0; + WOLFSSL_EC_KEY* ret = NULL; + + WOLFSSL_ENTER("wolfSSL_o2i_ECPublicKey"); + + /* Validate parameters: EC group needed to perform import. */ + if ((key == NULL) || (*key == NULL) || ((*key)->group == NULL) || + (in == NULL) || (*in == NULL) || (len <= 0)) { + WOLFSSL_MSG("wolfSSL_o2i_ECPublicKey Bad arguments"); + err = 1; + } + + if (!err) { + /* Return the EC key object passed in. */ + ret = *key; + + /* Import point into public key field. */ + if (wolfSSL_EC_POINT_oct2point(ret->group, ret->pub_key, *in, + (size_t)len, NULL) != 1) { + WOLFSSL_MSG("wolfSSL_EC_POINT_oct2point error"); + ret = NULL; + err = 1; + } + } + if (!err) { + /* Assumed length passed in is all the data. */ + *in += len; + } + + return ret; +} + +/* Puts the encoded public key into out. + * + * Passing in NULL for out returns length only. + * Passing in NULL for *out has buffer allocated, encoded into and passed back. + * Passing non-NULL for *out has it encoded into and pointer moved past. + * + * @param [in] key EC key to encode. + * @param [in, out] out Reference to buffer to encode into. May be NULL or + * point to NULL. + * @return Length of encoding in bytes on success. + * @return 0 on error. + */ +int wolfSSL_i2o_ECPublicKey(const WOLFSSL_EC_KEY *key, unsigned char **out) +{ + int ret = 1; + size_t len = 0; + int form = WC_POINT_CONVERSION_UNCOMPRESSED; + + WOLFSSL_ENTER("wolfSSL_i2o_ECPublicKey"); + + /* Validate parameters. */ + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_i2o_ECPublicKey Bad arguments"); + ret = 0; + } + + /* Ensure the external key data is set from the internal EC key. */ + if ((ret == 1) && (!key->exSet) && (SetECKeyExternal((WOLFSSL_EC_KEY*) + key) != 1)) { + WOLFSSL_MSG("SetECKeyExternal failure"); + ret = 0; + } + + if (ret == 1) { + #ifdef HAVE_COMP_KEY + /* Default to compressed form if not set */ + form = (key->form == WC_POINT_CONVERSION_UNCOMPRESSED) ? + WC_POINT_CONVERSION_UNCOMPRESSED : + WC_POINT_CONVERSION_COMPRESSED; + #endif + + /* Calculate length of point encoding. */ + len = wolfSSL_EC_POINT_point2oct(key->group, key->pub_key, form, NULL, + 0, NULL); + } + /* Encode if length calculated and pointer supplied to update. */ + if ((ret == 1) && (len != 0) && (out != NULL)) { + unsigned char *tmp = NULL; + + /* Allocate buffer for encoding if no buffer supplied. */ + if (*out == NULL) { + tmp = (unsigned char*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); + if (tmp == NULL) { + WOLFSSL_MSG("malloc failed"); + ret = 0; + } + } + else { + /* Get buffer to encode into. */ + tmp = *out; + } + + /* Encode public key into buffer. */ + if ((ret == 1) && (wolfSSL_EC_POINT_point2oct(key->group, key->pub_key, + form, tmp, len, NULL) == 0)) { + ret = 0; + } + + if (ret == 1) { + /* Return buffer if allocated. */ + if (*out == NULL) { + *out = tmp; + } + else { + /* Step over encoded data if not allocated. */ + *out += len; + } + } + else if (*out == NULL) { + /* Dispose of allocated buffer. */ + XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); + } + } + + if (ret == 1) { + /* Return length on success. */ + ret = (int)len; + } + return ret; +} + +#ifdef HAVE_ECC_KEY_IMPORT +/* Create a EC key from the DER encoded private key. + * + * @param [out] key Reference to EC key. + * @param [in, out] in On in, reference to buffer that contains DER data. + * On out, reference to buffer after private key data. + * @param [in] long Length of data in the buffer. May be larger than the + * length of the encoded private key. + * @return Allocated EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY* wolfSSL_d2i_ECPrivateKey(WOLFSSL_EC_KEY** key, + const unsigned char** in, long len) +{ + int err = 0; + word32 idx = 0; + WOLFSSL_EC_KEY* ret = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_ECPrivateKey"); + + /* Validate parameters. */ + if ((in == NULL) || (*in == NULL) || (len <= 0)) { + WOLFSSL_MSG("wolfSSL_d2i_ECPrivateKey Bad arguments"); + err = 1; + } + + /* Create a new, empty EC key. */ + if ((!err) && ((ret = wolfSSL_EC_KEY_new()) == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); + err = 1; + } + + /* Decode the private key DER data into internal EC key. */ + if ((!err) && (wc_EccPrivateKeyDecode(*in, &idx, (ecc_key*)ret->internal, + (word32)len) != 0)) { + WOLFSSL_MSG("wc_EccPrivateKeyDecode error"); + err = 1; + } + + if (!err) { + /* Internal EC key setup. */ + ret->inSet = 1; + + /* Set the EC key from the internal values. */ + if (SetECKeyExternal(ret) != 1) { + WOLFSSL_MSG("SetECKeyExternal error"); + err = 1; + } + } + + if (!err) { + /* Move buffer on to next byte after data used. */ + *in += idx; + if (key) { + /* Return new EC key through reference. */ + *key = ret; + } + } + + if (err && (ret != NULL)) { + /* Dispose of allocated EC key. */ + wolfSSL_EC_KEY_free(ret); + ret = NULL; + } + return ret; +} +#endif /* HAVE_ECC_KEY_IMPORT */ + +/* Enecode the private key of the EC key into the buffer as DER. + * + * @param [in] key EC key to encode. + * @param [in, out] out On in, reference to buffer to place DER encoding into. + * On out, reference to buffer after the encoding. + * May be NULL. + * @return Length of DER encoding on success. + * @return 0 on error. + */ +int wolfSSL_i2d_ECPrivateKey(const WOLFSSL_EC_KEY *key, unsigned char **out) +{ + int err = 0; + word32 len = 0; + + WOLFSSL_ENTER("wolfSSL_i2d_ECPrivateKey"); + + /* Validate parameters. */ + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_i2d_ECPrivateKey Bad arguments"); + err = 1; + } + + /* Update the internal EC key if not set. */ + if ((!err) && (!key->inSet) && (SetECKeyInternal((WOLFSSL_EC_KEY*)key) != + 1)) { + WOLFSSL_MSG("SetECKeyInternal error"); + err = 1; + } + + /* Calculate the length of the private key DER encoding using internal EC + * key. */ + if ((!err) && ((int)(len = (word32)wc_EccKeyDerSize((ecc_key*)key->internal, + 0)) <= 0)) { + WOLFSSL_MSG("wc_EccKeyDerSize error"); + err = 1; + } + + /* Only return length when out is NULL. */ + if ((!err) && (out != NULL)) { + unsigned char* buf = NULL; + + /* Must have a buffer to encode into. */ + if (*out == NULL) { + /* Allocate a new buffer of appropriate length. */ + buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + /* Error and return 0. */ + err = 1; + len = 0; + } + else { + /* Return the allocated buffer. */ + *out = buf; + } + } + /* Encode the internal EC key as a private key in DER format. */ + if ((!err) && wc_EccPrivateKeyToDer((ecc_key*)key->internal, *out, + len) < 0) { + WOLFSSL_MSG("wc_EccPrivateKeyToDer error"); + err = 1; + } + else if (buf != *out) { + /* Move the reference to byte past encoded private key. */ + *out += len; + } + + /* Dispose of any allocated buffer on error. */ + if (err && (*out == buf)) { + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *out = NULL; + } + } + + return (int)len; +} + +/* Load private key into EC key from DER encoding. + * + * Not an OpenSSL compatibility API. + * + * @param [in, out] key EC key to put private key values into. + * @param [in] derBuf Buffer holding DER encoding. + * @param [in] derSz Size of DER encoding in bytes. + * @return 1 on success. + * @return -1 on error. + */ +int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, + int derSz) +{ + return wolfSSL_EC_KEY_LoadDer_ex(key, derBuf, derSz, + WOLFSSL_EC_KEY_LOAD_PRIVATE); +} + +/* Load private/public key into EC key from DER encoding. + * + * Not an OpenSSL compatibility API. + * + * @param [in, out] key EC key to put private/public key values into. + * @param [in] derBuf Buffer holding DER encoding. + * @param [in] derSz Size of DER encoding in bytes. + * @param [in] opt Key type option. Valid values: + * WOLFSSL_EC_KEY_LOAD_PRIVATE, + * WOLFSSL_EC_KEY_LOAD_PUBLIC. + * @return 1 on success. + * @return -1 on error. + */ +int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, + int derSz, int opt) +{ + int res = 1; + int ret; + word32 idx = 0; + word32 algId; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_LoadDer"); + + /* Validate parameters. */ + if ((key == NULL) || (key->internal == NULL) || (derBuf == NULL) || + (derSz <= 0)) { + WOLFSSL_MSG("Bad function arguments"); + res = WOLFSSL_FATAL_ERROR; + } + if ((res == 1) && (opt != WOLFSSL_EC_KEY_LOAD_PRIVATE) && + (opt != WOLFSSL_EC_KEY_LOAD_PUBLIC)) { + res = WOLFSSL_FATAL_ERROR; + } + + if (res == 1) { + /* Assume no PKCS#8 header. */ + key->pkcs8HeaderSz = 0; + + /* Check if input buffer has PKCS8 header. In the case that it does not + * have a PKCS8 header then do not error out. + */ + if ((ret = ToTraditionalInline_ex((const byte*)derBuf, &idx, + (word32)derSz, &algId)) > 0) { + WOLFSSL_MSG("Found PKCS8 header"); + key->pkcs8HeaderSz = (word16)idx; + res = 1; + } + /* Error out on parsing error. */ + else if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) { + WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header"); + res = WOLFSSL_FATAL_ERROR; + } + } + + if (res == 1) { + /* Load into internal EC key based on key type option. */ + if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) { + ret = wc_EccPrivateKeyDecode(derBuf, &idx, (ecc_key*)key->internal, + (word32)derSz); + } + else { + ret = wc_EccPublicKeyDecode(derBuf, &idx, (ecc_key*)key->internal, + (word32)derSz); + if (ret < 0) { + ecc_key *tmp = (ecc_key*)XMALLOC(sizeof(ecc_key), + ((ecc_key*)key->internal)->heap, DYNAMIC_TYPE_ECC); + if (tmp == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + else { + /* We now try again as x.963 [point type][x][opt y]. */ + ret = wc_ecc_init_ex(tmp, ((ecc_key*)key->internal)->heap, + INVALID_DEVID); + if (ret == 0) { + ret = wc_ecc_import_x963(derBuf, (word32)derSz, tmp); + if (ret == 0) { + /* Take ownership of new key - set tmp to the old + * key which will then be freed below. */ + ecc_key *old = (ecc_key *)key->internal; + key->internal = tmp; + tmp = old; + + idx = (word32)derSz; + } + wc_ecc_free(tmp); + } + XFREE(tmp, ((ecc_key*)key->internal)->heap, + DYNAMIC_TYPE_ECC); + } + } + } + if (ret < 0) { + /* Error returned from wolfSSL. */ + if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) { + WOLFSSL_MSG("wc_EccPrivateKeyDecode failed"); + } + else { + WOLFSSL_MSG("wc_EccPublicKeyDecode failed"); + } + res = WOLFSSL_FATAL_ERROR; + } + + /* Internal key updated - update whether it is a valid key. */ + key->inSet = (res == 1); + } + + /* Set the external EC key based on value in internal. */ + if ((res == 1) && (SetECKeyExternal(key) != 1)) { + WOLFSSL_MSG("SetECKeyExternal failed"); + res = WOLFSSL_FATAL_ERROR; + } + + return res; +} + + +#ifndef NO_BIO + +WOLFSSL_EC_KEY *wolfSSL_d2i_EC_PUBKEY_bio(WOLFSSL_BIO *bio, + WOLFSSL_EC_KEY **out) +{ + char* data = NULL; + int dataSz = 0; + int memAlloced = 0; + WOLFSSL_EC_KEY* ec = NULL; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_d2i_EC_PUBKEY_bio"); + + if (bio == NULL) + return NULL; + + if (err == 0 && wolfssl_read_bio(bio, &data, &dataSz, &memAlloced) != 0) { + WOLFSSL_ERROR_MSG("wolfssl_read_bio failed"); + err = 1; + } + + if (err == 0 && (ec = wolfSSL_EC_KEY_new()) == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_EC_KEY_new failed"); + err = 1; + } + + /* Load the EC key with the public key from the DER encoding. */ + if (err == 0 && wolfSSL_EC_KEY_LoadDer_ex(ec, (const unsigned char*)data, + dataSz, WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1) { + WOLFSSL_ERROR_MSG("wolfSSL_EC_KEY_LoadDer_ex failed"); + err = 1; + } + + if (memAlloced) + XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (err) { /* on error */ + wolfSSL_EC_KEY_free(ec); + ec = NULL; + } + else { /* on success */ + if (out != NULL) + *out = ec; + } + + return ec; +} + +#endif /* !NO_BIO */ + +/* + * EC key PEM APIs + */ + +#ifdef HAVE_ECC_KEY_EXPORT +#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_FILESYSTEM) || !defined(NO_BIO)) +/* Encode the EC public key as DER. + * + * @param [in] key EC 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_ec_key_to_pubkey_der(WOLFSSL_EC_KEY* key, + unsigned char** der, void* heap) +{ + int sz; + unsigned char* buf = NULL; + + (void)heap; + + /* Calculate encoded size to allocate. */ + sz = wc_EccPublicKeyDerSize((ecc_key*)key->internal, 1); + if (sz <= 0) { + WOLFSSL_MSG("wc_EccPublicKeyDerSize failed"); + sz = 0; + } + if (sz > 0) { + /* 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_EccPublicKeyToDer((ecc_key*)key->internal, buf, (word32)sz, 1); + if (sz < 0) { + WOLFSSL_MSG("wc_EccPublicKeyToDer 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; +} +#endif + +#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_KEY_GEN) +/* + * Return code compliant with OpenSSL. + * + * @param [in] fp File pointer to write PEM encoding to. + * @param [in] key EC key to encode and write. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_PEM_write_EC_PUBKEY(XFILE fp, WOLFSSL_EC_KEY* key) +{ + int ret = 1; + unsigned char* derBuf = NULL; + int derSz = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_write_EC_PUBKEY"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (key == NULL)) { + WOLFSSL_MSG("Bad argument."); + return 0; + } + + /* Encode public key in EC key as DER. */ + derSz = wolfssl_ec_key_to_pubkey_der(key, &derBuf, key->heap); + if (derSz == 0) { + ret = 0; + } + + /* Write out to file the PEM encoding of the DER. */ + if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, + ECC_PUBLICKEY_TYPE, key->heap) != 1)) { + ret = 0; + } + + /* Dispose of any dynamically allocated data. */ + XFREE(derBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + + WOLFSSL_LEAVE("wolfSSL_PEM_write_EC_PUBKEY", ret); + + return ret; +} +#endif +#endif + +#ifndef NO_BIO +/* Read a PEM encoded EC public key from a BIO. + * + * @param [in] bio BIO to read EC public key from. + * @param [out] out Pointer to return EC key object through. May be NULL. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM + * encrypted. + * @return New EC key object on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_EC_PUBKEY(WOLFSSL_BIO* bio, + WOLFSSL_EC_KEY** out, wc_pem_password_cb* cb, void *pass) +{ + int err = 0; + WOLFSSL_EC_KEY* ec = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_EC_PUBKEY"); + + /* Validate parameters. */ + if (bio == NULL) { + err = 1; + } + + if (!err) { + /* Create an empty EC key. */ + ec = wolfSSL_EC_KEY_new(); + if (ec == NULL) { + err = 1; + } + } + /* Read a PEM key in to a new DER buffer. */ + if ((!err) && (pem_read_bio_key(bio, cb, pass, ECC_PUBLICKEY_TYPE, + &keyFormat, &der) <= 0)) { + err = 1; + } + /* Load the EC key with the public key from the DER encoding. */ + if ((!err) && (wolfSSL_EC_KEY_LoadDer_ex(ec, der->buffer, (int)der->length, + WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1)) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_KEY"); + err = 1; + } + + /* Dispose of dynamically allocated data not needed anymore. */ + FreeDer(&der); + if (err) { + wolfSSL_EC_KEY_free(ec); + ec = NULL; + } + + /* Return EC key through out if required. */ + if ((out != NULL) && (ec != NULL)) { + *out = ec; + } + return ec; +} + +/* Read a PEM encoded EC private key from a BIO. + * + * @param [in] bio BIO to read EC private key from. + * @param [out] out Pointer to return EC key object through. May be NULL. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM + * encrypted. + * @return New EC key object on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_ECPrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_EC_KEY** out, wc_pem_password_cb* cb, void *pass) +{ + int err = 0; + WOLFSSL_EC_KEY* ec = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_ECPrivateKey"); + + /* Validate parameters. */ + if (bio == NULL) { + err = 1; + } + + if (!err) { + /* Create an empty EC key. */ + ec = wolfSSL_EC_KEY_new(); + if (ec == NULL) { + err = 1; + } + } + /* Read a PEM key in to a new DER buffer. + * To check ENC EC PRIVATE KEY, it uses PRIVATEKEY_TYPE to call + * pem_read_bio_key(), and then check key format if it is EC. + */ + if ((!err) && (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, + &keyFormat, &der) <= 0)) { + err = 1; + } + if (keyFormat != ECDSAk) { + WOLFSSL_ERROR_MSG("Error not EC key format"); + err = 1; + } + /* Load the EC key with the private key from the DER encoding. */ + if ((!err) && (wolfSSL_EC_KEY_LoadDer_ex(ec, der->buffer, (int)der->length, + WOLFSSL_EC_KEY_LOAD_PRIVATE) != 1)) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_KEY"); + err = 1; + } + + /* Dispose of dynamically allocated data not needed anymore. */ + FreeDer(&der); + if (err) { + wolfSSL_EC_KEY_free(ec); + ec = NULL; + } + + /* Return EC key through out if required. */ + if ((out != NULL) && (ec != NULL)) { + *out = ec; + } + return ec; +} +#endif /* !NO_BIO */ + +#if defined(WOLFSSL_KEY_GEN) && defined(HAVE_ECC_KEY_EXPORT) +#ifndef NO_BIO +/* Write out the EC public key as PEM to the BIO. + * + * @param [in] bio BIO to write PEM encoding to. + * @param [in] ec EC public key to encode. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_PEM_write_bio_EC_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec) +{ + int ret = 1; + unsigned char* derBuf = NULL; + int derSz = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_EC_PUBKEY"); + + /* Validate parameters. */ + if ((bio == NULL) || (ec == NULL)) { + WOLFSSL_MSG("Bad Function Arguments"); + return 0; + } + + /* Encode public key in EC key as DER. */ + derSz = wolfssl_ec_key_to_pubkey_der(ec, &derBuf, ec->heap); + if (derSz == 0) { + ret = 0; + } + + /* 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; + } + + /* Dispose of any dynamically allocated data. */ + XFREE(derBuf, ec->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/* Write out the EC private key as PEM to the BIO. + * + * Return code compliant with OpenSSL. + * + * @param [in] bio BIO to write PEM encoding to. + * @param [in] ec EC private key to encode. + * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. + * @param [in] passwd Password string when PEM encrypted. May be NULL. + * @param [in] passwdSz Length of password string when PEM encrypted. + * @param [in] cb Password callback when PEM encrypted. Unused. + * @param [in] pass NUL terminated string for passphrase when PEM + * encrypted. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_PEM_write_bio_ECPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, + wc_pem_password_cb* cb, void* arg) +{ + int ret = 1; + unsigned char* pem = NULL; + int pLen = 0; + + (void)cb; + (void)arg; + + /* Validate parameters. */ + if ((bio == NULL) || (ec == NULL)) { + ret = 0; + } + + /* Write EC private key to PEM. */ + if ((ret == 1) && (wolfSSL_PEM_write_mem_ECPrivateKey(ec, cipher, passwd, + passwdSz, &pem, &pLen) != 1)) { + ret = 0; + } + /* Write PEM to BIO. */ + if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) != pLen)) { + WOLFSSL_ERROR_MSG("EC private key BIO write failed"); + ret = 0; + } + + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + + return ret; +} + +#endif /* !NO_BIO */ + +/* Encode the EC private key as PEM into buffer. + * + * Return code compliant with OpenSSL. + * Not an OpenSSL API. + * + * @param [in] ec EC private key to encode. + * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. + * @param [in] passwd Password string when PEM encrypted. May be NULL. + * @param [in] passwdSz Length of password string when PEM encrypted. + * @param [out] pem Newly allocated buffer holding PEM encoding. + * @param [out] pLen Length of PEM encoding in bytes. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* ec, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, + unsigned char **pem, int *pLen) +{ +#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) + int ret = 1; + byte* derBuf = NULL; + word32 der_max_len = 0; + int derSz = 0; + + WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey"); + + /* Validate parameters. */ + if ((pem == NULL) || (pLen == NULL) || (ec == NULL) || + (ec->internal == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = 0; + } + + /* Ensure internal EC key is set from external. */ + if ((ret == 1) && (ec->inSet == 0)) { + WOLFSSL_MSG("No ECC internal set, do it"); + + if (SetECKeyInternal(ec) != 1) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = 0; + } + } + + if (ret == 1) { + /* Calculate maximum size of DER encoding. + * 4 > size of pub, priv + ASN.1 additional information */ + der_max_len = 4 * (word32)wc_ecc_size((ecc_key*)ec->internal) + + WC_AES_BLOCK_SIZE; + + /* Allocate buffer big enough to hold encoding. */ + derBuf = (byte*)XMALLOC((size_t)der_max_len, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + WOLFSSL_MSG("malloc failed"); + ret = 0; + } + } + + if (ret == 1) { + /* Encode EC private key as DER. */ + derSz = wc_EccKeyToDer((ecc_key*)ec->internal, derBuf, der_max_len); + if (derSz < 0) { + WOLFSSL_MSG("wc_EccKeyToDer failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + ret = 0; + } + } + + /* Convert DER to PEM - possibly encrypting. */ + if ((ret == 1) && (der_to_enc_pem_alloc(derBuf, derSz, cipher, passwd, + passwdSz, ECC_PRIVATEKEY_TYPE, NULL, pem, pLen) != 1)) { + WOLFSSL_ERROR_MSG("der_to_enc_pem_alloc failed"); + ret = 0; + } + + return ret; +#else + (void)ec; + (void)cipher; + (void)passwd; + (void)passwdSz; + (void)pem; + (void)pLen; + return 0; +#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ +} + +#ifndef NO_FILESYSTEM +/* Write out the EC private key as PEM to file. + * + * Return code compliant with OpenSSL. + * + * @param [in] fp File pointer to write PEM encoding to. + * @param [in] ec EC private key to encode. + * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. + * @param [in] passwd Password string when PEM encrypted. May be NULL. + * @param [in] passwdSz Length of password string when PEM encrypted. + * @param [in] cb Password callback when PEM encrypted. Unused. + * @param [in] pass NUL terminated string for passphrase when PEM + * encrypted. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_PEM_write_ECPrivateKey(XFILE fp, WOLFSSL_EC_KEY *ec, + const WOLFSSL_EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz, + wc_pem_password_cb *cb, void *pass) +{ + int ret = 1; + byte *pem = NULL; + int pLen = 0; + + (void)cb; + (void)pass; + + WOLFSSL_MSG("wolfSSL_PEM_write_ECPrivateKey"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (ec == NULL) || (ec->internal == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = 0; + } + + /* Write EC private key to PEM. */ + if ((ret == 1) && (wolfSSL_PEM_write_mem_ECPrivateKey(ec, cipher, passwd, + passwdSz, &pem, &pLen) != 1)) { + WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey failed"); + ret = 0; + } + + /* Write out to file the PEM encoding of the EC private key. */ + if ((ret == 1) && ((int)XFWRITE(pem, 1, (size_t)pLen, fp) != pLen)) { + WOLFSSL_MSG("ECC private key file write failed"); + ret = 0; + } + + /* Dispose of any dynamically allocated data. */ + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + + return ret; +} + +#endif /* NO_FILESYSTEM */ +#endif /* WOLFSSL_KEY_GEN && HAVE_ECC_KEY_EXPORT */ + +/* + * EC key print APIs + */ + +#ifndef NO_CERTS + +#if defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \ + !defined(NO_STDIO_FILESYSTEM) +/* Print the EC key to a file pointer as text. + * + * @param [in] fp File pointer. + * @param [in] key EC key to print. + * @param [in] indent Number of spaces to place before each line printed. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_EC_KEY_print_fp(XFILE fp, WOLFSSL_EC_KEY* key, int indent) +{ + int ret = 1; + int bits = 0; + int priv = 0; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_print_fp"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (key == NULL) || (key->group == NULL) || + (indent < 0)) { + ret = 0; + } + + if (ret == 1) { + /* Get EC groups order size in bits. */ + bits = wolfSSL_EC_GROUP_order_bits(key->group); + if (bits <= 0) { + WOLFSSL_MSG("Failed to get group order bits."); + ret = 0; + } + } + if (ret == 1) { + const char* keyType; + + /* Determine whether this is a private or public key. */ + if ((key->priv_key != NULL) && (!wolfSSL_BN_is_zero(key->priv_key))) { + keyType = "Private-Key"; + priv = 1; + } + else { + keyType = "Public-Key"; + } + + /* Print key header. */ + if (XFPRINTF(fp, "%*s%s: (%d bit)\n", indent, "", keyType, bits) < 0) { + ret = 0; + } + } + if ((ret == 1) && priv) { + /* Print the private key BN. */ + ret = pk_bn_field_print_fp(fp, indent, "priv", key->priv_key); + } + /* Check for public key data in EC key. */ + if ((ret == 1) && (key->pub_key != NULL) && (key->pub_key->exSet)) { + /* Get the public key point as one BN. */ + WOLFSSL_BIGNUM* pubBn = wolfSSL_EC_POINT_point2bn(key->group, + key->pub_key, WC_POINT_CONVERSION_UNCOMPRESSED, NULL, NULL); + if (pubBn == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_point2bn failed."); + ret = 0; + } + else { + /* Print the public key in a BN. */ + ret = pk_bn_field_print_fp(fp, indent, "pub", pubBn); + wolfSSL_BN_free(pubBn); + } + } + if (ret == 1) { + /* Get the NID of the group. */ + int nid = wolfSSL_EC_GROUP_get_curve_name(key->group); + if (nid > 0) { + /* Convert the NID into a long name and NIST name. */ + const char* curve = wolfSSL_OBJ_nid2ln(nid); + const char* nistName = wolfSSL_EC_curve_nid2nist(nid); + + /* Print OID name if known. */ + if ((curve != NULL) && + (XFPRINTF(fp, "%*sASN1 OID: %s\n", indent, "", curve) < 0)) { + ret = 0; + } + /* Print NIST curve name if known. */ + if ((nistName != NULL) && + (XFPRINTF(fp, "%*sNIST CURVE: %s\n", indent, "", + nistName) < 0)) { + ret = 0; + } + } + } + + + WOLFSSL_LEAVE("wolfSSL_EC_KEY_print_fp", ret); + + return ret; +} +#endif /* XFPRINTF && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ + +#endif /* !NO_CERTS */ + +/* + * EC_KEY get/set/test APIs + */ + +/* Set data of internal, wolfCrypt EC key object into EC key. + * + * EC_KEY wolfSSL -> OpenSSL + * + * @param [in, out] p EC key to update. + * @return 1 on success. + * @return -1 on failure. + */ +int SetECKeyExternal(WOLFSSL_EC_KEY* eckey) +{ + int ret = 1; + + WOLFSSL_ENTER("SetECKeyExternal"); + + /* Validate parameter. */ + if ((eckey == NULL) || (eckey->internal == NULL)) { + WOLFSSL_MSG("ec key NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + ecc_key* key = (ecc_key*)eckey->internal; + + /* Set group (OID, nid and idx) from wolfCrypt EC key. */ + eckey->group->curve_oid = (int)key->dp->oidSum; + eckey->group->curve_nid = EccEnumToNID(key->dp->id); + eckey->group->curve_idx = key->idx; + + if (eckey->pub_key->internal != NULL) { + /* Copy internal public point from internal key's public point. */ + if (wc_ecc_copy_point(&key->pubkey, + (ecc_point*)eckey->pub_key->internal) != MP_OKAY) { + WOLFSSL_MSG("SetECKeyExternal ecc_copy_point failed"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Set external public key from internal wolfCrypt, public key. */ + if ((ret == 1) && (ec_point_external_set(eckey->pub_key) != 1)) { + WOLFSSL_MSG("SetECKeyExternal ec_point_external_set failed"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + /* set the external privkey */ + if ((ret == 1) && (key->type == ECC_PRIVATEKEY) && + (wolfssl_bn_set_value(&eckey->priv_key, + wc_ecc_key_get_priv(key)) != 1)) { + WOLFSSL_MSG("ec priv key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* External values set when operations succeeded. */ + eckey->exSet = (ret == 1); + } + + return ret; +} + +/* Set data of EC key into internal, wolfCrypt EC key object. + * + * EC_KEY Openssl -> WolfSSL + * + * @param [in, out] p EC key to update. + * @return 1 on success. + * @return -1 on failure. + */ +int SetECKeyInternal(WOLFSSL_EC_KEY* eckey) +{ + int ret = 1; + + WOLFSSL_ENTER("SetECKeyInternal"); + + /* Validate parameter. */ + if ((eckey == NULL) || (eckey->internal == NULL) || + (eckey->group == NULL)) { + WOLFSSL_MSG("ec key NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + ecc_key* key = (ecc_key*)eckey->internal; + int pubSet = 0; + + /* Validate group. */ + if ((eckey->group->curve_idx < 0) || + (wc_ecc_is_valid_idx(eckey->group->curve_idx) == 0)) { + WOLFSSL_MSG("invalid curve idx"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + /* Set group (idx of curve and corresponding domain parameters). */ + key->idx = eckey->group->curve_idx; + key->dp = &ecc_sets[key->idx]; + pubSet = (eckey->pub_key != NULL); + } + /* Set public key (point). */ + if ((ret == 1) && pubSet) { + if (ec_point_internal_set(eckey->pub_key) != 1) { + WOLFSSL_MSG("ec key pub error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Copy public point to key. */ + if ((ret == 1) && (wc_ecc_copy_point( + (ecc_point*)eckey->pub_key->internal, &key->pubkey) != + MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_copy_point error"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + /* Set that the internal key is a public key */ + key->type = ECC_PUBLICKEY; + } + } + + /* set privkey */ + if ((ret == 1) && (eckey->priv_key != NULL)) { + if (wolfssl_bn_get_value(eckey->priv_key, + wc_ecc_key_get_priv(key)) != 1) { + WOLFSSL_MSG("ec key priv error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* private key */ + if ((ret == 1) && (!mp_iszero(wc_ecc_key_get_priv(key)))) { + if (pubSet) { + key->type = ECC_PRIVATEKEY; + } + else { + key->type = ECC_PRIVATEKEY_ONLY; + } + } + } + + /* Internal values set when operations succeeded. */ + eckey->inSet = (ret == 1); + } + + return ret; +} + +/* Get point conversion format of EC key. + * + * @param [in] key EC key. + * @return Point conversion format on success. + * @return -1 on error. + */ +wc_point_conversion_form_t wolfSSL_EC_KEY_get_conv_form( + const WOLFSSL_EC_KEY* key) +{ + if (key == NULL) + return WOLFSSL_FATAL_ERROR; + return key->form; +} + +/* Set point conversion format into EC key. + * + * @param [in, out] key EC key to set format into. + * @param [in] form Point conversion format. Valid values: + * WC_POINT_CONVERSION_UNCOMPRESSED, + * WC_POINT_CONVERSION_COMPRESSED (when HAVE_COMP_KEY) + */ +void wolfSSL_EC_KEY_set_conv_form(WOLFSSL_EC_KEY *key, int form) +{ + if (key == NULL) { + WOLFSSL_MSG("Key passed in NULL"); + } + else if (form == WC_POINT_CONVERSION_UNCOMPRESSED +#ifdef HAVE_COMP_KEY + || form == WC_POINT_CONVERSION_COMPRESSED +#endif + ) { + key->form = (unsigned char)form; + } + else { + WOLFSSL_MSG("Incorrect form or HAVE_COMP_KEY not compiled in"); + } +} + +/* Get the EC group object that is in EC key. + * + * @param [in] key EC key. + * @return EC group object on success. + * @return NULL when key is NULL. + */ +const WOLFSSL_EC_GROUP *wolfSSL_EC_KEY_get0_group(const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_EC_GROUP* group = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_group"); + + if (key != NULL) { + group = key->group; + } + + return group; +} + +/* Set the group in WOLFSSL_EC_KEY + * + * @param [in, out] key EC key to update. + * @param [in] group EC group to copy. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC_KEY_set_group(WOLFSSL_EC_KEY *key, WOLFSSL_EC_GROUP *group) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_group"); + + /* Validate parameters. */ + if ((key == NULL) || (group == NULL)) { + ret = 0; + } + + if (ret == 1) { + /* Dispose of the current group. */ + if (key->group != NULL) { + wolfSSL_EC_GROUP_free(key->group); + } + /* Duplicate the passed in group into EC key. */ + key->group = wolfSSL_EC_GROUP_dup(group); + if (key->group == NULL) { + ret = 0; + } + } + + return ret; +} + +/* Get the BN object that is the private key in the EC key. + * + * @param [in] key EC key. + * @return BN object on success. + * @return NULL when key is NULL or private key is not set. + */ +WOLFSSL_BIGNUM *wolfSSL_EC_KEY_get0_private_key(const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_BIGNUM* priv_key = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_private_key"); + + /* Validate parameter. */ + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_get0_private_key Bad arguments"); + } + /* Only return private key if it is not 0. */ + else if (!wolfSSL_BN_is_zero(key->priv_key)) { + priv_key = key->priv_key; + } + + return priv_key; +} + +/* Sets the private key value into EC key. + * + * Return code compliant with OpenSSL. + * + * @param [in, out] key EC key to set. + * @param [in] priv_key Private key value in a BN. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC_KEY_set_private_key(WOLFSSL_EC_KEY *key, + const WOLFSSL_BIGNUM *priv_key) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_private_key"); + + /* Validate parameters. */ + if ((key == NULL) || (priv_key == NULL)) { + WOLFSSL_MSG("Bad arguments"); + ret = 0; + } + + /* Check for obvious invalid values. */ + if (wolfSSL_BN_is_negative(priv_key) || wolfSSL_BN_is_zero(priv_key) || + wolfSSL_BN_is_one(priv_key)) { + WOLFSSL_MSG("Invalid private key value"); + ret = 0; + } + + if (ret == 1) { + /* Free key if previously set. */ + if (key->priv_key != NULL) { + wolfSSL_BN_free(key->priv_key); + } + + /* Duplicate the BN passed in. */ + key->priv_key = wolfSSL_BN_dup(priv_key); + if (key->priv_key == NULL) { + WOLFSSL_MSG("key ecc priv key NULL"); + ret = 0; + } + } + /* Set the external values into internal EC key. */ + if ((ret == 1) && (SetECKeyInternal(key) != 1)) { + WOLFSSL_MSG("SetECKeyInternal failed"); + /* Dispose of new private key on error. */ + wolfSSL_BN_free(key->priv_key); + key->priv_key = NULL; + ret = 0; + } + + return ret; +} + +/* Get the public key EC point object that is in EC key. + * + * @param [in] key EC key. + * @return EC point object that is the public key on success. + * @return NULL when key is NULL. + */ +WOLFSSL_EC_POINT* wolfSSL_EC_KEY_get0_public_key(const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_EC_POINT* pub_key = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_public_key"); + + if (key != NULL) { + pub_key = key->pub_key; + } + + return pub_key; +} + +/* + * Return code compliant with OpenSSL. + * + * @param [in, out] key EC key. + * @param [in] pub Public key as an EC point. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC_KEY_set_public_key(WOLFSSL_EC_KEY *key, + const WOLFSSL_EC_POINT *pub) +{ + int ret = 1; + ecc_point *pub_p = NULL; + ecc_point *key_p = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_public_key"); + + /* Validate parameters. */ + if ((key == NULL) || (key->internal == NULL) || (pub == NULL) || + (pub->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_KEY_set_public_key Bad arguments"); + ret = 0; + } + + /* Ensure the internal EC key is set. */ + if ((ret == 1) && (key->inSet == 0) && (SetECKeyInternal(key) != 1)) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = 0; + } + + /* Ensure the internal EC point of pub is setup. */ + if ((ret == 1) && (ec_point_setup(pub) != 1)) { + ret = 0; + } + + if (ret == 1) { + /* Get the internal point of pub and the public key in key. */ + pub_p = (ecc_point*)pub->internal; + key_p = (ecc_point*)key->pub_key->internal; + + /* Create new point if required. */ + if (key_p == NULL) { + key_p = wc_ecc_new_point(); + key->pub_key->internal = (void*)key_p; + } + /* Check point available. */ + if (key_p == NULL) { + WOLFSSL_MSG("key ecc point NULL"); + ret = 0; + } + } + + /* Copy the internal pub point into internal key point. */ + if ((ret == 1) && (wc_ecc_copy_point(pub_p, key_p) != MP_OKAY)) { + WOLFSSL_MSG("ecc_copy_point failure"); + ret = 0; + } + + /* Copy the internal point data into external. */ + if ((ret == 1) && (ec_point_external_set(key->pub_key) != 1)) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = 0; + } + + /* Copy the internal key into external. */ + if ((ret == 1) && (SetECKeyInternal(key) != 1)) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = 0; + } + + if (ret == 1) { + /* Dump out the point and the key's public key for debug. */ + wolfSSL_EC_POINT_dump("pub", pub); + wolfSSL_EC_POINT_dump("key->pub_key", key->pub_key); + } + + return ret; +} + +#ifndef NO_WOLFSSL_STUB +/* Set the ASN.1 encoding flag against the EC key. + * + * No implementation as only named curves supported for encoding. + * + * @param [in, out] key EC key. + * @param [in] flag ASN.1 flag to set. Valid values: + * OPENSSL_EC_EXPLICIT_CURVE, OPENSSL_EC_NAMED_CURVE + */ +void wolfSSL_EC_KEY_set_asn1_flag(WOLFSSL_EC_KEY *key, int asn1_flag) +{ + (void)key; + (void)asn1_flag; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_asn1_flag"); + WOLFSSL_STUB("EC_KEY_set_asn1_flag"); +} +#endif + +/* + * EC key generate key APIs + */ + +/* Generate an EC key. + * + * Uses the internal curve index set in the EC key or the default. + * + * @param [in, out] key EC key. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC_KEY_generate_key(WOLFSSL_EC_KEY *key) +{ + int res = 1; + int initTmpRng = 0; + WC_RNG* rng = NULL; + WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); + + WOLFSSL_ENTER("wolfSSL_EC_KEY_generate_key"); + + /* Validate parameters. */ + if ((key == NULL) || (key->internal == NULL) || (key->group == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key Bad arguments"); + res = 0; + } + if (res == 1) { + /* Check if we know which internal curve index to use. */ + if (key->group->curve_idx < 0) { + /* Generate key using the default curve. */ +#if FIPS_VERSION3_GE(6,0,0) + key->group->curve_idx = ECC_SECP256R1; /* FIPS default to 256 */ +#else + key->group->curve_idx = ECC_CURVE_DEF; +#endif + } + + /* 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; + } + } + if (res == 1) { + /* NIDToEccEnum returns -1 for invalid NID so if key->group->curve_nid + * is 0 then pass ECC_CURVE_DEF as arg */ + int eccEnum = key->group->curve_nid ? +#if FIPS_VERSION3_GE(6,0,0) + NIDToEccEnum(key->group->curve_nid) : ECC_SECP256R1; +#else + NIDToEccEnum(key->group->curve_nid) : ECC_CURVE_DEF; +#endif + /* Get the internal EC key. */ + ecc_key* ecKey = (ecc_key*)key->internal; + /* Make the key using internal API. */ + int ret = 0; + +#if FIPS_VERSION3_GE(6,0,0) + /* In the case of FIPS only allow key generation with approved curves */ + if (eccEnum != ECC_SECP256R1 && eccEnum != ECC_SECP224R1 && + eccEnum != ECC_SECP384R1 && eccEnum != ECC_SECP521R1) { + WOLFSSL_MSG("Unsupported curve selected in FIPS mode"); + res = 0; + } + if (res == 1) { +#endif + ret = wc_ecc_make_key_ex(rng, 0, ecKey, eccEnum); +#if FIPS_VERSION3_GE(6,0,0) + } +#endif + + #if defined(WOLFSSL_ASYNC_CRYPT) + /* Wait on asynchronouse operation. */ + ret = wc_AsyncWait(ret, &ecKey->asyncDev, WC_ASYNC_FLAG_NONE); + #endif + if (ret != 0) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key wc_ecc_make_key failed"); + res = 0; + } + } + + /* Dispose of local random number generator if initialized. */ + if (initTmpRng) { + wc_FreeRng(rng); + WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); + } + + /* Set the external key from new internal key values. */ + if ((res == 1) && (SetECKeyExternal(key) != 1)) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key SetECKeyExternal failed"); + res = 0; + } + + return res; +} + +/* + * EC key check key APIs + */ + +/* Check that the EC key is valid. + * + * @param [in] key EC key. + * @return 1 on valid. + * @return 0 on invalid or error. + */ +int wolfSSL_EC_KEY_check_key(const WOLFSSL_EC_KEY *key) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_check_key"); + + /* Validate parameter. */ + if ((key == NULL) || (key->internal == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = 0; + } + + /* Set the external EC key values into internal if not already. */ + if ((ret == 1) && (key->inSet == 0) && (SetECKeyInternal( + (WOLFSSL_EC_KEY*)key) != 1)) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = 0; + } + + if (ret == 1) { + /* Have internal EC implementation check key. */ + ret = wc_ecc_check_key((ecc_key*)key->internal) == 0; + } + + return ret; +} + +/* End EC_KEY */ + +#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) +/* Get the supported, built-in EC curves + * + * @param [in, out] curves Pre-allocated list to put supported curves into. + * @param [in] len Maximum number of items to place in list. + * @return Number of built-in EC curves when curves is NULL or len is 0. + * @return Number of items placed in list otherwise. + */ +size_t wolfSSL_EC_get_builtin_curves(WOLFSSL_EC_BUILTIN_CURVE *curves, + size_t len) +{ + size_t i; + size_t cnt; +#ifdef HAVE_SELFTEST + /* Defined in ecc.h when available. */ + size_t ecc_sets_count; + + /* Count the pre-defined curves since global not available. */ + for (i = 0; ecc_sets[i].size != 0 && ecc_sets[i].name != NULL; i++) { + /* Do nothing. */ + } + ecc_sets_count = i; +#endif + + /* Assume we are going to return total count. */ + cnt = ecc_sets_count; + /* Check we have a list that can hold data. */ + if ((curves != NULL) && (len != 0)) { + /* Limit count to length of list. */ + if (cnt > len) { + cnt = len; + } + + /* Put in built-in EC curve nid and short name. */ + for (i = 0; i < cnt; i++) { + curves[i].nid = EccEnumToNID(ecc_sets[i].id); + curves[i].comment = wolfSSL_OBJ_nid2sn(curves[i].nid); + } + } + + return cnt; +} +#endif /* !HAVE_FIPS || FIPS_VERSION_GT(2,0) */ + +/* Start ECDSA_SIG */ + +/* Allocate a new ECDSA signature object. + * + * @return New, allocated ECDSA signature object on success. + * @return NULL on error. + */ +WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_SIG_new(void) +{ + int err = 0; + WOLFSSL_ECDSA_SIG *sig; + + WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_new"); + + /* Allocate memory for ECDSA signature object. */ + sig = (WOLFSSL_ECDSA_SIG*)XMALLOC(sizeof(WOLFSSL_ECDSA_SIG), NULL, + DYNAMIC_TYPE_ECC); + if (sig == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA signature failure"); + err = 1; + } + + if (!err) { + /* Set s to NULL in case of error. */ + sig->s = NULL; + /* Allocate BN into r. */ + sig->r = wolfSSL_BN_new(); + if (sig->r == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA r failure"); + err = 1; + } + } + if (!err) { + /* Allocate BN into s. */ + sig->s = wolfSSL_BN_new(); + if (sig->s == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA s failure"); + err = 1; + } + } + + if (err && (sig != NULL)) { + /* Dispose of allocated memory. */ + wolfSSL_ECDSA_SIG_free(sig); + sig = NULL; + } + return sig; +} + +/* Dispose of ECDSA signature object. + * + * Cannot use object after this call. + * + * @param [in] sig ECDSA signature object to free. + */ +void wolfSSL_ECDSA_SIG_free(WOLFSSL_ECDSA_SIG *sig) +{ + WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_free"); + + if (sig != NULL) { + /* Dispose of BNs allocated for r and s. */ + wolfSSL_BN_free(sig->r); + wolfSSL_BN_free(sig->s); + + /* Dispose of memory associated with ECDSA signature object. */ + XFREE(sig, NULL, DYNAMIC_TYPE_ECC); + } +} + +/* Create an ECDSA signature from the DER encoding. + * + * @param [in, out] sig Reference to ECDSA signature object. May be NULL. + * @param [in, out] pp On in, reference to buffer containing DER encoding. + * On out, reference to buffer after signature data. + * @param [in] len Length of the data in the buffer. May be more than + * the length of the signature. + * @return ECDSA signature object on success. + * @return NULL on error. + */ +WOLFSSL_ECDSA_SIG* wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG** sig, + const unsigned char** pp, long len) +{ + int err = 0; + /* ECDSA signature object to return. */ + WOLFSSL_ECDSA_SIG *s = NULL; + + /* Validate parameter. */ + if (pp == NULL) { + err = 1; + } + if (!err) { + if (sig != NULL) { + /* Use the ECDSA signature object passed in. */ + s = *sig; + } + if (s == NULL) { + /* No ECDSA signature object passed in - create a new one. */ + s = wolfSSL_ECDSA_SIG_new(); + if (s == NULL) { + err = 1; + } + } + } + if (!err) { + /* DecodeECC_DSA_Sig calls mp_init, so free these. */ + mp_free((mp_int*)s->r->internal); + mp_free((mp_int*)s->s->internal); + + /* Decode the signature into internal r and s fields. */ + if (DecodeECC_DSA_Sig(*pp, (word32)len, (mp_int*)s->r->internal, + (mp_int*)s->s->internal) != MP_OKAY) { + err = 1; + } + } + + if (!err) { + /* Move pointer passed signature data successfully decoded. */ + *pp += wolfssl_der_length(*pp, (int)len); + if (sig != NULL) { + /* Update reference to ECDSA signature object. */ + *sig = s; + } + } + + /* Dispose of newly allocated object on error. */ + if (err) { + if ((s != NULL) && ((sig == NULL) || (*sig != s))) { + wolfSSL_ECDSA_SIG_free(s); + } + /* Return NULL for object on error. */ + s = NULL; + } + return s; +} + +/* Encode the ECDSA signature as DER. + * + * @param [in] sig ECDSA signature object. + * @param [in, out] pp On in, reference to buffer in which to place encoding. + * On out, reference to buffer after encoding. + * May be NULL or point to NULL in which case no encoding + * is done. + * @return Length of encoding on success. + * @return 0 on error. + */ +int wolfSSL_i2d_ECDSA_SIG(const WOLFSSL_ECDSA_SIG *sig, unsigned char **pp) +{ + word32 len = 0; + int update_p = 1; + + /* Validate parameter. */ + if (sig != NULL) { + /* ASN.1: SEQ + INT + INT + * ASN.1 Integer must be a positive value - prepend zero if number has + * top bit set. + */ + /* Get total length of r including any prepended zero. */ + word32 rLen = (word32)(mp_leading_bit((mp_int*)sig->r->internal) + + mp_unsigned_bin_size((mp_int*)sig->r->internal)); + /* Get total length of s including any prepended zero. */ + word32 sLen = (word32)(mp_leading_bit((mp_int*)sig->s->internal) + + mp_unsigned_bin_size((mp_int*)sig->s->internal)); + /* Calculate length of data in sequence. */ + len = (word32)1 + ASN_LEN_SIZE(rLen) + rLen + + (word32)1 + ASN_LEN_SIZE(sLen) + sLen; + /* Add in the length of the SEQUENCE. */ + len += (word32)1 + ASN_LEN_SIZE(len); + + #ifdef WOLFSSL_I2D_ECDSA_SIG_ALLOC + if ((pp != NULL) && (*pp == NULL)) { + *pp = (unsigned char *)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); + if (*pp != NULL) { + WOLFSSL_MSG("malloc error"); + return 0; + } + update_p = 0; + } + #endif + + /* Encode only if there is a buffer to encode into. */ + if ((pp != NULL) && (*pp != NULL)) { + /* Encode using the internal representations of r and s. */ + if (StoreECC_DSA_Sig(*pp, &len, (mp_int*)sig->r->internal, + (mp_int*)sig->s->internal) != MP_OKAY) { + /* No bytes encoded. */ + len = 0; + } + else if (update_p) { + /* Update pointer to after encoding. */ + *pp += len; + } + } + } + + return (int)len; +} + +/* Get the pointer to the fields of the ECDSA signature. + * + * r and s untouched when sig is NULL. + * + * @param [in] sig ECDSA signature object. + * @param [out] r R field of ECDSA signature as a BN. May be NULL. + * @param [out] s S field of ECDSA signature as a BN. May be NULL. + */ +void wolfSSL_ECDSA_SIG_get0(const WOLFSSL_ECDSA_SIG* sig, + const WOLFSSL_BIGNUM** r, const WOLFSSL_BIGNUM** s) +{ + /* Validate parameter. */ + if (sig != NULL) { + /* Return the r BN when pointer to return through. */ + if (r != NULL) { + *r = sig->r; + } + /* Return the s BN when pointer to return through. */ + if (s != NULL) { + *s = sig->s; + } + } +} + +/* Set the pointers to the fields of the ECDSA signature. + * + * @param [in, out] sig ECDSA signature object to update. + * @param [in] r R field of ECDSA signature as a BN. + * @param [in] s S field of ECDSA signature as a BN. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_ECDSA_SIG_set0(WOLFSSL_ECDSA_SIG* sig, WOLFSSL_BIGNUM* r, + WOLFSSL_BIGNUM* s) +{ + int ret = 1; + + /* Validate parameters. */ + if ((sig == NULL) || (r == NULL) || (s == NULL)) { + ret = 0; + } + + if (ret == 1) { + /* Dispose of old BN objects. */ + wolfSSL_BN_free(sig->r); + wolfSSL_BN_free(sig->s); + + /* Assign new BN objects. */ + sig->r = r; + sig->s = s; + } + + return ret; +} + +/* End ECDSA_SIG */ + +/* Start ECDSA */ + +/* Calculate maximum size of the DER encoded ECDSA signature for the curve. + * + * @param [in] key EC key. + * @return Size of DER encoded signature on success. + * @return 0 on error. + */ +int wolfSSL_ECDSA_size(const WOLFSSL_EC_KEY *key) +{ + int err = 0; + int len = 0; + const WOLFSSL_EC_GROUP *group = NULL; + int bits = 0; + + /* Validate parameter. */ + if (key == NULL) { + err = 1; + } + + /* Get group from key to get order bits. */ + if ((!err) && ((group = wolfSSL_EC_KEY_get0_group(key)) == NULL)) { + err = 1; + } + /* Get order bits of group. */ + if ((!err) && ((bits = wolfSSL_EC_GROUP_order_bits(group)) == 0)) { + /* Group is not set. */ + err = 1; + } + + if (!err) { + /* r and s are mod order. */ + int bytes = (bits + 7) / 8; /* Bytes needed to hold bits. */ + len = SIG_HEADER_SZ + /* 2*ASN_TAG + 2*LEN(ENUM) */ + ECC_MAX_PAD_SZ + /* possible leading zeroes in r and s */ + bytes + bytes; /* max r and s in bytes */ + } + + return len; +} + +/* Create ECDSA signature by signing digest with key. + * + * @param [in] dgst Digest to sign. + * @param [in] dLen Length of digest in bytes. + * @param [in] key EC key to sign with. + * @return ECDSA signature object on success. + * @return NULL on error. + */ +WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_do_sign(const unsigned char *dgst, int dLen, + WOLFSSL_EC_KEY *key) +{ + int err = 0; + WOLFSSL_ECDSA_SIG *sig = NULL; + WC_DECLARE_VAR(out, byte, ECC_BUFSIZE, 0); + unsigned int outLen = ECC_BUFSIZE; + + WOLFSSL_ENTER("wolfSSL_ECDSA_do_sign"); + + /* Validate parameters. */ + if ((dgst == NULL) || (key == NULL) || (key->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign Bad arguments"); + err = 1; + } + + /* Ensure internal EC key is set from external. */ + if ((!err) && (key->inSet == 0)) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign No EC key internal set, do it"); + + if (SetECKeyInternal(key) != 1) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign SetECKeyInternal failed"); + err = 1; + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (!err) { + /* Allocate buffer to hold encoded signature. */ + out = (byte*)XMALLOC(outLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (out == NULL) { + err = 1; + } + } +#endif + + /* Sign the digest with the key to create encoded ECDSA signature. */ + if ((!err) && (wolfSSL_ECDSA_sign(0, dgst, dLen, out, &outLen, key) != 1)) { + err = 1; + } + + if (!err) { + const byte* p = out; + /* Decode the ECDSA signature into a new object. */ + sig = wolfSSL_d2i_ECDSA_SIG(NULL, &p, outLen); + } + + WC_FREE_VAR_EX(out, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return sig; +} + +/* Verify ECDSA signature in the object using digest and key. + * + * Return code compliant with OpenSSL. + * + * @param [in] dgst Digest to verify. + * @param [in] dLen Length of the digest in bytes. + * @param [in] sig ECDSA signature object. + * @param [in] key EC key containing public key. + * @return 1 when signature is valid. + * @return 0 when signature is invalid. + * @return -1 on error. + */ +int wolfSSL_ECDSA_do_verify(const unsigned char *dgst, int dLen, + const WOLFSSL_ECDSA_SIG *sig, WOLFSSL_EC_KEY *key) +{ + int ret = 1; + int verified = 0; +#ifdef WOLF_CRYPTO_CB_ONLY_ECC + byte signature[ECC_MAX_SIG_SIZE]; + int signatureLen; + byte* p = signature; +#endif + + WOLFSSL_ENTER("wolfSSL_ECDSA_do_verify"); + + /* Validate parameters. */ + if ((dgst == NULL) || (sig == NULL) || (key == NULL) || + (key->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_verify Bad arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Ensure internal EC key is set from external. */ + if ((ret == 1) && (key->inSet == 0)) { + WOLFSSL_MSG("No EC key internal set, do it"); + + if (SetECKeyInternal(key) != 1) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 1) { +#ifndef WOLF_CRYPTO_CB_ONLY_ECC + /* Verify hash using digest, r and s as MP ints and internal EC key. */ + if (wc_ecc_verify_hash_ex((mp_int*)sig->r->internal, + (mp_int*)sig->s->internal, dgst, (word32)dLen, &verified, + (ecc_key *)key->internal) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_verify_hash failed"); + ret = WOLFSSL_FATAL_ERROR; + } + else if (verified == 0) { + WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected"); + ret = 0; + } +#else + signatureLen = i2d_ECDSA_SIG(sig, &p); + if (signatureLen > 0) { + /* verify hash. expects to call wc_CryptoCb_EccVerify internally */ + ret = wc_ecc_verify_hash(signature, signatureLen, dgst, + (word32)dLen, &verified, (ecc_key*)key->internal); + if (ret != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_verify_hash failed"); + ret = WOLFSSL_FATAL_ERROR; + } + else if (verified == 0) { + WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected"); + ret = 0; + } + } +#endif /* WOLF_CRYPTO_CB_ONLY_ECC */ + } + + return ret; +} + +/* Sign the digest with the key to produce a DER encode signature. + * + * @param [in] type Digest algorithm used to create digest. Unused. + * @param [in] digest Digest of the message to sign. + * @param [in] digestSz Size of the digest in bytes. + * @param [out] sig Buffer to hold signature. + * @param [in, out] sigSz On in, size of buffer in bytes. + * On out, size of signatre in bytes. + * @param [in] key EC key containing private key. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_ECDSA_sign(int type, const unsigned char *digest, int digestSz, + unsigned char *sig, unsigned int *sigSz, WOLFSSL_EC_KEY *key) +{ + int ret = 1; + WC_RNG* rng = NULL; + WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); + int initTmpRng = 0; + + WOLFSSL_ENTER("wolfSSL_ECDSA_sign"); + + /* Digest algorithm not used in DER encoding. */ + (void)type; + + /* Validate parameters. */ + if (key == NULL) { + ret = 0; + } + + if (ret == 1) { + /* Make an RNG - create local or get global. */ + rng = wolfssl_make_rng(tmpRng, &initTmpRng); + if (rng == NULL) { + ret = 0; + } + } + /* Sign the digest with the key using the RNG and put signature into buffer + * update sigSz to be actual length. + */ + if ((ret == 1) && (wc_ecc_sign_hash(digest, (word32)digestSz, sig, sigSz, + rng, (ecc_key*)key->internal) != 0)) { + ret = 0; + } + + if (initTmpRng) { + wc_FreeRng(rng); + WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); + } + + return ret; +} + +/* Verify the signature with the digest and key. + * + * @param [in] type Digest algorithm used to create digest. Unused. + * @param [in] digest Digest of the message to verify. + * @param [in] digestSz Size of the digest in bytes. + * @param [in] sig Buffer holding signature. + * @param [in] sigSz Size of signature data in bytes. + * @param [in] key EC key containing public key. + * @return 1 when signature is valid. + * @return 0 when signature is invalid or error. + */ +int wolfSSL_ECDSA_verify(int type, const unsigned char *digest, int digestSz, + const unsigned char *sig, int sigSz, WOLFSSL_EC_KEY *key) +{ + int ret = 1; + int verify = 0; + + WOLFSSL_ENTER("wolfSSL_ECDSA_verify"); + + /* Digest algorithm not used in DER encoding. */ + (void)type; + + /* Validate parameters. */ + if (key == NULL) { + ret = 0; + } + + /* Verify signature using digest and key. */ + if ((ret == 1) && (wc_ecc_verify_hash(sig, (word32)sigSz, digest, + (word32)digestSz, &verify, (ecc_key*)key->internal) != 0)) { + ret = 0; + } + /* When no error, verification may still have failed - check now. */ + if ((ret == 1) && (verify != 1)) { + WOLFSSL_MSG("wolfSSL_ECDSA_verify failed"); + ret = 0; + } + + return ret; +} + +/* End ECDSA */ + +/* Start ECDH */ + +#ifndef WOLF_CRYPTO_CB_ONLY_ECC +/* Compute the shared secret (key) using ECDH. + * + * KDF not supported. + * + * Return code compliant with OpenSSL. + * + * @param [out] out Buffer to hold key. + * @param [in] outLen Length of buffer in bytes. + * @param [in] pubKey Public key as an EC point. + * @param [in] privKey EC key holding a private key. + * @param [in] kdf Key derivation function to apply to secret. + * @return Length of computed key on success + * @return 0 on error. + */ +int wolfSSL_ECDH_compute_key(void *out, size_t outLen, + const WOLFSSL_EC_POINT *pubKey, WOLFSSL_EC_KEY *privKey, + void *(*kdf) (const void *in, size_t inlen, void *out, size_t *outLen)) +{ + int err = 0; + word32 len = 0; + ecc_key* key = NULL; +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) + int setGlobalRNG = 0; +#endif + + /* TODO: support using the KDF. */ + (void)kdf; + + WOLFSSL_ENTER("wolfSSL_ECDH_compute_key"); + + /* Validate parameters. */ + if ((out == NULL) || (pubKey == NULL) || (pubKey->internal == NULL) || + (privKey == NULL) || (privKey->internal == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + err = 1; + } + + /* Ensure internal EC key is set from external. */ + if ((!err) && (privKey->inSet == 0)) { + WOLFSSL_MSG("No EC key internal set, do it"); + + if (SetECKeyInternal(privKey) != 1) { + WOLFSSL_MSG("SetECKeyInternal failed"); + err = 1; + } + } + + if (!err) { + int ret; + + /* Get the internal key. */ + key = (ecc_key*)privKey->internal; + /* Set length into variable of type suitable for wolfSSL API. */ + len = (word32)outLen; + + #if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) + /* An RNG is needed. */ + if (key->rng == NULL) { + key->rng = wolfssl_make_global_rng(); + /* RNG set and needs to be unset. */ + setGlobalRNG = 1; + } + #endif + + PRIVATE_KEY_UNLOCK(); + /* Create secret using wolfSSL. */ + ret = wc_ecc_shared_secret_ex(key, (ecc_point*)pubKey->internal, + (byte *)out, &len); + PRIVATE_KEY_LOCK(); + if (ret != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_shared_secret failed"); + err = 1; + } + } + +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) + /* Remove global from key. */ + if (setGlobalRNG) { + key->rng = NULL; + } +#endif + + if (err) { + /* Make returned value zero. */ + len = 0; + } + return (int)len; +} +#endif /* WOLF_CRYPTO_CB_ONLY_ECC */ + +/* End ECDH */ + +#ifndef NO_WOLFSSL_STUB +const WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_OpenSSL(void) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_OpenSSL"); + + return NULL; +} + +WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_METHOD_new( + const WOLFSSL_EC_KEY_METHOD *meth) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_new"); + + (void)meth; + + return NULL; +} + +void wolfSSL_EC_KEY_METHOD_free(WOLFSSL_EC_KEY_METHOD *meth) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_free"); + + (void)meth; +} + +void wolfSSL_EC_KEY_METHOD_set_init(WOLFSSL_EC_KEY_METHOD *meth, + void* a1, void* a2, void* a3, void* a4, void* a5, void* a6) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_set_init"); + + (void)meth; + (void)a1; + (void)a2; + (void)a3; + (void)a4; + (void)a5; + (void)a6; +} + +void wolfSSL_EC_KEY_METHOD_set_sign(WOLFSSL_EC_KEY_METHOD *meth, + void* a1, void* a2, void* a3) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_set_sign"); + + (void)meth; + (void)a1; + (void)a2; + (void)a3; +} + +const WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_get_method( + const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_get_method"); + + (void)key; + + return NULL; +} + +int wolfSSL_EC_KEY_set_method(WOLFSSL_EC_KEY *key, + const WOLFSSL_EC_KEY_METHOD *meth) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_set_method"); + + (void)key; + (void)meth; + + return 0; +} + +#endif /* !NO_WOLFSSL_STUB */ + +#endif /* OPENSSL_EXTRA */ + +#endif /* HAVE_ECC */ + +/******************************************************************************* + * END OF EC API + ******************************************************************************/ + +#endif /* !WOLFSSL_PK_EC_INCLUDED */ + diff --git a/src/pk_rsa.c b/src/pk_rsa.c new file mode 100644 index 0000000000..abef08bf8d --- /dev/null +++ b/src/pk_rsa.c @@ -0,0 +1,3943 @@ +/* pk_rsa.c + * + * Copyright (C) 2006-2025 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 3 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 + */ + +#include + +#include +#ifndef WC_NO_RNG + #include +#endif + +#if !defined(WOLFSSL_PK_RSA_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning pk_rsa.c does not need to be compiled separately from ssl.c + #endif +#else + +#ifndef NO_RSA + #include +#endif + +/******************************************************************************* + * START OF RSA API + ******************************************************************************/ + +#ifndef NO_RSA + +/* + * RSA METHOD + * Could be used to hold function pointers to implementations of RSA operations. + */ + +#if defined(OPENSSL_EXTRA) +/* Return a blank RSA method and set the name and flags. + * + * Only one implementation of RSA operations. + * name is duplicated. + * + * @param [in] name Name to use in method. + * @param [in] flags Flags to set into method. + * @return Newly allocated RSA method on success. + * @return NULL on failure. + */ +WOLFSSL_RSA_METHOD *wolfSSL_RSA_meth_new(const char *name, int flags) +{ + WOLFSSL_RSA_METHOD* meth = NULL; + int name_len = 0; + int err; + + /* Validate name is not NULL. */ + if (name == NULL) + return NULL; + /* Allocate an RSA METHOD to return. */ + meth = (WOLFSSL_RSA_METHOD*)XMALLOC(sizeof(WOLFSSL_RSA_METHOD), NULL, + DYNAMIC_TYPE_OPENSSL); + if (meth == NULL) + return NULL; + + XMEMSET(meth, 0, sizeof(*meth)); + meth->flags = flags; + meth->dynamic = 1; + + name_len = (int)XSTRLEN(name); + meth->name = (char*)XMALLOC((size_t)(name_len + 1), NULL, + DYNAMIC_TYPE_OPENSSL); + err = (meth->name == NULL); + + if (!err) { + XMEMCPY(meth->name, name, (size_t)(name_len + 1)); + } + + if (err) { + /* meth->name won't be allocated on error. */ + XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL); + meth = NULL; + } + return meth; +} + +/* Default RSA method is one with wolfSSL name and no flags. + * + * @return Newly allocated wolfSSL RSA method on success. + * @return NULL on failure. + */ +const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_default_method(void) +{ + static const WOLFSSL_RSA_METHOD wolfssl_rsa_meth = { + 0, /* No flags. */ + (char*)"wolfSSL RSA", + 0 /* Static definition. */ + }; + return &wolfssl_rsa_meth; +} + +/* Dispose of RSA method and allocated data. + * + * @param [in] meth RSA method to free. + */ +void wolfSSL_RSA_meth_free(WOLFSSL_RSA_METHOD *meth) +{ + /* Free method if available and dynamically allocated. */ + if ((meth != NULL) && meth->dynamic) { + /* Name was duplicated and must be freed. */ + XFREE(meth->name, NULL, DYNAMIC_TYPE_OPENSSL); + /* Dispose of RSA method. */ + XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +#ifndef NO_WOLFSSL_STUB +/* Stub function for any RSA method setting function. + * + * Nothing is stored - not even flags or name. + * + * @param [in] meth RSA method. + * @param [in] p A pointer. + * @return 1 to indicate success. + */ +int wolfSSL_RSA_meth_set(WOLFSSL_RSA_METHOD *meth, void* p) +{ + WOLFSSL_STUB("RSA_METHOD is not implemented."); + + (void)meth; + (void)p; + + return 1; +} +#endif /* !NO_WOLFSSL_STUB */ +#endif /* OPENSSL_EXTRA */ + +/* + * RSA constructor/deconstructor APIs + */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Dispose of RSA key and allocated data. + * + * Cannot use rsa after this call. + * + * @param [in] rsa RSA key to free. + */ +void wolfSSL_RSA_free(WOLFSSL_RSA* rsa) +{ + int doFree = 1; + + WOLFSSL_ENTER("wolfSSL_RSA_free"); + + /* Validate parameter. */ + if (rsa == NULL) { + doFree = 0; + } + if (doFree) { + int err; + + /* Decrement reference count. */ + wolfSSL_RefDec(&rsa->ref, &doFree, &err); + #ifndef WOLFSSL_REFCNT_ERROR_RETURN + (void)err; + #endif + } + if (doFree) { + void* heap = rsa->heap; + + /* Dispose of allocated reference counting data. */ + wolfSSL_RefFree(&rsa->ref); + + #ifdef HAVE_EX_DATA_CLEANUP_HOOKS + wolfSSL_CRYPTO_cleanup_ex_data(&rsa->ex_data); + #endif + + if (rsa->internal != NULL) { + #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) + /* Check if RNG is owned before freeing it. */ + if (rsa->ownRng) { + WC_RNG* rng = ((RsaKey*)(rsa->internal))->rng; + if ((rng != NULL) && (rng != wolfssl_get_global_rng())) { + wc_FreeRng(rng); + XFREE(rng, heap, DYNAMIC_TYPE_RNG); + } + /* RNG isn't freed by wolfCrypt RSA free. */ + } + #endif + /* Dispose of allocated data in wolfCrypt RSA key. */ + wc_FreeRsaKey((RsaKey*)rsa->internal); + /* Dispose of memory for wolfCrypt RSA key. */ + XFREE(rsa->internal, heap, DYNAMIC_TYPE_RSA); + } + + /* Dispose of external representation of RSA values. */ + wolfSSL_BN_clear_free(rsa->iqmp); + wolfSSL_BN_clear_free(rsa->dmq1); + wolfSSL_BN_clear_free(rsa->dmp1); + wolfSSL_BN_clear_free(rsa->q); + wolfSSL_BN_clear_free(rsa->p); + wolfSSL_BN_clear_free(rsa->d); + wolfSSL_BN_free(rsa->e); + wolfSSL_BN_free(rsa->n); + + #if defined(OPENSSL_EXTRA) + if (rsa->meth) { + wolfSSL_RSA_meth_free((WOLFSSL_RSA_METHOD*)rsa->meth); + } + #endif + + /* Set back to NULLs for safety. */ + ForceZero(rsa, sizeof(*rsa)); + + XFREE(rsa, heap, DYNAMIC_TYPE_RSA); + (void)heap; + } +} + +/* Allocate and initialize a new RSA key. + * + * Not OpenSSL API. + * + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] devId Device identifier value. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_RSA_new_ex(void* heap, int devId) +{ + WOLFSSL_RSA* rsa = NULL; + RsaKey* key = NULL; + int err = 0; + int rsaKeyInited = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_new"); + + /* Allocate memory for new wolfCrypt RSA key. */ + key = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA); + if (key == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_new malloc RsaKey failure"); + err = 1; + } + if (!err) { + /* Allocate memory for new RSA key. */ + rsa = (WOLFSSL_RSA*)XMALLOC(sizeof(WOLFSSL_RSA), heap, + DYNAMIC_TYPE_RSA); + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_new malloc WOLFSSL_RSA failure"); + err = 1; + } + } + if (!err) { + /* Clear all fields of RSA key. */ + XMEMSET(rsa, 0, sizeof(WOLFSSL_RSA)); + /* Cache heap to use for all allocations. */ + rsa->heap = heap; + #ifdef OPENSSL_EXTRA + /* Always have a method set. */ + rsa->meth = wolfSSL_RSA_get_default_method(); + #endif + + /* Initialize reference counting. */ + wolfSSL_RefInit(&rsa->ref, &err); +#ifdef WOLFSSL_REFCNT_ERROR_RETURN + } + if (!err) { +#endif + /* Initialize wolfCrypt RSA key. */ + if (wc_InitRsaKey_ex(key, heap, devId) != 0) { + WOLFSSL_ERROR_MSG("InitRsaKey WOLFSSL_RSA failure"); + err = 1; + } + else { + rsaKeyInited = 1; + } + } + #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) + if (!err) { + WC_RNG* rng; + + /* Create a local RNG. */ + rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), heap, DYNAMIC_TYPE_RNG); + if ((rng != NULL) && (wc_InitRng_ex(rng, heap, devId) != 0)) { + WOLFSSL_MSG("InitRng failure, attempting to use global RNG"); + XFREE(rng, heap, DYNAMIC_TYPE_RNG); + rng = NULL; + } + + rsa->ownRng = 1; + if (rng == NULL) { + /* Get the wolfSSL global RNG - not thread safe. */ + rng = wolfssl_get_global_rng(); + rsa->ownRng = 0; + } + if (rng == NULL) { + /* Couldn't create global either. */ + WOLFSSL_ERROR_MSG("wolfSSL_RSA_new no WC_RNG for blinding"); + err = 1; + } + else { + /* Set the local or global RNG into the wolfCrypt RSA key. */ + (void)wc_RsaSetRNG(key, rng); + /* Won't fail as key and rng are not NULL. */ + } + } + #endif /* !HAVE_FIPS && WC_RSA_BLINDING */ + if (!err) { + /* Set wolfCrypt RSA key into RSA key. */ + rsa->internal = key; + /* Data from external RSA key has not been set into internal one. */ + rsa->inSet = 0; + } + + if (err) { + /* Dispose of any allocated data on error. */ + /* No failure after RNG allocation - no need to free RNG. */ + if (rsaKeyInited) { + wc_FreeRsaKey(key); + } + XFREE(key, heap, DYNAMIC_TYPE_RSA); + XFREE(rsa, heap, DYNAMIC_TYPE_RSA); + /* Return NULL. */ + rsa = NULL; + } + return rsa; +} + +/* Allocate and initialize a new RSA key. + * + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_RSA_new(void) +{ + /* Call wolfSSL API to do work. */ + return wolfSSL_RSA_new_ex(NULL, INVALID_DEVID); +} + +/* Increments ref count of RSA key. + * + * @param [in, out] rsa RSA key. + * @return 1 on success + * @return 0 on error + */ +int wolfSSL_RSA_up_ref(WOLFSSL_RSA* rsa) +{ + int err = 0; + if (rsa != NULL) { + wolfSSL_RefInc(&rsa->ref, &err); + } + return !err; +} + +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#ifdef OPENSSL_EXTRA + +#if defined(WOLFSSL_KEY_GEN) + +/* Allocate a new RSA key and make it a copy. + * + * Encodes to and from DER to copy. + * + * @param [in] rsa RSA key to duplicate. + * @return RSA key on success. + * @return NULL on error. + */ +WOLFSSL_RSA* wolfSSL_RSAPublicKey_dup(WOLFSSL_RSA *rsa) +{ + WOLFSSL_RSA* ret = NULL; + int derSz = 0; + byte* derBuf = NULL; + int err; + + WOLFSSL_ENTER("wolfSSL_RSAPublicKey_dup"); + + err = (rsa == NULL); + if (!err) { + /* Create a new RSA key to return. */ + ret = wolfSSL_RSA_new(); + if (ret == NULL) { + WOLFSSL_ERROR_MSG("Error creating a new WOLFSSL_RSA structure"); + err = 1; + } + } + if (!err) { + /* Encode RSA public key to copy to DER - allocates DER buffer. */ + if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, rsa->heap)) < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + err = 1; + } + } + if (!err) { + /* Decode DER of the RSA public key into new key. */ + if (wolfSSL_RSA_LoadDer_ex(ret, derBuf, derSz, + WOLFSSL_RSA_LOAD_PUBLIC) != 1) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_LoadDer_ex failed"); + err = 1; + } + } + + /* Dispose of any allocated DER buffer. */ + XFREE(derBuf, rsa ? rsa->heap : NULL, DYNAMIC_TYPE_ASN1); + if (err) { + /* Disposes of any created RSA key - on error. */ + wolfSSL_RSA_free(ret); + ret = NULL; + } + return ret; +} + +/* wolfSSL_RSAPrivateKey_dup not supported */ + +#endif /* WOLFSSL_KEY_GEN */ + +static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, + void* heap); + +/* + * RSA to/from bin APIs + */ + +/* Convert RSA public key data to internal. + * + * Creates new RSA key from the DER encoded RSA public key. + * + * @param [out] out Pointer to RSA key to return through. May be NULL. + * @param [in, out] derBuf Pointer to start of DER encoded data. + * @param [in] derSz Length of the data in the DER buffer. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA *wolfSSL_d2i_RSAPublicKey(WOLFSSL_RSA **out, + const unsigned char **derBuf, long derSz) +{ + WOLFSSL_RSA *rsa = NULL; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_d2i_RSAPublicKey"); + + /* Validate parameters. */ + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("Bad argument"); + err = 1; + } + /* Create a new RSA key to return. */ + if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { + WOLFSSL_ERROR_MSG("RSA_new failed"); + err = 1; + } + /* Decode RSA key from DER. */ + if ((!err) && (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz, + WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { + WOLFSSL_ERROR_MSG("RSA_LoadDer failed"); + err = 1; + } + if ((!err) && (out != NULL)) { + /* Return through parameter too. */ + *out = rsa; + /* Move buffer on by the used amount. */ + *derBuf += wolfssl_der_length(*derBuf, (int)derSz); + } + + if (err) { + /* Dispose of any created RSA key. */ + wolfSSL_RSA_free(rsa); + rsa = NULL; + } + return rsa; +} + +/* Convert RSA private key data to internal. + * + * Create a new RSA key from the DER encoded RSA private key. + * + * @param [out] out Pointer to RSA key to return through. May be NULL. + * @param [in, out] derBuf Pointer to start of DER encoded data. + * @param [in] derSz Length of the data in the DER buffer. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA *wolfSSL_d2i_RSAPrivateKey(WOLFSSL_RSA **out, + const unsigned char **derBuf, long derSz) +{ + WOLFSSL_RSA *rsa = NULL; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_d2i_RSAPublicKey"); + + /* Validate parameters. */ + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("Bad argument"); + err = 1; + } + /* Create a new RSA key to return. */ + if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { + WOLFSSL_ERROR_MSG("RSA_new failed"); + err = 1; + } + /* Decode RSA key from DER. */ + if ((!err) && (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz, + WOLFSSL_RSA_LOAD_PRIVATE) != 1)) { + WOLFSSL_ERROR_MSG("RSA_LoadDer failed"); + err = 1; + } + if ((!err) && (out != NULL)) { + /* Return through parameter too. */ + *out = rsa; + /* Move buffer on by the used amount. */ + *derBuf += wolfssl_der_length(*derBuf, (int)derSz); + } + + if (err) { + /* Dispose of any created RSA key. */ + wolfSSL_RSA_free(rsa); + rsa = NULL; + } + return rsa; +} + +/* Converts an internal RSA structure to DER format for the private key. + * + * If "pp" is null then buffer size only is returned. + * If "*pp" is null then a created buffer is set in *pp and the caller is + * responsible for free'ing it. + * + * @param [in] rsa RSA key. + * @param [in, out] pp On in, pointer to allocated buffer or NULL. + * May be NULL. + * On out, newly allocated buffer or pointer to byte after + * encoding in passed in buffer. + * + * @return Size of DER encoding on success + * @return BAD_FUNC_ARG when rsa is NULL. + * @return 0 on failure. + */ +int wolfSSL_i2d_RSAPrivateKey(WOLFSSL_RSA *rsa, unsigned char **pp) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_i2d_RSAPrivateKey"); + + /* Validate parameters. */ + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Bad Function Arguments"); + ret = BAD_FUNC_ARG; + } + /* Encode the RSA key as a DER. Call allocates buffer into pp. + * No heap hint as this gets returned to the user */ + else if ((ret = wolfSSL_RSA_To_Der_ex(rsa, pp, 0, NULL)) < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + ret = 0; + } + + /* Size of DER encoding. */ + return ret; +} + +/* Converts an internal RSA structure to DER format for the public key. + * + * If "pp" is null then buffer size only is returned. + * If "*pp" is null then a created buffer is set in *pp and the caller is + * responsible for free'ing it. + * + * @param [in] rsa RSA key. + * @param [in, out] pp On in, pointer to allocated buffer or NULL. + * May be NULL. + * On out, newly allocated buffer or pointer to byte after + * encoding in passed in buffer. + * @return Size of DER encoding on success + * @return BAD_FUNC_ARG when rsa is NULL. + * @return 0 on failure. + */ +int wolfSSL_i2d_RSAPublicKey(WOLFSSL_RSA *rsa, unsigned char **pp) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_i2d_RSAPublicKey"); + + /* check for bad functions arguments */ + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Bad Function Arguments"); + ret = BAD_FUNC_ARG; + } + /* Encode the RSA key as a DER. Call allocates buffer into pp. + * No heap hint as this gets returned to the user */ + else if ((ret = wolfSSL_RSA_To_Der_ex(rsa, pp, 1, NULL)) < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + ret = 0; + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +/* + * RSA to/from BIO APIs + */ + +/* wolfSSL_d2i_RSAPublicKey_bio not supported */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ + || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) + +#if defined(WOLFSSL_KEY_GEN) && !defined(NO_BIO) + +/* Read DER data from a BIO. + * + * DER structures start with a constructed sequence. Use this to calculate the + * total length of the DER data. + * + * @param [in] bio BIO object to read from. + * @param [out] out Buffer holding DER encoding. + * @return Number of bytes to DER encoding on success. + * @return 0 on failure. + */ +static int wolfssl_read_der_bio(WOLFSSL_BIO* bio, unsigned char** out) +{ + int err = 0; + unsigned char seq[MAX_SEQ_SZ]; + unsigned char* der = NULL; + int derLen = 0; + + /* Read in a minimal amount to get a SEQUENCE header of any size. */ + if (wolfSSL_BIO_read(bio, seq, sizeof(seq)) != sizeof(seq)) { + WOLFSSL_ERROR_MSG("wolfSSL_BIO_read() of sequence failure"); + err = 1; + } + /* Calculate complete DER encoding length. */ + if ((!err) && ((derLen = wolfssl_der_length(seq, sizeof(seq))) <= 0)) { + WOLFSSL_ERROR_MSG("DER SEQUENCE decode failed"); + err = 1; + } + /* Allocate a buffer to read DER data into. */ + if ((!err) && ((der = (unsigned char*)XMALLOC((size_t)derLen, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER)) == NULL)) { + WOLFSSL_ERROR_MSG("Malloc failure"); + err = 1; + } + if ((!err) && (derLen <= (int)sizeof(seq))) { + /* Copy the previously read data into the buffer. */ + XMEMCPY(der, seq, derLen); + } + else if (!err) { + /* Calculate the unread amount. */ + int len = derLen - (int)sizeof(seq); + /* Copy the previously read data into the buffer. */ + XMEMCPY(der, seq, sizeof(seq)); + /* Read rest of DER data from BIO. */ + if (wolfSSL_BIO_read(bio, der + sizeof(seq), len) != len) { + WOLFSSL_ERROR_MSG("wolfSSL_BIO_read() failure"); + err = 1; + } + } + if (!err) { + /* Return buffer through parameter. */ + *out = der; + } + + if (err) { + /* Dispose of any allocated buffer on error. */ + XFREE(der, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + derLen = 0; + } + return derLen; +} + +/* Reads the RSA private key data from a BIO to the internal form. + * + * Creates new RSA key from the DER encoded RSA private key read from the BIO. + * + * @param [in] bio BIO object to read from. + * @param [out] out Pointer to RSA key to return through. May be NULL. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_d2i_RSAPrivateKey_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out) +{ + WOLFSSL_RSA* key = NULL; + unsigned char* der = NULL; + int derLen = 0; + int err; + + WOLFSSL_ENTER("wolfSSL_d2i_RSAPrivateKey_bio"); + + /* Validate parameters. */ + err = (bio == NULL); + /* Read just DER encoding from BIO - buffer allocated in call. */ + if ((!err) && ((derLen = wolfssl_read_der_bio(bio, &der)) == 0)) { + err = 1; + } + if (!err) { + /* Keep der for call to deallocate. */ + const unsigned char* cder = der; + /* Create an RSA key from the data from the BIO. */ + key = wolfSSL_d2i_RSAPrivateKey(NULL, &cder, derLen); + err = (key == NULL); + } + if ((!err) && (out != NULL)) { + /* Return the created RSA key through the parameter. */ + *out = key; + } + + if (err) { + /* Dispose of created key on error. */ + wolfSSL_RSA_free(key); + key = NULL; + } + /* Dispose of allocated data. */ + XFREE(der, bio ? bio->heap : NULL, DYNAMIC_TYPE_TMP_BUFFER); + return key; +} +#endif /* defined(WOLFSSL_KEY_GEN) && !NO_BIO */ + +#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ + +/* + * RSA DER APIs + */ + +#ifdef OPENSSL_EXTRA + +/* Create a DER encoding of key. + * + * Not OpenSSL API. + * + * @param [in] rsa RSA key. + * @param [out] outBuf Allocated buffer containing DER encoding. + * May be NULL. + * @param [in] publicKey Whether to encode as public key. + * @param [in] heap Heap hint. + * @return Encoding size on success. + * @return Negative on failure. + */ +int wolfSSL_RSA_To_Der(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, + void* heap) +{ + byte* p = NULL; + int ret; + + if (outBuf != NULL) { + p = *outBuf; + } + ret = wolfSSL_RSA_To_Der_ex(rsa, outBuf, publicKey, heap); + if ((ret > 0) && (p != NULL)) { + *outBuf = p; + } + return ret; +} + +/* Create a DER encoding of key. + * + * Buffer allocated with heap and DYNAMIC_TYPE_TMP_BUFFER. + * + * @param [in] rsa RSA key. + * @param [in, out] outBuf On in, pointer to allocated buffer or NULL. + * May be NULL. + * On out, newly allocated buffer or pointer to byte + * after encoding in passed in buffer. + * @param [in] publicKey Whether to encode as public key. + * @param [in] heap Heap hint. + * @return Encoding size on success. + * @return Negative on failure. + */ +static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, + void* heap) +{ + int ret = 1; + int derSz = 0; + byte* derBuf = NULL; + + WOLFSSL_ENTER("wolfSSL_RSA_To_Der"); + + /* Unused if memory is disabled. */ + (void)heap; + + /* Validate parameters. */ + if ((rsa == NULL) || ((publicKey != 0) && (publicKey != 1))) { + WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", BAD_FUNC_ARG); + ret = BAD_FUNC_ARG; + } + /* Push external RSA data into internal RSA key if not set. */ + if ((ret == 1) && (!rsa->inSet)) { + ret = SetRsaInternal(rsa); + } + /* wc_RsaKeyToPublicDer encode regardless of values. */ + if ((ret == 1) && publicKey && (mp_iszero(&((RsaKey*)rsa->internal)->n) || + mp_iszero(&((RsaKey*)rsa->internal)->e))) { + ret = BAD_FUNC_ARG; + } + + if (ret == 1) { + if (publicKey) { + /* Calculate length of DER encoded RSA public key. */ + derSz = wc_RsaPublicKeyDerSize((RsaKey*)rsa->internal, 1); + if (derSz < 0) { + WOLFSSL_ERROR_MSG("wc_RsaPublicKeyDerSize failed"); + ret = derSz; + } + } + else { + /* Calculate length of DER encoded RSA private key. */ + derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, NULL, 0); + if (derSz < 0) { + WOLFSSL_ERROR_MSG("wc_RsaKeyToDer failed"); + ret = derSz; + } + } + } + + if ((ret == 1) && (outBuf != NULL)) { + derBuf = *outBuf; + if (derBuf == NULL) { + /* Allocate buffer to hold DER encoded RSA key. */ + derBuf = (byte*)XMALLOC((size_t)derSz, heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("Memory allocation failed"); + ret = MEMORY_ERROR; + } + } + } + if ((ret == 1) && (outBuf != NULL)) { + if (publicKey > 0) { + /* RSA public key to DER. */ + derSz = wc_RsaKeyToPublicDer((RsaKey*)rsa->internal, derBuf, + (word32)derSz); + } + else { + /* RSA private key to DER. */ + derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, derBuf, + (word32)derSz); + } + if (derSz < 0) { + WOLFSSL_ERROR_MSG("RSA key encoding failed"); + ret = derSz; + } + else if ((*outBuf) != NULL) { + derBuf = NULL; + *outBuf += derSz; + } + else { + /* Return allocated buffer. */ + *outBuf = derBuf; + } + } + if (ret == 1) { + /* Success - return DER encoding size. */ + ret = derSz; + } + + if ((outBuf != NULL) && (*outBuf != derBuf)) { + /* Not returning buffer, needs to be disposed of. */ + XFREE(derBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); + } + WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", ret); + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Load the DER encoded private RSA key. + * + * Not OpenSSL API. + * + * @param [in] rsa RSA key. + * @param [in] derBuf Buffer holding DER encoding. + * @param [in] derSz Length of DER encoding. + * @return 1 on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_LoadDer(WOLFSSL_RSA* rsa, const unsigned char* derBuf, + int derSz) +{ + /* Call implementation that handles both private and public keys. */ + return wolfSSL_RSA_LoadDer_ex(rsa, derBuf, derSz, WOLFSSL_RSA_LOAD_PRIVATE); +} + +/* Load the DER encoded public or private RSA key. + * + * Not OpenSSL API. + * + * @param [in] rsa RSA key. + * @param [in] derBuf Buffer holding DER encoding. + * @param [in] derSz Length of DER encoding. + * @param [in] opt Indicates public or private key. + * (WOLFSSL_RSA_LOAD_PUBLIC or WOLFSSL_RSA_LOAD_PRIVATE) + * @return 1 on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_LoadDer_ex(WOLFSSL_RSA* rsa, const unsigned char* derBuf, + int derSz, int opt) +{ + int ret = 1; + int res; + word32 idx = 0; + word32 algId; + + WOLFSSL_ENTER("wolfSSL_RSA_LoadDer"); + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->internal == NULL) || (derBuf == NULL) || + (derSz <= 0)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + rsa->pkcs8HeaderSz = 0; + /* Check if input buffer has PKCS8 header. In the case that it does not + * have a PKCS8 header then do not error out. */ + res = ToTraditionalInline_ex((const byte*)derBuf, &idx, (word32)derSz, + &algId); + if (res > 0) { + /* Store size of PKCS#8 header for encoding. */ + WOLFSSL_MSG("Found PKCS8 header"); + rsa->pkcs8HeaderSz = (word16)idx; + } + /* When decoding and not PKCS#8, return will be ASN_PARSE_E. */ + else if (res != WC_NO_ERR_TRACE(ASN_PARSE_E)) { + /* Something went wrong while decoding. */ + WOLFSSL_ERROR_MSG("Unexpected error with trying to remove PKCS#8 " + "header"); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Decode private or public key data. */ + if (opt == WOLFSSL_RSA_LOAD_PRIVATE) { + res = wc_RsaPrivateKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, + (word32)derSz); + } + else { + res = wc_RsaPublicKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, + (word32)derSz); + } + /* Check for error. */ + if (res < 0) { + if (opt == WOLFSSL_RSA_LOAD_PRIVATE) { + WOLFSSL_ERROR_MSG("RsaPrivateKeyDecode failed"); + } + else { + WOLFSSL_ERROR_MSG("RsaPublicKeyDecode failed"); + } + WOLFSSL_ERROR_VERBOSE(res); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Set external RSA key data from wolfCrypt key. */ + if (SetRsaExternal(rsa) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + else { + rsa->inSet = 1; + } + } + + return ret; +} + +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) + +#if !defined(NO_BIO) || !defined(NO_FILESYSTEM) +/* Load DER encoded data into WOLFSSL_RSA object. + * + * Creates a new WOLFSSL_RSA object if one is not passed in. + * + * @param [in, out] rsa WOLFSSL_RSA object to load into. + * When rsa or *rsa is NULL a new object is created. + * When not NULL and *rsa is NULL then new object + * returned through pointer. + * @param [in] in DER encoded RSA key data. + * @param [in] inSz Size of DER encoded data in bytes. + * @param [in] opt Public or private key encoded in data. Valid values: + * WOLFSSL_RSA_LOAD_PRIVATE, WOLFSSL_RSA_LOAD_PUBLIC. + * @return NULL on failure. + * @return WOLFSSL_RSA object on success. + */ +static WOLFSSL_RSA* wolfssl_rsa_d2i(WOLFSSL_RSA** rsa, const unsigned char* in, + long inSz, int opt) +{ + WOLFSSL_RSA* ret = NULL; + + if ((rsa != NULL) && (*rsa != NULL)) { + ret = *rsa; + } + else { + ret = wolfSSL_RSA_new(); + } + if ((ret != NULL) && (wolfSSL_RSA_LoadDer_ex(ret, in, (int)inSz, opt) + != 1)) { + if ((rsa == NULL) || (ret != *rsa)) { + wolfSSL_RSA_free(ret); + } + ret = NULL; + } + + if ((rsa != NULL) && (*rsa == NULL)) { + *rsa = ret; + } + return ret; +} +#endif + +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + +/* + * RSA PEM APIs + */ + +#ifdef OPENSSL_EXTRA + +#ifndef NO_BIO +#if defined(WOLFSSL_KEY_GEN) +/* Writes PEM encoding of an RSA public key to a BIO. + * + * @param [in] bio BIO object to write to. + * @param [in] rsa RSA key to write. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa) +{ + int ret = 1; + int derSz = 0; + byte* derBuf = NULL; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSA_PUBKEY"); + + /* Validate parameters. */ + if ((bio == NULL) || (rsa == NULL)) { + WOLFSSL_ERROR_MSG("Bad Function Arguments"); + return 0; + } + + if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, bio->heap)) < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + ret = 0; + } + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed to get buffer"); + ret = 0; + } + if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, + PUBLICKEY_TYPE) != 1)) { + ret = 0; + } + + /* Dispose of DER buffer. */ + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} + +#endif /* WOLFSSL_KEY_GEN */ +#endif /* !NO_BIO */ + +#if defined(WOLFSSL_KEY_GEN) +#ifndef NO_FILESYSTEM + +/* Writes PEM encoding of an RSA public key to a file pointer. + * + * @param [in] fp File pointer to write to. + * @param [in] rsa RSA key to write. + * @param [in] type PEM type to write out. + * @return 1 on success. + * @return 0 on failure. + */ +static int wolfssl_pem_write_rsa_public_key(XFILE fp, WOLFSSL_RSA* rsa, + int type) +{ + int ret = 1; + int derSz; + byte* derBuf = NULL; + + /* Validate parameters. */ + if ((fp == XBADFILE) || (rsa == NULL)) { + WOLFSSL_ERROR_MSG("Bad Function Arguments"); + return 0; + } + + if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, rsa->heap)) < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + ret = 0; + } + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed to get buffer"); + ret = 0; + } + if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, type, + rsa->heap) != 1)) { + ret = 0; + } + + /* Dispose of DER buffer. */ + XFREE(derBuf, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/* Writes PEM encoding of an RSA public key to a file pointer. + * + * Header/footer will contain: PUBLIC KEY + * + * @param [in] fp File pointer to write to. + * @param [in] rsa RSA key to write. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_RSA_PUBKEY(XFILE fp, WOLFSSL_RSA* rsa) +{ + return wolfssl_pem_write_rsa_public_key(fp, rsa, PUBLICKEY_TYPE); +} + +/* Writes PEM encoding of an RSA public key to a file pointer. + * + * Header/footer will contain: RSA PUBLIC KEY + * + * @param [in] fp File pointer to write to. + * @param [in] rsa RSA key to write. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_RSAPublicKey(XFILE fp, WOLFSSL_RSA* rsa) +{ + return wolfssl_pem_write_rsa_public_key(fp, rsa, RSA_PUBLICKEY_TYPE); +} +#endif /* !NO_FILESYSTEM */ +#endif /* WOLFSSL_KEY_GEN */ + +#ifndef NO_BIO +/* Create an RSA public key by reading the PEM encoded data from the BIO. + * + * @param [in] bio BIO object to read from. + * @param [out] out RSA key created. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA *wolfSSL_PEM_read_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, + WOLFSSL_RSA** out, wc_pem_password_cb* cb, void *pass) +{ + WOLFSSL_RSA* rsa = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSA_PUBKEY"); + + if ((bio != NULL) && (pem_read_bio_key(bio, cb, pass, PUBLICKEY_TYPE, + &keyFormat, &der) >= 0)) { + rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, + WOLFSSL_RSA_LOAD_PUBLIC); + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); + } + } + + FreeDer(&der); + if ((out != NULL) && (rsa != NULL)) { + *out = rsa; + } + return rsa; +} + +WOLFSSL_RSA *wolfSSL_d2i_RSA_PUBKEY_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out) +{ + char* data = NULL; + int dataSz = 0; + int memAlloced = 0; + WOLFSSL_RSA* rsa = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_RSA_PUBKEY_bio"); + + if (bio == NULL) + return NULL; + + if (wolfssl_read_bio(bio, &data, &dataSz, &memAlloced) != 0) { + if (memAlloced) + XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + rsa = wolfssl_rsa_d2i(out, (const unsigned char*)data, dataSz, + WOLFSSL_RSA_LOAD_PUBLIC); + if (memAlloced) + XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return rsa; +} +#endif /* !NO_BIO */ + +#ifndef NO_FILESYSTEM +/* Create an RSA public key by reading the PEM encoded data from the BIO. + * + * Header/footer should contain: PUBLIC KEY + * PEM decoder supports either 'RSA PUBLIC KEY' or 'PUBLIC KEY'. + * + * @param [in] fp File pointer to read from. + * @param [out] out RSA key created. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA *wolfSSL_PEM_read_RSA_PUBKEY(XFILE fp, + WOLFSSL_RSA** out, wc_pem_password_cb* cb, void *pass) +{ + WOLFSSL_RSA* rsa = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_RSA_PUBKEY"); + + if ((fp != XBADFILE) && (pem_read_file_key(fp, cb, pass, PUBLICKEY_TYPE, + &keyFormat, &der) >= 0)) { + rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, + WOLFSSL_RSA_LOAD_PUBLIC); + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); + } + } + + FreeDer(&der); + if ((out != NULL) && (rsa != NULL)) { + *out = rsa; + } + return rsa; +} + +/* Create an RSA public key by reading the PEM encoded data from the BIO. + * + * Header/footer should contain: RSA PUBLIC KEY + * PEM decoder supports either 'RSA PUBLIC KEY' or 'PUBLIC KEY'. + * + * @param [in] fp File pointer to read from. + * @param [out] rsa RSA key created. + * @param [in] cb Password callback when PEM encrypted. May be NULL. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * May be NULL. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_PEM_read_RSAPublicKey(XFILE fp, WOLFSSL_RSA** rsa, + wc_pem_password_cb* cb, void* pass) +{ + return wolfSSL_PEM_read_RSA_PUBKEY(fp, rsa, cb, pass); +} + +#endif /* NO_FILESYSTEM */ + +#if defined(WOLFSSL_KEY_GEN) && \ + (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) + +/* Writes PEM encoding of an RSA private key to newly allocated buffer. + * + * Buffer returned was allocated with: DYNAMIC_TYPE_KEY. + * + * @param [in] rsa RSA key to write. + * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. + * @param [in] passwd Password string when PEM encrypted. May be NULL. + * @param [in] passwdSz Length of password string when PEM encrypted. + * @param [out] pem Allocated buffer with PEM encoding. + * @param [out] pLen Length of PEM encoding. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_mem_RSAPrivateKey(WOLFSSL_RSA* rsa, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, + unsigned char **pem, int *pLen) +{ + int ret = 1; + byte* derBuf = NULL; + int derSz = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_write_mem_RSAPrivateKey"); + + /* Validate parameters. */ + if ((pem == NULL) || (pLen == NULL) || (rsa == NULL) || + (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + /* Set the RSA key data into the wolfCrypt RSA key if not done so. */ + if ((ret == 1) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = 0; + } + + /* Encode wolfCrypt RSA key to DER - derBuf allocated in call. */ + if ((ret == 1) && ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 0, + rsa->heap)) < 0)) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + ret = 0; + } + + if ((ret == 1) && (der_to_enc_pem_alloc(derBuf, derSz, cipher, passwd, + passwdSz, PRIVATEKEY_TYPE, NULL, pem, pLen) != 1)) { + WOLFSSL_ERROR_MSG("der_to_enc_pem_alloc failed"); + ret = 0; + } + + return ret; +} + +#ifndef NO_BIO +/* Writes PEM encoding of an RSA private key to a BIO. + * + * @param [in] bio BIO object to write to. + * @param [in] rsa RSA key to write. + * @param [in] cipher Cipher to use when PEM encrypted. + * @param [in] passwd Password string when PEM encrypted. + * @param [in] len Length of password string when PEM encrypted. + * @param [in] cb Password callback to use when PEM encrypted. + * @param [in] arg NUL terminated string for passphrase when PEM encrypted. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_bio_RSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int len, + wc_pem_password_cb* cb, void* arg) +{ + int ret = 1; + byte* pem = NULL; + int pLen = 0; + + (void)cb; + (void)arg; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSAPrivateKey"); + + /* Validate parameters. */ + if ((bio == NULL) || (rsa == NULL) || (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + if (ret == 1) { + /* Write PEM to buffer that is allocated in the call. */ + ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, cipher, passwd, len, + &pem, &pLen); + if (ret != 1) { + WOLFSSL_ERROR_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed"); + } + } + /* Write PEM to BIO. */ + if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) <= 0)) { + WOLFSSL_ERROR_MSG("RSA private key BIO write failed"); + ret = 0; + } + + /* Dispose of any allocated PEM buffer. */ + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + return ret; +} +#endif /* !NO_BIO */ + +#ifndef NO_FILESYSTEM +/* Writes PEM encoding of an RSA private key to a file pointer. + * + * TODO: Support use of the password callback and callback context. + * + * @param [in] fp File pointer to write to. + * @param [in] rsa RSA key to write. + * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. + * @param [in] passwd Password string when PEM encrypted. May be NULL. + * @param [in] passwdSz Length of password string when PEM encrypted. + * @param [in] cb Password callback to use when PEM encrypted. Unused. + * @param [in] arg NUL terminated string for passphrase when PEM + * encrypted. Unused. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_RSAPrivateKey(XFILE fp, WOLFSSL_RSA *rsa, + const WOLFSSL_EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz, + wc_pem_password_cb *cb, void *arg) +{ + int ret = 1; + byte* pem = NULL; + int pLen = 0; + + (void)cb; + (void)arg; + + WOLFSSL_ENTER("wolfSSL_PEM_write_RSAPrivateKey"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (rsa == NULL) || (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + if (ret == 1) { + /* Write PEM to buffer that is allocated in the call. */ + ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, cipher, passwd, passwdSz, + &pem, &pLen); + if (ret != 1) { + WOLFSSL_ERROR_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed"); + } + } + /* Write PEM to file pointer. */ + if ((ret == 1) && ((int)XFWRITE(pem, 1, (size_t)pLen, fp) != pLen)) { + WOLFSSL_ERROR_MSG("RSA private key file write failed"); + ret = 0; + } + + /* Dispose of any allocated PEM buffer. */ + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + return ret; +} +#endif /* NO_FILESYSTEM */ +#endif /* WOLFSSL_KEY_GEN && WOLFSSL_PEM_TO_DER */ + +#ifndef NO_BIO +/* Create an RSA private key by reading the PEM encoded data from the BIO. + * + * @param [in] bio BIO object to read from. + * @param [out] out RSA key created. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_PEM_read_bio_RSAPrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_RSA** out, wc_pem_password_cb* cb, void* pass) +{ + WOLFSSL_RSA* rsa = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSAPrivateKey"); + + if ((bio != NULL) && (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, + &keyFormat, &der) >= 0)) { + rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, + WOLFSSL_RSA_LOAD_PRIVATE); + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); + } + } + + FreeDer(&der); + if ((out != NULL) && (rsa != NULL)) { + *out = rsa; + } + return rsa; +} +#endif /* !NO_BIO */ + +/* Create an RSA private key by reading the PEM encoded data from the file + * pointer. + * + * @param [in] fp File pointer to read from. + * @param [out] out RSA key created. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * @return RSA key on success. + * @return NULL on failure. + */ +#ifndef NO_FILESYSTEM +WOLFSSL_RSA* wolfSSL_PEM_read_RSAPrivateKey(XFILE fp, WOLFSSL_RSA** out, + wc_pem_password_cb* cb, void* pass) +{ + WOLFSSL_RSA* rsa = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_RSAPrivateKey"); + + if ((fp != XBADFILE) && (pem_read_file_key(fp, cb, pass, PRIVATEKEY_TYPE, + &keyFormat, &der) >= 0)) { + rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, + WOLFSSL_RSA_LOAD_PRIVATE); + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); + } + } + + FreeDer(&der); + if ((out != NULL) && (rsa != NULL)) { + *out = rsa; + } + return rsa; +} +#endif /* !NO_FILESYSTEM */ + +/* + * RSA print APIs + */ + +#if defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \ + !defined(NO_STDIO_FILESYSTEM) +/* Print an RSA key to a file pointer. + * + * @param [in] fp File pointer to write to. + * @param [in] rsa RSA key to write. + * @param [in] indent Number of spaces to prepend to each line. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_print_fp(XFILE fp, WOLFSSL_RSA* rsa, int indent) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_RSA_print_fp"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (rsa == NULL)) { + ret = 0; + } + + /* Set the external data from the wolfCrypt RSA key if not done. */ + if ((ret == 1) && (!rsa->exSet)) { + ret = SetRsaExternal(rsa); + } + + /* Get the key size from modulus if available. */ + if ((ret == 1) && (rsa->n != NULL)) { + int keySize = wolfSSL_BN_num_bits(rsa->n); + if (keySize == 0) { + ret = 0; + } + else { + if (XFPRINTF(fp, "%*s", indent, "") < 0) + ret = 0; + else if (XFPRINTF(fp, "RSA Private-Key: (%d bit, 2 primes)\n", + keySize) < 0) + ret = 0; + } + } + /* Print out any components available. */ + if ((ret == 1) && (rsa->n != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "modulus", rsa->n); + } + if ((ret == 1) && (rsa->d != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "privateExponent", rsa->d); + } + if ((ret == 1) && (rsa->p != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "prime1", rsa->p); + } + if ((ret == 1) && (rsa->q != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "prime2", rsa->q); + } + if ((ret == 1) && (rsa->dmp1 != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "exponent1", rsa->dmp1); + } + if ((ret == 1) && (rsa->dmq1 != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "exponent2", rsa->dmq1); + } + if ((ret == 1) && (rsa->iqmp != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "coefficient", rsa->iqmp); + } + + WOLFSSL_LEAVE("wolfSSL_RSA_print_fp", ret); + + return ret; +} +#endif /* XFPRINTF && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ + +#if defined(XSNPRINTF) && !defined(NO_BIO) +/* snprintf() must be available */ + +/* Maximum size of a header line. */ +#define RSA_PRINT_MAX_HEADER_LINE PRINT_NUM_MAX_INDENT + +/* Writes the human readable form of RSA to a BIO. + * + * @param [in] bio BIO object to write to. + * @param [in] rsa RSA key to write. + * @param [in] indent Number of spaces before each line. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_print(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa, int indent) +{ + int ret = 1; + int sz = 0; + RsaKey* key = NULL; + char line[RSA_PRINT_MAX_HEADER_LINE]; + int i = 0; + mp_int *num = NULL; + /* Header strings. */ + const char *name[] = { + "Modulus:", "Exponent:", "PrivateExponent:", "Prime1:", "Prime2:", + "Exponent1:", "Exponent2:", "Coefficient:" + }; + + WOLFSSL_ENTER("wolfSSL_RSA_print"); + + /* Validate parameters. */ + if ((bio == NULL) || (rsa == NULL) || (indent > PRINT_NUM_MAX_INDENT)) { + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + key = (RsaKey*)rsa->internal; + + /* Get size in bits of key for printing out. */ + sz = wolfSSL_RSA_bits(rsa); + if (sz <= 0) { + WOLFSSL_ERROR_MSG("Error getting RSA key size"); + ret = 0; + } + } + if (ret == 1) { + /* Print any indent spaces. */ + ret = wolfssl_print_indent(bio, line, sizeof(line), indent); + } + if (ret == 1) { + /* Print header line. */ + int len = XSNPRINTF(line, sizeof(line), "\nRSA %s: (%d bit)\n", + (!mp_iszero(&key->d)) ? "Private-Key" : "Public-Key", sz); + if (len >= (int)sizeof(line)) { + WOLFSSL_ERROR_MSG("Buffer overflow while formatting key preamble"); + ret = 0; + } + else { + if (wolfSSL_BIO_write(bio, line, len) <= 0) { + ret = 0; + } + } + } + + for (i = 0; (ret == 1) && (i < RSA_INTS); i++) { + /* Get mp_int for index. */ + switch (i) { + case 0: + /* Print out modulus */ + num = &key->n; + break; + case 1: + num = &key->e; + break; + case 2: + num = &key->d; + break; + case 3: + num = &key->p; + break; + case 4: + num = &key->q; + break; + case 5: + num = &key->dP; + break; + case 6: + num = &key->dQ; + break; + case 7: + num = &key->u; + break; + default: + WOLFSSL_ERROR_MSG("Bad index value"); + } + + if (i == 1) { + /* Print exponent as a 32-bit value. */ + ret = wolfssl_print_value(bio, num, name[i], indent); + } + else if (!mp_iszero(num)) { + /* Print name and MP integer. */ + ret = wolfssl_print_number(bio, num, name[i], indent); + } + } + + return ret; +} +#endif /* XSNPRINTF && !NO_BIO */ + +#endif /* OPENSSL_EXTRA */ + +/* + * RSA get/set/test APIs + */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Set RSA key data (external) from wolfCrypt RSA key (internal). + * + * @param [in, out] rsa RSA key. + * @return 1 on success. + * @return 0 on failure. + */ +int SetRsaExternal(WOLFSSL_RSA* rsa) +{ + int ret = 1; + + WOLFSSL_ENTER("SetRsaExternal"); + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("rsa key NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + RsaKey* key = (RsaKey*)rsa->internal; + + /* Copy modulus. */ + ret = wolfssl_bn_set_value(&rsa->n, &key->n); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa n error"); + } + if (ret == 1) { + /* Copy public exponent. */ + ret = wolfssl_bn_set_value(&rsa->e, &key->e); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa e error"); + } + } + + if (key->type == RSA_PRIVATE) { + #ifndef WOLFSSL_RSA_PUBLIC_ONLY + if (ret == 1) { + /* Copy private exponent. */ + ret = wolfssl_bn_set_value(&rsa->d, &key->d); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa d error"); + } + } + if (ret == 1) { + /* Copy first prime. */ + ret = wolfssl_bn_set_value(&rsa->p, &key->p); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa p error"); + } + } + if (ret == 1) { + /* Copy second prime. */ + ret = wolfssl_bn_set_value(&rsa->q, &key->q); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa q error"); + } + } + #if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || \ + !defined(RSA_LOW_MEM) + if (ret == 1) { + /* Copy d mod p-1. */ + ret = wolfssl_bn_set_value(&rsa->dmp1, &key->dP); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa dP error"); + } + } + if (ret == 1) { + /* Copy d mod q-1. */ + ret = wolfssl_bn_set_value(&rsa->dmq1, &key->dQ); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa dq error"); + } + } + if (ret == 1) { + /* Copy 1/q mod p. */ + ret = wolfssl_bn_set_value(&rsa->iqmp, &key->u); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa u error"); + } + } + #endif + #else + WOLFSSL_ERROR_MSG("rsa private key not compiled in "); + ret = 0; + #endif /* !WOLFSSL_RSA_PUBLIC_ONLY */ + } + } + if (ret == 1) { + /* External values set. */ + rsa->exSet = 1; + } + else { + /* Return 0 on failure. */ + ret = 0; + } + + return ret; +} +#endif /* (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */ + +#ifdef OPENSSL_EXTRA + +/* Set wolfCrypt RSA key data (internal) from RSA key (external). + * + * @param [in, out] rsa RSA key. + * @return 1 on success. + * @return 0 on failure. + */ +int SetRsaInternal(WOLFSSL_RSA* rsa) +{ + int ret = 1; + + WOLFSSL_ENTER("SetRsaInternal"); + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("rsa key NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + RsaKey* key = (RsaKey*)rsa->internal; + + /* Copy down modulus if available. */ + if ((rsa->n != NULL) && (wolfssl_bn_get_value(rsa->n, &key->n) != 1)) { + WOLFSSL_ERROR_MSG("rsa n key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Copy down public exponent if available. */ + if ((ret == 1) && (rsa->e != NULL) && + (wolfssl_bn_get_value(rsa->e, &key->e) != 1)) { + WOLFSSL_ERROR_MSG("rsa e key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Enough numbers for public key */ + key->type = RSA_PUBLIC; + +#ifndef WOLFSSL_RSA_PUBLIC_ONLY + /* Copy down private exponent if available. */ + if ((ret == 1) && (rsa->d != NULL)) { + if (wolfssl_bn_get_value(rsa->d, &key->d) != 1) { + WOLFSSL_ERROR_MSG("rsa d key error"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + /* Enough numbers for private key */ + key->type = RSA_PRIVATE; + } + } + + /* Copy down first prime if available. */ + if ((ret == 1) && (rsa->p != NULL) && + (wolfssl_bn_get_value(rsa->p, &key->p) != 1)) { + WOLFSSL_ERROR_MSG("rsa p key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Copy down second prime if available. */ + if ((ret == 1) && (rsa->q != NULL) && + (wolfssl_bn_get_value(rsa->q, &key->q) != 1)) { + WOLFSSL_ERROR_MSG("rsa q key error"); + ret = WOLFSSL_FATAL_ERROR; + } + +#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM) + /* Copy down d mod p-1 if available. */ + if ((ret == 1) && (rsa->dmp1 != NULL) && + (wolfssl_bn_get_value(rsa->dmp1, &key->dP) != 1)) { + WOLFSSL_ERROR_MSG("rsa dP key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Copy down d mod q-1 if available. */ + if ((ret == 1) && (rsa->dmq1 != NULL) && + (wolfssl_bn_get_value(rsa->dmq1, &key->dQ) != 1)) { + WOLFSSL_ERROR_MSG("rsa dQ key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Copy down 1/q mod p if available. */ + if ((ret == 1) && (rsa->iqmp != NULL) && + (wolfssl_bn_get_value(rsa->iqmp, &key->u) != 1)) { + WOLFSSL_ERROR_MSG("rsa u key error"); + ret = WOLFSSL_FATAL_ERROR; + } +#endif +#endif + + if (ret == 1) { + /* All available numbers have been set down. */ + rsa->inSet = 1; + } + } + + return ret; +} + +/* Set the RSA method into object. + * + * @param [in, out] rsa RSA key. + * @param [in] meth RSA method. + * @return 1 always. + */ +int wolfSSL_RSA_set_method(WOLFSSL_RSA *rsa, WOLFSSL_RSA_METHOD *meth) +{ + if (rsa != NULL) { + /* Store the method into object. */ + rsa->meth = meth; + /* Copy over flags. */ + rsa->flags = meth->flags; + } + /* OpenSSL always assumes it will work. */ + return 1; +} + +/* Get the RSA method from the RSA object. + * + * @param [in] rsa RSA key. + * @return RSA method on success. + * @return NULL when RSA is NULL or no method set. + */ +const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_method(const WOLFSSL_RSA *rsa) +{ + return (rsa != NULL) ? rsa->meth : NULL; +} + +/* Get the size in bytes of the RSA key. + * + * Return compliant with OpenSSL + * + * @param [in] rsa RSA key. + * @return RSA modulus size in bytes. + * @return 0 on error. + */ +int wolfSSL_RSA_size(const WOLFSSL_RSA* rsa) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_size"); + + if (rsa != NULL) { + /* Make sure we have set the RSA values into wolfCrypt RSA key. */ + if (rsa->inSet || (SetRsaInternal((WOLFSSL_RSA*)rsa) == 1)) { + /* Get key size in bytes using wolfCrypt RSA key. */ + ret = wc_RsaEncryptSize((RsaKey*)rsa->internal); + } + } + + return ret; +} + +/* Get the size in bits of the RSA key. + * + * Uses external modulus field. + * + * @param [in] rsa RSA key. + * @return RSA modulus size in bits. + * @return 0 on error. + */ +int wolfSSL_RSA_bits(const WOLFSSL_RSA* rsa) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_bits"); + + if (rsa != NULL) { + /* Get number of bits in external modulus. */ + ret = wolfSSL_BN_num_bits(rsa->n); + } + + return ret; +} + +/* Get the BN objects that are the Chinese-Remainder Theorem (CRT) parameters. + * + * Only for those that are not NULL parameters. + * + * @param [in] rsa RSA key. + * @param [out] dmp1 BN that is d mod (p - 1). May be NULL. + * @param [out] dmq1 BN that is d mod (q - 1). May be NULL. + * @param [out] iqmp BN that is 1/q mod p. May be NULL. + */ +void wolfSSL_RSA_get0_crt_params(const WOLFSSL_RSA *rsa, + const WOLFSSL_BIGNUM **dmp1, const WOLFSSL_BIGNUM **dmq1, + const WOLFSSL_BIGNUM **iqmp) +{ + WOLFSSL_ENTER("wolfSSL_RSA_get0_crt_params"); + + /* For any parameters not NULL, return the BN from the key or NULL. */ + if (dmp1 != NULL) { + *dmp1 = (rsa != NULL) ? rsa->dmp1 : NULL; + } + if (dmq1 != NULL) { + *dmq1 = (rsa != NULL) ? rsa->dmq1 : NULL; + } + if (iqmp != NULL) { + *iqmp = (rsa != NULL) ? rsa->iqmp : NULL; + } +} + +/* Set the BN objects that are the Chinese-Remainder Theorem (CRT) parameters + * into RSA key. + * + * If CRT parameter is NULL then there must be one in the RSA key already. + * + * @param [in, out] rsa RSA key. + * @param [in] dmp1 BN that is d mod (p - 1). May be NULL. + * @param [in] dmq1 BN that is d mod (q - 1). May be NULL. + * @param [in] iqmp BN that is 1/q mod p. May be NULL. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_set0_crt_params(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *dmp1, + WOLFSSL_BIGNUM *dmq1, WOLFSSL_BIGNUM *iqmp) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_RSA_set0_crt_params"); + + /* If a param is NULL in rsa then it must be non-NULL in the + * corresponding user input. */ + if ((rsa == NULL) || ((rsa->dmp1 == NULL) && (dmp1 == NULL)) || + ((rsa->dmq1 == NULL) && (dmq1 == NULL)) || + ((rsa->iqmp == NULL) && (iqmp == NULL))) { + WOLFSSL_ERROR_MSG("Bad parameters"); + ret = 0; + } + if (ret == 1) { + /* Replace the BNs. */ + if (dmp1 != NULL) { + wolfSSL_BN_clear_free(rsa->dmp1); + rsa->dmp1 = dmp1; + } + if (dmq1 != NULL) { + wolfSSL_BN_clear_free(rsa->dmq1); + rsa->dmq1 = dmq1; + } + if (iqmp != NULL) { + wolfSSL_BN_clear_free(rsa->iqmp); + rsa->iqmp = iqmp; + } + + /* Set the values into the wolfCrypt RSA key. */ + if (SetRsaInternal(rsa) != 1) { + if (dmp1 != NULL) { + rsa->dmp1 = NULL; + } + if (dmq1 != NULL) { + rsa->dmq1 = NULL; + } + if (iqmp != NULL) { + rsa->iqmp = NULL; + } + ret = 0; + } + } + + return ret; +} + +/* Get the BN objects that are the factors of the RSA key (two primes p and q). + * + * @param [in] rsa RSA key. + * @param [out] p BN that is first prime. May be NULL. + * @param [out] q BN that is second prime. May be NULL. + */ +void wolfSSL_RSA_get0_factors(const WOLFSSL_RSA *rsa, const WOLFSSL_BIGNUM **p, + const WOLFSSL_BIGNUM **q) +{ + WOLFSSL_ENTER("wolfSSL_RSA_get0_factors"); + + /* For any primes not NULL, return the BN from the key or NULL. */ + if (p != NULL) { + *p = (rsa != NULL) ? rsa->p : NULL; + } + if (q != NULL) { + *q = (rsa != NULL) ? rsa->q : NULL; + } +} + +/* Set the BN objects that are the factors of the RSA key (two primes p and q). + * + * If factor parameter is NULL then there must be one in the RSA key already. + * + * @param [in, out] rsa RSA key. + * @param [in] p BN that is first prime. May be NULL. + * @param [in] q BN that is second prime. May be NULL. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_set0_factors(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *p, + WOLFSSL_BIGNUM *q) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_RSA_set0_factors"); + + /* If a param is null in r then it must be non-null in the + * corresponding user input. */ + if (rsa == NULL || ((rsa->p == NULL) && (p == NULL)) || + ((rsa->q == NULL) && (q == NULL))) { + WOLFSSL_ERROR_MSG("Bad parameters"); + ret = 0; + } + if (ret == 1) { + /* Replace the BNs. */ + if (p != NULL) { + wolfSSL_BN_clear_free(rsa->p); + rsa->p = p; + } + if (q != NULL) { + wolfSSL_BN_clear_free(rsa->q); + rsa->q = q; + } + + /* Set the values into the wolfCrypt RSA key. */ + if (SetRsaInternal(rsa) != 1) { + if (p != NULL) { + rsa->p = NULL; + } + if (q != NULL) { + rsa->q = NULL; + } + ret = 0; + } + } + + return ret; +} + +/* Get the BN objects for the basic key numbers of the RSA key (modulus, public + * exponent, private exponent). + * + * @param [in] rsa RSA key. + * @param [out] n BN that is the modulus. May be NULL. + * @param [out] e BN that is the public exponent. May be NULL. + * @param [out] d BN that is the private exponent. May be NULL. + */ +void wolfSSL_RSA_get0_key(const WOLFSSL_RSA *rsa, const WOLFSSL_BIGNUM **n, + const WOLFSSL_BIGNUM **e, const WOLFSSL_BIGNUM **d) +{ + WOLFSSL_ENTER("wolfSSL_RSA_get0_key"); + + /* For any parameters not NULL, return the BN from the key or NULL. */ + if (n != NULL) { + *n = (rsa != NULL) ? rsa->n : NULL; + } + if (e != NULL) { + *e = (rsa != NULL) ? rsa->e : NULL; + } + if (d != NULL) { + *d = (rsa != NULL) ? rsa->d : NULL; + } +} + +/* Set the BN objects for the basic key numbers into the RSA key (modulus, + * public exponent, private exponent). + * + * If BN parameter is NULL then there must be one in the RSA key already. + * + * @param [in,out] rsa RSA key. + * @param [in] n BN that is the modulus. May be NULL. + * @param [in] e BN that is the public exponent. May be NULL. + * @param [in] d BN that is the private exponent. May be NULL. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_set0_key(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *n, WOLFSSL_BIGNUM *e, + WOLFSSL_BIGNUM *d) +{ + int ret = 1; + + /* If the fields n and e in r are NULL, the corresponding input + * parameters MUST be non-NULL for n and e. d may be + * left NULL (in case only the public key is used). + */ + if ((rsa == NULL) || ((rsa->n == NULL) && (n == NULL)) || + ((rsa->e == NULL) && (e == NULL))) { + ret = 0; + } + if (ret == 1) { + /* Replace the BNs. */ + if (n != NULL) { + wolfSSL_BN_free(rsa->n); + rsa->n = n; + } + if (e != NULL) { + wolfSSL_BN_free(rsa->e); + rsa->e = e; + } + if (d != NULL) { + /* Private key is sensitive data. */ + wolfSSL_BN_clear_free(rsa->d); + rsa->d = d; + } + + /* Set the values into the wolfCrypt RSA key. */ + if (SetRsaInternal(rsa) != 1) { + if (n != NULL) { + rsa->n = NULL; + } + if (e != NULL) { + rsa->e = NULL; + } + if (d != NULL) { + rsa->d = NULL; + } + ret = 0; + } + } + + return ret; +} + +/* Get the flags of the RSA key. + * + * @param [in] rsa RSA key. + * @return Flags set in RSA key on success. + * @return 0 when RSA key is NULL. + */ +int wolfSSL_RSA_flags(const WOLFSSL_RSA *rsa) +{ + int ret = 0; + + /* Get flags from the RSA key if available. */ + if (rsa != NULL) { + ret = rsa->flags; + } + + return ret; +} + +/* Set the flags into the RSA key. + * + * @param [in, out] rsa RSA key. + * @param [in] flags Flags to set. + */ +void wolfSSL_RSA_set_flags(WOLFSSL_RSA *rsa, int flags) +{ + /* Add the flags into RSA key if available. */ + if (rsa != NULL) { + rsa->flags |= flags; + } +} + +/* Clear the flags in the RSA key. + * + * @param [in, out] rsa RSA key. + * @param [in] flags Flags to clear. + */ +void wolfSSL_RSA_clear_flags(WOLFSSL_RSA *rsa, int flags) +{ + /* Clear the flags passed in that are on the RSA key if available. */ + if (rsa != NULL) { + rsa->flags &= ~flags; + } +} + +/* Test the flags in the RSA key. + * + * @param [in] rsa RSA key. + * @return Matching flags of RSA key on success. + * @return 0 when RSA key is NULL. + */ +int wolfSSL_RSA_test_flags(const WOLFSSL_RSA *rsa, int flags) +{ + /* Return the flags passed in that are set on the RSA key if available. */ + return (rsa != NULL) ? (rsa->flags & flags) : 0; +} + +/* Get the extra data, by index, associated with the RSA key. + * + * @param [in] rsa RSA key. + * @param [in] idx Index of extra data. + * @return Extra data (anonymous type) on success. + * @return NULL on failure. + */ +void* wolfSSL_RSA_get_ex_data(const WOLFSSL_RSA *rsa, int idx) +{ + WOLFSSL_ENTER("wolfSSL_RSA_get_ex_data"); + +#ifdef HAVE_EX_DATA + return (rsa == NULL) ? NULL : + wolfSSL_CRYPTO_get_ex_data(&rsa->ex_data, idx); +#else + (void)rsa; + (void)idx; + + return NULL; +#endif +} + +/* Set extra data against the RSA key at an index. + * + * @param [in, out] rsa RSA key. + * @param [in] idx Index set set extra data at. + * @param [in] data Extra data of anonymous type. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_set_ex_data(WOLFSSL_RSA *rsa, int idx, void *data) +{ + WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data"); + +#ifdef HAVE_EX_DATA + return (rsa == NULL) ? 0 : + wolfSSL_CRYPTO_set_ex_data(&rsa->ex_data, idx, data); +#else + (void)rsa; + (void)idx; + (void)data; + + return 0; +#endif +} + +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS +/* Set the extra data and cleanup callback against the RSA key at an index. + * + * Not OpenSSL API. + * + * @param [in, out] rsa RSA key. + * @param [in] idx Index set set extra data at. + * @param [in] data Extra data of anonymous type. + * @param [in] freeCb Callback function to free extra data. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_set_ex_data_with_cleanup(WOLFSSL_RSA *rsa, int idx, void *data, + wolfSSL_ex_data_cleanup_routine_t freeCb) +{ + WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data_with_cleanup"); + + return (rsa == NULL) ? 0 : + wolfSSL_CRYPTO_set_ex_data_with_cleanup(&rsa->ex_data, idx, data, + freeCb); +} +#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ + +/* + * RSA check key APIs + */ + +#ifdef WOLFSSL_RSA_KEY_CHECK +/* Check that the RSA key is valid using wolfCrypt. + * + * @param [in] rsa RSA key. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_check_key(const WOLFSSL_RSA* rsa) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_RSA_check_key"); + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->internal == NULL)) { + ret = 0; + } + + /* Constant RSA - assume internal data has been set. */ + + /* Check wolfCrypt RSA key. */ + if ((ret == 1) && (wc_CheckRsaKey((RsaKey*)rsa->internal) != 0)) { + ret = 0; + } + + WOLFSSL_LEAVE("wolfSSL_RSA_check_key", ret); + + return ret; +} +#endif /* WOLFSSL_RSA_KEY_CHECK */ + +/* + * RSA generate APIs + */ + +/* Get a random number generator associated with the RSA key. + * + * If not able, then get the global if possible. + * *tmpRng must not be an initialized RNG. + * *tmpRng is allocated when WOLFSSL_SMALL_STACK is defined and an RNG isn't + * associated with the wolfCrypt RSA key. + * + * @param [in] rsa RSA key. + * @param [out] tmpRng Temporary random number generator. + * @param [out] initTmpRng Temporary random number generator was initialized. + * + * @return A wolfCrypt RNG to use on success. + * @return NULL on error. + */ +WC_RNG* WOLFSSL_RSA_GetRNG(WOLFSSL_RSA* rsa, WC_RNG** tmpRng, int* initTmpRng) +{ + WC_RNG* rng = NULL; + int err = 0; + + /* Check validity of parameters. */ + if ((rsa == NULL) || (initTmpRng == NULL)) { + err = 1; + } + if (!err) { + /* Haven't initialized any RNG passed through tmpRng. */ + *initTmpRng = 0; + + #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) + /* Use wolfCrypt RSA key's RNG if available/set. */ + rng = ((RsaKey*)rsa->internal)->rng; + #endif + } + if ((!err) && (rng == NULL) && (tmpRng != NULL)) { + /* Make an RNG with tmpRng or get global. */ + rng = wolfssl_make_rng(*tmpRng, initTmpRng); + if ((rng != NULL) && *initTmpRng) { + *tmpRng = rng; + } + } + + return rng; +} + +/* Use the wolfCrypt RSA APIs to generate a new RSA key. + * + * @param [in, out] rsa RSA key. + * @param [in] bits Number of bits that the modulus must have. + * @param [in] e A BN object holding the public exponent to use. + * @param [in] cb Status callback. Unused. + * @return 0 on success. + * @return wolfSSL native error code on error. + */ +static int wolfssl_rsa_generate_key_native(WOLFSSL_RSA* rsa, int bits, + WOLFSSL_BIGNUM* e, void* cb) +{ +#ifdef WOLFSSL_KEY_GEN + int ret = 0; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRng = NULL; +#else + WC_RNG _tmpRng[1]; + WC_RNG* tmpRng = _tmpRng; +#endif + int initTmpRng = 0; + WC_RNG* rng = NULL; + long en = 0; +#endif + + (void)cb; + + WOLFSSL_ENTER("wolfssl_rsa_generate_key_native"); + +#ifdef WOLFSSL_KEY_GEN + /* Get RNG in wolfCrypt RSA key or initialize a new one (or global). */ + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); + if (rng == NULL) { + /* Something went wrong so return memory error. */ + ret = MEMORY_E; + } + if ((ret == 0) && ((en = (long)wolfSSL_BN_get_word(e)) <= 0)) { + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + /* Generate an RSA key. */ + ret = wc_MakeRsaKey((RsaKey*)rsa->internal, bits, en, rng); + if (ret != MP_OKAY) { + WOLFSSL_ERROR_MSG("wc_MakeRsaKey failed"); + } + } + if (ret == 0) { + /* Get the values from wolfCrypt RSA key into external RSA key. */ + ret = SetRsaExternal(rsa); + if (ret == 1) { + /* Internal matches external. */ + rsa->inSet = 1; + /* Return success. */ + ret = 0; + } + else { + /* Something went wrong so return memory error. */ + ret = MEMORY_E; + } + } + + /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ + if (initTmpRng) { + wc_FreeRng(tmpRng); + } + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); + + return ret; +#else + WOLFSSL_ERROR_MSG("No Key Gen built in"); + + (void)rsa; + (void)e; + (void)bits; + + return NOT_COMPILED_IN; +#endif +} + +/* Generate an RSA key that has the specified modulus size and public exponent. + * + * Note: Because of wc_MakeRsaKey an RSA key size generated can be rounded + * down to nearest multiple of 8. For example generating a key of size + * 2999 bits will make a key of size 374 bytes instead of 375 bytes. + * + * @param [in] bits Number of bits that the modulus must have i.e. 2048. + * @param [in] e Public exponent to use i.e. 65537. + * @param [in] cb Status callback. Unused. + * @param [in] data Data to pass to status callback. Unused. + * @return A new RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_RSA_generate_key(int bits, unsigned long e, + void(*cb)(int, int, void*), void* data) +{ + WOLFSSL_RSA* rsa = NULL; + WOLFSSL_BIGNUM* bn = NULL; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_generate_key"); + + (void)cb; + (void)data; + + /* Validate bits. */ + if (bits < 0) { + WOLFSSL_ERROR_MSG("Bad argument: bits was less than 0"); + err = 1; + } + /* Create a new BN to hold public exponent - for when wolfCrypt supports + * longer values. */ + if ((!err) && ((bn = wolfSSL_BN_new()) == NULL)) { + WOLFSSL_ERROR_MSG("Error creating big number"); + err = 1; + } + /* Set public exponent. */ + if ((!err) && (wolfSSL_BN_set_word(bn, e) != 1)) { + WOLFSSL_ERROR_MSG("Error using e value"); + err = 1; + } + + /* Create an RSA key object to hold generated key. */ + if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { + WOLFSSL_ERROR_MSG("memory error"); + err = 1; + } + while (!err) { + int ret; + + /* Use wolfCrypt to generate RSA key. */ + ret = wolfssl_rsa_generate_key_native(rsa, bits, bn, NULL); + #ifdef HAVE_FIPS + /* Keep trying if failed to find a prime. */ + if (ret == WC_NO_ERR_TRACE(PRIME_GEN_E)) { + continue; + } + #endif + if (ret != WOLFSSL_ERROR_NONE) { + /* Unrecoverable error in generation. */ + err = 1; + } + /* Done generating - unrecoverable error or success. */ + break; + } + if (err) { + /* Dispose of RSA key object if generation didn't work. */ + wolfSSL_RSA_free(rsa); + /* Returning NULL on error. */ + rsa = NULL; + } + /* Dispose of the temporary BN used for the public exponent. */ + wolfSSL_BN_free(bn); + + return rsa; +} + +/* Generate an RSA key that has the specified modulus size and public exponent. + * + * Note: Because of wc_MakeRsaKey an RSA key size generated can be rounded + * down to nearest multiple of 8. For example generating a key of size + * 2999 bits will make a key of size 374 bytes instead of 375 bytes. + * + * @param [in] bits Number of bits that the modulus must have i.e. 2048. + * @param [in] e Public exponent to use, i.e. 65537, as a BN. + * @param [in] cb Status callback. Unused. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_generate_key_ex(WOLFSSL_RSA* rsa, int bits, WOLFSSL_BIGNUM* e, + void* cb) +{ + int ret = 1; + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("bad arguments"); + ret = 0; + } + else { + for (;;) { + /* Use wolfCrypt to generate RSA key. */ + int gen_ret = wolfssl_rsa_generate_key_native(rsa, bits, e, cb); + #ifdef HAVE_FIPS + /* Keep trying again if public key value didn't work. */ + if (gen_ret == WC_NO_ERR_TRACE(PRIME_GEN_E)) { + continue; + } + #endif + if (gen_ret != WOLFSSL_ERROR_NONE) { + /* Unrecoverable error in generation. */ + ret = 0; + } + /* Done generating - unrecoverable error or success. */ + break; + } + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +/* + * RSA padding APIs + */ + +#ifdef WC_RSA_PSS + +#if defined(OPENSSL_EXTRA) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) +static int rsa_pss_calc_salt(int saltLen, int hashLen, int emLen) +{ + /* Calculate the salt length to use for special cases. */ + switch (saltLen) { + /* Negative saltLen values are treated differently. */ + case WC_RSA_PSS_SALTLEN_DIGEST: + saltLen = hashLen; + break; + case WC_RSA_PSS_SALTLEN_MAX_SIGN: + case WC_RSA_PSS_SALTLEN_MAX: + #ifdef WOLFSSL_PSS_LONG_SALT + saltLen = emLen - hashLen - 2; + #else + saltLen = hashLen; + (void)emLen; + #endif + break; + default: + break; + } + if (saltLen < 0) { + /* log invalid salt, let wolfCrypt handle error */ + WOLFSSL_ERROR_MSG("invalid saltLen"); + saltLen = -3; /* for wolfCrypt to produce error must be < -2 */ + } + return saltLen; +} +#endif /* OPENSSL_EXTRA && !HAVE_SELFTEST */ + +#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX)) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + +/* Add PKCS#1 PSS padding to hash. + * + * + * +-----------+ + * | M | + * +-----------+ + * | + * V + * Hash + * | + * V + * +--------+----------+----------+ + * M' = |Padding1| mHash | salt | + * +--------+----------+----------+ + * | + * +--------+----------+ V + * DB = |Padding2|maskedseed| Hash + * +--------+----------+ | + * | | + * V | +--+ + * xor <--- MGF <---| |bc| + * | | +--+ + * | | | + * V V V + * +-------------------+----------+--+ + * EM = | maskedDB |maskedseed|bc| + * +-------------------+----------+--+ + * Diagram taken from https://tools.ietf.org/html/rfc3447#section-9.1 + * + * @param [in] rsa RSA key. + * @param [out] em Encoded message. + * @param [in[ mHash Message hash. + * @param [in] hashAlg Hash algorithm. + * @param [in] mgf1Hash MGF algorithm. + * @param [in] saltLen Length of salt to generate. + * @return 1 on success. + * @return 0 on failure. + */ + +int wolfSSL_RSA_padding_add_PKCS1_PSS_mgf1(WOLFSSL_RSA *rsa, unsigned char *em, + const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, + const WOLFSSL_EVP_MD *mgf1Hash, int saltLen) +{ + int ret = 1; + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + int hashLen = 0; + int emLen = 0; + int mgf = 0; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRng = NULL; +#else + WC_RNG _tmpRng[1]; + WC_RNG* tmpRng = _tmpRng; +#endif + + WOLFSSL_ENTER("wolfSSL_RSA_padding_add_PKCS1_PSS"); + + /* Validate parameters. */ + if ((rsa == NULL) || (em == NULL) || (mHash == NULL) || (hashAlg == NULL)) { + ret = 0; + } + + if (mgf1Hash == NULL) + mgf1Hash = hashAlg; + + if (ret == 1) { + /* Get/create an RNG. */ + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); + if (rng == NULL) { + WOLFSSL_ERROR_MSG("WOLFSSL_RSA_GetRNG error"); + ret = 0; + } + } + + /* TODO: use wolfCrypt RSA key to get emLen and bits? */ + /* Set the external data from the wolfCrypt RSA key if not done. */ + if ((ret == 1) && (!rsa->exSet)) { + ret = SetRsaExternal(rsa); + } + + if (ret == 1) { + /* Get the wolfCrypt hash algorithm type. */ + hashType = EvpMd2MacType(hashAlg); + if (hashType > WC_HASH_TYPE_MAX) { + WOLFSSL_ERROR_MSG("EvpMd2MacType error"); + ret = 0; + } + } + if (ret == 1) { + /* Get the wolfCrypt MGF algorithm from hash algorithm. */ + mgf = wc_hash2mgf(EvpMd2MacType(mgf1Hash)); + if (mgf == WC_MGF1NONE) { + WOLFSSL_ERROR_MSG("wc_hash2mgf error"); + ret = 0; + } + } + if (ret == 1) { + /* Get the length of the hash output. */ + hashLen = wolfSSL_EVP_MD_size(hashAlg); + if (hashLen < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_EVP_MD_size error"); + ret = 0; + } + } + + if (ret == 1) { + /* Get length of RSA key - encrypted message length. */ + emLen = wolfSSL_RSA_size(rsa); + if (emLen <= 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_size error"); + ret = 0; + } + } + + if (ret == 1) { + saltLen = rsa_pss_calc_salt(saltLen, hashLen, emLen); + } + + if (ret == 1) { + /* Generate RSA PKCS#1 PSS padding for hash using wolfCrypt. */ + if (wc_RsaPad_ex(mHash, (word32)hashLen, em, (word32)emLen, + RSA_BLOCK_TYPE_1, rng, WC_RSA_PSS_PAD, hashType, mgf, NULL, 0, + saltLen, wolfSSL_BN_num_bits(rsa->n), NULL) != MP_OKAY) { + WOLFSSL_ERROR_MSG("wc_RsaPad_ex error"); + ret = 0; + } + } + + /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ + if (initTmpRng) { + wc_FreeRng(tmpRng); + } + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); + + return ret; +} + +int wolfSSL_RSA_padding_add_PKCS1_PSS(WOLFSSL_RSA *rsa, unsigned char *em, + const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, int saltLen) +{ + return wolfSSL_RSA_padding_add_PKCS1_PSS_mgf1(rsa, em, mHash, hashAlg, NULL, + saltLen); +} + +/* Checks that the hash is valid for the RSA PKCS#1 PSS encoded message. + * + * Refer to wolfSSL_RSA_padding_add_PKCS1_PSS for a diagram. + * + * @param [in] rsa RSA key. + * @param [in[ mHash Message hash. + * @param [in] hashAlg Hash algorithm. + * @param [in] mgf1Hash MGF algorithm. + * @param [in] em Encoded message. + * @param [in] saltLen Length of salt to generate. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_verify_PKCS1_PSS_mgf1(WOLFSSL_RSA *rsa, + const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, + const WOLFSSL_EVP_MD *mgf1Hash, const unsigned char *em, int saltLen) +{ + int ret = 1; + int hashLen = 0; + int mgf = 0; + int emLen = 0; + int mPrimeLen = 0; + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + byte *mPrime = NULL; + byte *buf = NULL; + + WOLFSSL_ENTER("wolfSSL_RSA_verify_PKCS1_PSS"); + + /* Validate parameters. */ + if ((rsa == NULL) || (mHash == NULL) || (hashAlg == NULL) || (em == NULL)) { + ret = 0; + } + + if (mgf1Hash == NULL) + mgf1Hash = hashAlg; + + /* TODO: use wolfCrypt RSA key to get emLen and bits? */ + /* Set the external data from the wolfCrypt RSA key if not done. */ + if ((ret == 1) && (!rsa->exSet)) { + ret = SetRsaExternal(rsa); + } + + if (ret == 1) { + /* Get hash length for hash algorithm. */ + hashLen = wolfSSL_EVP_MD_size(hashAlg); + if (hashLen < 0) { + ret = 0; + } + } + + if (ret == 1) { + /* Get length of RSA key - encrypted message length. */ + emLen = wolfSSL_RSA_size(rsa); + if (emLen <= 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_size error"); + ret = 0; + } + } + + if (ret == 1) { + saltLen = rsa_pss_calc_salt(saltLen, hashLen, emLen); + } + + if (ret == 1) { + /* Get the wolfCrypt hash algorithm type. */ + hashType = EvpMd2MacType(hashAlg); + if (hashType > WC_HASH_TYPE_MAX) { + WOLFSSL_ERROR_MSG("EvpMd2MacType error"); + ret = 0; + } + } + + if (ret == 1) { + /* Get the wolfCrypt MGF algorithm from hash algorithm. */ + if ((mgf = wc_hash2mgf(EvpMd2MacType(mgf1Hash))) == WC_MGF1NONE) { + WOLFSSL_ERROR_MSG("wc_hash2mgf error"); + ret = 0; + } + } + + if (ret == 1) { + /* Allocate buffer to unpad inline with. */ + buf = (byte*)XMALLOC((size_t)emLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + WOLFSSL_ERROR_MSG("malloc error"); + ret = 0; + } + } + + if (ret == 1) { + /* Copy encrypted message to temp for inline unpadding. */ + XMEMCPY(buf, em, (size_t)emLen); + + /* Remove and verify the PSS padding. */ + mPrimeLen = wc_RsaUnPad_ex(buf, (word32)emLen, &mPrime, + RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD, hashType, mgf, NULL, 0, saltLen, + wolfSSL_BN_num_bits(rsa->n), NULL); + if (mPrimeLen < 0) { + WOLFSSL_ERROR_MSG("wc_RsaPad_ex error"); + ret = 0; + } + } + + if (ret == 1) { + /* Verify the hash is correct. */ + if (wc_RsaPSS_CheckPadding_ex(mHash, (word32)hashLen, mPrime, + (word32)mPrimeLen, hashType, saltLen, + wolfSSL_BN_num_bits(rsa->n)) != MP_OKAY) { + WOLFSSL_ERROR_MSG("wc_RsaPSS_CheckPadding_ex error"); + ret = 0; + } + } + + /* Dispose of any allocated buffer. */ + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} + +int wolfSSL_RSA_verify_PKCS1_PSS(WOLFSSL_RSA *rsa, const unsigned char *mHash, + const WOLFSSL_EVP_MD *hashAlg, + const unsigned char *em, int saltLen) +{ + return wolfSSL_RSA_verify_PKCS1_PSS_mgf1(rsa, mHash, hashAlg, NULL, em, + saltLen); +} +#endif /* (!HAVE_FIPS || FIPS_VERSION_GT(2,0)) && \ + (OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_NGINX) */ +#endif /* WC_RSA_PSS */ + +/* + * RSA sign/verify APIs + */ + +#if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) + #ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER + #define DEF_PSS_SALT_LEN RSA_PSS_SALT_LEN_DEFAULT + #else + #define DEF_PSS_SALT_LEN RSA_PSS_SALT_LEN_DISCOVER + #endif +#else + #define DEF_PSS_SALT_LEN 0 /* not used */ +#endif + +#if defined(OPENSSL_EXTRA) + +/* Encode the message hash. + * + * Used by signing and verification. + * + * @param [in] hashAlg Hash algorithm OID. + * @param [in] hash Hash of message to encode for signing. + * @param [in] hLen Length of hash of message. + * @param [out] enc Encoded message hash. + * @param [out] encLen Length of encoded message hash. + * @param [in] padding Which padding scheme is being used. + * @return 1 on success. + * @return 0 on failure. + */ +static int wolfssl_rsa_sig_encode(int hashAlg, const unsigned char* hash, + unsigned int hLen, unsigned char* enc, unsigned int* encLen, int padding) +{ + int ret = 1; + int hType = WC_HASH_TYPE_NONE; + + /* Validate parameters. */ + if ((hash == NULL) || (enc == NULL) || (encLen == NULL)) { + ret = 0; + } + + if ((ret == 1) && (hashAlg != WC_NID_undef) && + (padding == WC_RSA_PKCS1_PADDING)) { + /* Convert hash algorithm to hash type for PKCS#1.5 padding. */ + hType = (int)nid2oid(hashAlg, oidHashType); + if (hType == -1) { + ret = 0; + } + } + if ((ret == 1) && (padding == WC_RSA_PKCS1_PADDING)) { + /* PKCS#1.5 encoding. */ + word32 encSz = wc_EncodeSignature(enc, hash, hLen, hType); + if (encSz == 0) { + WOLFSSL_ERROR_MSG("Bad Encode Signature"); + ret = 0; + } + else { + *encLen = (unsigned int)encSz; + } + } + /* Other padding schemes require the hash as is. */ + if ((ret == 1) && (padding != WC_RSA_PKCS1_PADDING)) { + XMEMCPY(enc, hash, hLen); + *encLen = hLen; + } + + return ret; +} + +/* Sign the message hash using hash algorithm and RSA key. + * + * @param [in] hashAlg Hash algorithm OID. + * @param [in] hash Hash of message to encode for signing. + * @param [in] hLen Length of hash of message. + * @param [out] enc Encoded message hash. + * @param [out] encLen Length of encoded message hash. + * @param [in] rsa RSA key. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_sign(int hashAlg, const unsigned char* hash, unsigned int hLen, + unsigned char* sigRet, unsigned int* sigLen, WOLFSSL_RSA* rsa) +{ + if (sigLen != NULL) { + /* No size checking in this API */ + *sigLen = RSA_MAX_SIZE / CHAR_BIT; + } + /* flag is 1: output complete signature. */ + return wolfSSL_RSA_sign_generic_padding(hashAlg, hash, hLen, sigRet, + sigLen, rsa, 1, WC_RSA_PKCS1_PADDING); +} + +/* Sign the message hash using hash algorithm and RSA key. + * + * Not OpenSSL API. + * + * @param [in] hashAlg Hash algorithm NID. + * @param [in] hash Hash of message to encode for signing. + * @param [in] hLen Length of hash of message. + * @param [out] enc Encoded message hash. + * @param [out] encLen Length of encoded message hash. + * @param [in] rsa RSA key. + * @param [in] flag When 1: Output encrypted signature. + * When 0: Output encoded hash. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_sign_ex(int hashAlg, const unsigned char* hash, + unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, + WOLFSSL_RSA* rsa, int flag) +{ + int ret = 0; + + if ((flag == 0) || (flag == 1)) { + if (sigLen != NULL) { + /* No size checking in this API */ + *sigLen = RSA_MAX_SIZE / CHAR_BIT; + } + ret = wolfSSL_RSA_sign_generic_padding(hashAlg, hash, hLen, sigRet, + sigLen, rsa, flag, WC_RSA_PKCS1_PADDING); + } + + return ret; +} + +int wolfSSL_RSA_sign_generic_padding(int hashAlg, const unsigned char* hash, + unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, + WOLFSSL_RSA* rsa, int flag, int padding) +{ + return wolfSSL_RSA_sign_mgf(hashAlg, hash, hLen, sigRet, sigLen, rsa, flag, + padding, hashAlg, DEF_PSS_SALT_LEN); +} + +/** + * Sign a message hash with the chosen message digest, padding, and RSA key. + * + * Not OpenSSL API. + * + * @param [in] hashAlg Hash NID + * @param [in] hash Message hash to sign. + * @param [in] mLen Length of message hash to sign. + * @param [out] sigRet Output buffer. + * @param [in, out] sigLen On Input: length of sigRet buffer. + * On Output: length of data written to sigRet. + * @param [in] rsa RSA key used to sign the input. + * @param [in] flag 1: Output the signature. + * 0: Output the value that the unpadded signature + * should be compared to. + * @param [in] padding Padding to use. Only RSA_PKCS1_PSS_PADDING and + * WC_RSA_PKCS1_PADDING are currently supported for + * signing. + * @param [in] mgf1Hash MGF1 Hash NID + * @param [in] saltLen Length of RSA PSS salt + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash, + unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, + WOLFSSL_RSA* rsa, int flag, int padding, int mgf1Hash, int saltLen) +{ + int ret = 1; + word32 outLen = 0; + int signSz = 0; + WC_RNG* rng = NULL; + int initTmpRng = 0; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRng = NULL; + byte* encodedSig = NULL; +#else + WC_RNG _tmpRng[1]; + WC_RNG* tmpRng = _tmpRng; + byte encodedSig[MAX_ENCODED_SIG_SZ]; +#endif + unsigned int encSz = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_sign_mgf"); + + if (flag == 0) { + /* Only encode message. */ + return wolfssl_rsa_sig_encode(hashAlg, hash, hLen, sigRet, sigLen, + padding); + } + + /* Validate parameters. */ + if ((hash == NULL) || (sigRet == NULL) || sigLen == NULL || rsa == NULL) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + /* Set wolfCrypt RSA key data from external if not already done. */ + if ((ret == 1) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = 0; + } + + if (ret == 1) { + /* Get the maximum signature length. */ + outLen = (word32)wolfSSL_BN_num_bytes(rsa->n); + /* Check not an error return. */ + if (outLen == 0) { + WOLFSSL_ERROR_MSG("Bad RSA size"); + ret = 0; + } + /* Check signature buffer is big enough. */ + else if (outLen > *sigLen) { + WOLFSSL_ERROR_MSG("Output buffer too small"); + ret = 0; + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 1) { + /* Allocate encoded signature buffer if doing PKCS#1 padding. */ + encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + DYNAMIC_TYPE_SIGNATURE); + if (encodedSig == NULL) { + ret = 0; + } + } +#endif + + if (ret == 1) { + /* Get/create an RNG. */ + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); + if (rng == NULL) { + WOLFSSL_ERROR_MSG("WOLFSSL_RSA_GetRNG error"); + ret = 0; + } + } + + /* Either encodes with PKCS#1.5 or copies hash into encodedSig. */ + if ((ret == 1) && (wolfssl_rsa_sig_encode(hashAlg, hash, hLen, encodedSig, + &encSz, padding) == 0)) { + WOLFSSL_ERROR_MSG("Bad Encode Signature"); + ret = 0; + } + + if (ret == 1) { + switch (padding) { + #if defined(WC_RSA_NO_PADDING) || defined(WC_RSA_DIRECT) + case WC_RSA_NO_PAD: + if ((signSz = wc_RsaDirect(encodedSig, encSz, sigRet, &outLen, + (RsaKey*)rsa->internal, RSA_PRIVATE_ENCRYPT, rng)) <= 0) { + WOLFSSL_ERROR_MSG("Bad RSA Sign no pad"); + ret = 0; + } + break; + #endif + #if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) + case WC_RSA_PKCS1_PSS_PADDING: + { + RsaKey* key = (RsaKey*)rsa->internal; + enum wc_HashType mgf1, hType; + hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); + if (mgf1Hash == WC_NID_undef) + mgf1Hash = hashAlg; + mgf1 = wc_OidGetHash((int)nid2oid(mgf1Hash, oidHashType)); + /* handle compat layer salt special cases */ + saltLen = rsa_pss_calc_salt(saltLen, wc_HashGetDigestSize(hType), + wolfSSL_RSA_size(rsa)); + + /* Create RSA PSS signature. */ + if ((signSz = wc_RsaPSS_Sign_ex(encodedSig, encSz, sigRet, outLen, + hType, wc_hash2mgf(mgf1), saltLen, key, rng)) <= 0) { + WOLFSSL_ERROR_MSG("Bad RSA PSS Sign"); + ret = 0; + } + break; + } + #endif + #ifndef WC_NO_RSA_OAEP + case WC_RSA_PKCS1_OAEP_PADDING: + /* Not a signature padding scheme. */ + WOLFSSL_ERROR_MSG("RSA_PKCS1_OAEP_PADDING not supported for " + "signing"); + ret = 0; + break; + #endif + case WC_RSA_PKCS1_PADDING: + { + /* Sign (private encrypt) PKCS#1 encoded signature. */ + if ((signSz = wc_RsaSSL_Sign(encodedSig, encSz, sigRet, outLen, + (RsaKey*)rsa->internal, rng)) <= 0) { + WOLFSSL_ERROR_MSG("Bad PKCS1 RSA Sign"); + ret = 0; + } + break; + } + default: + WOLFSSL_ERROR_MSG("Unsupported padding"); + (void)mgf1Hash; + (void)saltLen; + ret = 0; + break; + } + } + + if (ret == 1) { + /* Return the size of signature generated. */ + *sigLen = (unsigned int)signSz; + } + + /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ + if (initTmpRng) { + wc_FreeRng(tmpRng); + } + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); + WC_FREE_VAR_EX(encodedSig, NULL, DYNAMIC_TYPE_SIGNATURE); + + WOLFSSL_LEAVE("wolfSSL_RSA_sign_mgf", ret); + return ret; +} + +/** + * Verify a message hash with the chosen message digest, padding, and RSA key. + * + * @param [in] hashAlg Hash NID + * @param [in] hash Message hash. + * @param [in] mLen Length of message hash. + * @param [in] sigRet Signature data. + * @param [in] sigLen Length of signature data. + * @param [in] rsa RSA key used to sign the input + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_verify(int hashAlg, const unsigned char* hash, + unsigned int hLen, const unsigned char* sig, unsigned int sigLen, + WOLFSSL_RSA* rsa) +{ + return wolfSSL_RSA_verify_ex(hashAlg, hash, hLen, sig, sigLen, rsa, + WC_RSA_PKCS1_PADDING); +} + +int wolfSSL_RSA_verify_ex(int hashAlg, const unsigned char* hash, + unsigned int hLen, const unsigned char* sig, unsigned int sigLen, + WOLFSSL_RSA* rsa, int padding) +{ + return wolfSSL_RSA_verify_mgf(hashAlg, hash, hLen, sig, sigLen, rsa, + padding, hashAlg, DEF_PSS_SALT_LEN); +} + +/** + * Verify a message hash with the chosen message digest, padding, and RSA key. + * + * Not OpenSSL API. + * + * @param [in] hashAlg Hash NID + * @param [in] hash Message hash. + * @param [in] mLen Length of message hash. + * @param [in] sigRet Signature data. + * @param [in] sigLen Length of signature data. + * @param [in] rsa RSA key used to sign the input + * @param [in] padding Padding to use. Only RSA_PKCS1_PSS_PADDING and + * WC_RSA_PKCS1_PADDING are currently supported for + * signing. + * @param [in] mgf1Hash MGF1 Hash NID + * @param [in] saltLen Length of RSA PSS salt + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_verify_mgf(int hashAlg, const unsigned char* hash, + unsigned int hLen, const unsigned char* sig, unsigned int sigLen, + WOLFSSL_RSA* rsa, int padding, int mgf1Hash, int saltLen) +{ + int ret = 1; +#ifdef WOLFSSL_SMALL_STACK + unsigned char* encodedSig = NULL; +#else + unsigned char encodedSig[MAX_ENCODED_SIG_SZ]; +#endif + unsigned char* sigDec = NULL; + unsigned int len = MAX_ENCODED_SIG_SZ; + int verLen = 0; +#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && !defined(HAVE_SELFTEST) + enum wc_HashType hType = WC_HASH_TYPE_NONE; +#endif + + WOLFSSL_ENTER("wolfSSL_RSA_verify_mgf"); + + /* Validate parameters. */ + if ((hash == NULL) || (sig == NULL) || (rsa == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + if (ret == 1) { + /* Allocate memory for decrypted signature. */ + sigDec = (unsigned char *)XMALLOC(sigLen, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (sigDec == NULL) { + WOLFSSL_ERROR_MSG("Memory allocation failure"); + ret = 0; + } + } + if (ret == 1 && padding == WC_RSA_PKCS1_PSS_PADDING) { + #if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) + RsaKey* key = (RsaKey*)rsa->internal; + enum wc_HashType mgf1; + hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); + if (mgf1Hash == WC_NID_undef) + mgf1Hash = hashAlg; + mgf1 = wc_OidGetHash((int)nid2oid(mgf1Hash, oidHashType)); + + /* handle compat layer salt special cases */ + saltLen = rsa_pss_calc_salt(saltLen, wc_HashGetDigestSize(hType), + wolfSSL_RSA_size(rsa)); + + verLen = wc_RsaPSS_Verify_ex((byte*)sig, sigLen, sigDec, sigLen, + hType, wc_hash2mgf(mgf1), saltLen, key); + if (verLen > 0) { + /* Check PSS padding is valid. */ + if (wc_RsaPSS_CheckPadding_ex(hash, hLen, sigDec, (word32)verLen, + hType, saltLen, mp_count_bits(&key->n)) != 0) { + WOLFSSL_ERROR_MSG("wc_RsaPSS_CheckPadding_ex error"); + ret = WOLFSSL_FAILURE; + } + else { + /* Success! Free resources and return early */ + XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_SUCCESS; + } + } + else { + WOLFSSL_ERROR_MSG("wc_RsaPSS_Verify_ex failed!"); + ret = WOLFSSL_FAILURE; + } + #else + (void)mgf1Hash; + (void)saltLen; + WOLFSSL_ERROR_MSG("RSA PSS not compiled in!"); + ret = WOLFSSL_FAILURE; + #endif + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 1) { + /* Allocate memory for encoded signature. */ + encodedSig = (unsigned char *)XMALLOC(len, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (encodedSig == NULL) { + WOLFSSL_ERROR_MSG("Memory allocation failure"); + ret = 0; + } + } +#endif + if (ret == 1) { + /* Make encoded signature to compare with decrypted signature. */ + if (wolfssl_rsa_sig_encode(hashAlg, hash, hLen, encodedSig, &len, + padding) <= 0) { + WOLFSSL_ERROR_MSG("Message Digest Error"); + ret = 0; + } + } + if (ret == 1) { + /* Decrypt signature */ + #if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && \ + !defined(HAVE_SELFTEST) + hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); + if ((verLen = wc_RsaSSL_Verify_ex2(sig, sigLen, (unsigned char *)sigDec, + sigLen, (RsaKey*)rsa->internal, padding, hType)) <= 0) { + WOLFSSL_ERROR_MSG("RSA Decrypt error"); + ret = 0; + } + #else + verLen = wc_RsaSSL_Verify(sig, sigLen, (unsigned char *)sigDec, sigLen, + (RsaKey*)rsa->internal); + if (verLen < 0) { + ret = 0; + } + #endif + } + if (ret == 1) { + /* Compare decrypted signature to encoded signature. */ + if (((int)len != verLen) || + (XMEMCMP(encodedSig, sigDec, (size_t)verLen) != 0)) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_verify_ex failed"); + ret = 0; + } + } + + /* Dispose of any allocated data. */ + WC_FREE_VAR_EX(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + WOLFSSL_LEAVE("wolfSSL_RSA_verify_mgf", ret); + return ret; +} + +/* + * RSA public/private encrypt/decrypt APIs + */ + +/* Encrypt with the RSA public key. + * + * Return compliant with OpenSSL. + * + * @param [in] len Length of data to encrypt. + * @param [in] from Data to encrypt. + * @param [out] to Encrypted data. + * @param [in] rsa RSA key. + * @param [in] padding Type of padding to place around plaintext. + * @return Size of encrypted data on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_public_encrypt(int len, const unsigned char* from, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int ret = 0; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRng = NULL; +#else + WC_RNG _tmpRng[1]; + WC_RNG* tmpRng = _tmpRng; +#endif +#if !defined(HAVE_FIPS) + int mgf = WC_MGF1NONE; + enum wc_HashType hash = WC_HASH_TYPE_NONE; + int pad_type = WC_RSA_NO_PAD; +#endif + int outLen = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_public_encrypt"); + + /* Validate parameters. */ + if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || + (from == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + #if !defined(HAVE_FIPS) + /* Convert to wolfCrypt padding, hash and MGF. */ + switch (padding) { + case WC_RSA_PKCS1_PADDING: + pad_type = WC_RSA_PKCSV15_PAD; + break; + case WC_RSA_PKCS1_OAEP_PADDING: + pad_type = WC_RSA_OAEP_PAD; + hash = WC_HASH_TYPE_SHA; + mgf = WC_MGF1SHA1; + break; + case WC_RSA_NO_PAD: + pad_type = WC_RSA_NO_PAD; + break; + default: + WOLFSSL_ERROR_MSG("RSA_public_encrypt doesn't support padding " + "scheme"); + ret = WOLFSSL_FATAL_ERROR; + } + #else + /* Check for supported padding schemes in FIPS. */ + /* TODO: Do we support more schemes in later versions of FIPS? */ + if (padding != WC_RSA_PKCS1_PADDING) { + WOLFSSL_ERROR_MSG("RSA_public_encrypt pad type not supported in " + "FIPS"); + ret = WOLFSSL_FATAL_ERROR; + } + #endif + } + + /* Set wolfCrypt RSA key data from external if not already done. */ + if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + /* Calculate maximum length of encrypted data. */ + outLen = wolfSSL_RSA_size(rsa); + if (outLen == 0) { + WOLFSSL_ERROR_MSG("Bad RSA size"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Get an RNG. */ + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); + if (rng == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Use wolfCrypt to public-encrypt with RSA key. */ + #if !defined(HAVE_FIPS) + ret = wc_RsaPublicEncrypt_ex(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal, rng, pad_type, hash, mgf, NULL, 0); + #else + ret = wc_RsaPublicEncrypt(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal, rng); + #endif + } + + /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ + if (initTmpRng) { + wc_FreeRng(tmpRng); + } + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); + + /* wolfCrypt error means return -1. */ + if (ret <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_RSA_public_encrypt", ret); + return ret; +} + +/* Decrypt with the RSA public key. + * + * Return compliant with OpenSSL. + * + * @param [in] len Length of encrypted data. + * @param [in] from Encrypted data. + * @param [out] to Decrypted data. + * @param [in] rsa RSA key. + * @param [in] padding Type of padding to around plaintext to remove. + * @return Size of decrypted data on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_private_decrypt(int len, const unsigned char* from, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int ret = 0; +#if !defined(HAVE_FIPS) + int mgf = WC_MGF1NONE; + enum wc_HashType hash = WC_HASH_TYPE_NONE; + int pad_type = WC_RSA_NO_PAD; +#endif + int outLen = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_private_decrypt"); + + /* Validate parameters. */ + if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || + (from == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + #if !defined(HAVE_FIPS) + switch (padding) { + case WC_RSA_PKCS1_PADDING: + pad_type = WC_RSA_PKCSV15_PAD; + break; + case WC_RSA_PKCS1_OAEP_PADDING: + pad_type = WC_RSA_OAEP_PAD; + hash = WC_HASH_TYPE_SHA; + mgf = WC_MGF1SHA1; + break; + case WC_RSA_NO_PAD: + pad_type = WC_RSA_NO_PAD; + break; + default: + WOLFSSL_ERROR_MSG("RSA_private_decrypt unsupported padding"); + ret = WOLFSSL_FATAL_ERROR; + } + #else + /* Check for supported padding schemes in FIPS. */ + /* TODO: Do we support more schemes in later versions of FIPS? */ + if (padding != WC_RSA_PKCS1_PADDING) { + WOLFSSL_ERROR_MSG("RSA_public_encrypt pad type not supported in " + "FIPS"); + ret = WOLFSSL_FATAL_ERROR; + } + #endif + } + + /* Set wolfCrypt RSA key data from external if not already done. */ + if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + /* Calculate maximum length of decrypted data. */ + outLen = wolfSSL_RSA_size(rsa); + if (outLen == 0) { + WOLFSSL_ERROR_MSG("Bad RSA size"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Use wolfCrypt to private-decrypt with RSA key. + * Size of 'to' buffer must be size of RSA key */ + #if !defined(HAVE_FIPS) + ret = wc_RsaPrivateDecrypt_ex(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal, pad_type, hash, mgf, NULL, 0); + #else + ret = wc_RsaPrivateDecrypt(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal); + #endif + } + + /* wolfCrypt error means return -1. */ + if (ret <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_RSA_private_decrypt", ret); + return ret; +} + +/* Decrypt with the RSA public key. + * + * @param [in] len Length of encrypted data. + * @param [in] from Encrypted data. + * @param [out] to Decrypted data. + * @param [in] rsa RSA key. + * @param [in] padding Type of padding to around plaintext to remove. + * @return Size of decrypted data on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_public_decrypt(int len, const unsigned char* from, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int ret = 0; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + int pad_type = WC_RSA_NO_PAD; +#endif + int outLen = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_public_decrypt"); + + /* Validate parameters. */ + if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || + (from == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + switch (padding) { + case WC_RSA_PKCS1_PADDING: + pad_type = WC_RSA_PKCSV15_PAD; + break; + case WC_RSA_NO_PAD: + pad_type = WC_RSA_NO_PAD; + break; + /* TODO: RSA_X931_PADDING not supported */ + default: + WOLFSSL_ERROR_MSG("RSA_public_decrypt unsupported padding"); + ret = WOLFSSL_FATAL_ERROR; + } + #else + if (padding != WC_RSA_PKCS1_PADDING) { + WOLFSSL_ERROR_MSG("RSA_public_decrypt pad type not supported in " + "FIPS"); + ret = WOLFSSL_FATAL_ERROR; + } + #endif + } + + /* Set wolfCrypt RSA key data from external if not already done. */ + if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + /* Calculate maximum length of encrypted data. */ + outLen = wolfSSL_RSA_size(rsa); + if (outLen == 0) { + WOLFSSL_ERROR_MSG("Bad RSA size"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Use wolfCrypt to public-decrypt with RSA key. */ + #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + /* Size of 'to' buffer must be size of RSA key. */ + ret = wc_RsaSSL_Verify_ex(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal, pad_type); + #else + /* For FIPS v1/v2 only PKCSV15 padding is supported */ + ret = wc_RsaSSL_Verify(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal); + #endif + } + + /* wolfCrypt error means return -1. */ + if (ret <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_RSA_public_decrypt", ret); + return ret; +} + +/* Encrypt with the RSA private key. + * + * Calls wc_RsaSSL_Sign. + * + * @param [in] len Length of data to encrypt. + * @param [in] from Data to encrypt. + * @param [out] to Encrypted data. + * @param [in] rsa RSA key. + * @param [in] padding Type of padding to place around plaintext. + * @return Size of encrypted data on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_private_encrypt(int len, const unsigned char* from, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int ret = 0; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRng = NULL; +#else + WC_RNG _tmpRng[1]; + WC_RNG* tmpRng = _tmpRng; +#endif + + WOLFSSL_ENTER("wolfSSL_RSA_private_encrypt"); + + /* Validate parameters. */ + if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || + (from == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + switch (padding) { + case WC_RSA_PKCS1_PADDING: + #ifdef WC_RSA_NO_PADDING + case WC_RSA_NO_PAD: + #endif + break; + /* TODO: RSA_X931_PADDING not supported */ + default: + WOLFSSL_ERROR_MSG("RSA_private_encrypt unsupported padding"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + /* Set wolfCrypt RSA key data from external if not already done. */ + if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + /* Get an RNG. */ + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); + if (rng == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Use wolfCrypt to private-encrypt with RSA key. + * Size of output buffer must be size of RSA key. */ + if (padding == WC_RSA_PKCS1_PADDING) { + ret = wc_RsaSSL_Sign(from, (word32)len, to, + (word32)wolfSSL_RSA_size(rsa), (RsaKey*)rsa->internal, rng); + } + #ifdef WC_RSA_NO_PADDING + else if (padding == WC_RSA_NO_PAD) { + word32 outLen = (word32)wolfSSL_RSA_size(rsa); + ret = wc_RsaFunction(from, (word32)len, to, &outLen, + RSA_PRIVATE_ENCRYPT, (RsaKey*)rsa->internal, rng); + if (ret == 0) + ret = (int)outLen; + } + #endif + } + + /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ + if (initTmpRng) { + wc_FreeRng(tmpRng); + } + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); + + /* wolfCrypt error means return -1. */ + if (ret <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_RSA_private_encrypt", ret); + return ret; +} + +/* + * RSA misc operation APIs + */ + +/* Calculate d mod p-1 and q-1 into BNs. + * + * Not OpenSSL API. + * + * @param [in, out] rsa RSA key. + * @return 1 on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_GenAdd(WOLFSSL_RSA* rsa) +{ + int ret = 1; + int err; + mp_int* t = NULL; + WC_DECLARE_VAR(tmp, mp_int, 1, 0); + + WOLFSSL_ENTER("wolfSSL_RsaGenAdd"); + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->p == NULL) || (rsa->q == NULL) || + (rsa->d == NULL) || (rsa->dmp1 == NULL) || (rsa->dmq1 == NULL)) { + WOLFSSL_ERROR_MSG("rsa no init error"); + ret = WOLFSSL_FATAL_ERROR; + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 1) { + tmp = (mp_int *)XMALLOC(sizeof(*tmp), rsa->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL) { + WOLFSSL_ERROR_MSG("Memory allocation failure"); + ret = WOLFSSL_FATAL_ERROR; + } + } +#endif + + if (ret == 1) { + /* Initialize temp MP integer. */ + if (mp_init(tmp) != MP_OKAY) { + WOLFSSL_ERROR_MSG("mp_init error"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 1) { + t = tmp; + + /* Sub 1 from p into temp. */ + err = mp_sub_d((mp_int*)rsa->p->internal, 1, tmp); + if (err != MP_OKAY) { + WOLFSSL_ERROR_MSG("mp_sub_d error"); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Calculate d mod (p - 1) into dmp1 MP integer of BN. */ + err = mp_mod((mp_int*)rsa->d->internal, tmp, + (mp_int*)rsa->dmp1->internal); + if (err != MP_OKAY) { + WOLFSSL_ERROR_MSG("mp_mod error"); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Sub 1 from q into temp. */ + err = mp_sub_d((mp_int*)rsa->q->internal, 1, tmp); + if (err != MP_OKAY) { + WOLFSSL_ERROR_MSG("mp_sub_d error"); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Calculate d mod (q - 1) into dmq1 MP integer of BN. */ + err = mp_mod((mp_int*)rsa->d->internal, tmp, + (mp_int*)rsa->dmq1->internal); + if (err != MP_OKAY) { + WOLFSSL_ERROR_MSG("mp_mod error"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + mp_clear(t); + +#ifdef WOLFSSL_SMALL_STACK + if (rsa != NULL) { + XFREE(tmp, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + + return ret; +} + + +#ifndef NO_WOLFSSL_STUB +/* Enable blinding for RSA key operations. + * + * Blinding is a compile time option in wolfCrypt. + * + * @param [in] rsa RSA key. Unused. + * @param [in] bnCtx BN context to use for blinding. Unused. + * @return 1 always. + */ +int wolfSSL_RSA_blinding_on(WOLFSSL_RSA* rsa, WOLFSSL_BN_CTX* bnCtx) +{ + WOLFSSL_STUB("RSA_blinding_on"); + WOLFSSL_ENTER("wolfSSL_RSA_blinding_on"); + + (void)rsa; + (void)bnCtx; + + return 1; /* on by default */ +} +#endif + +#endif /* OPENSSL_EXTRA */ + +#endif /* !NO_RSA */ + +/******************************************************************************* + * END OF RSA API + ******************************************************************************/ + +#endif /* !WOLFSSL_PK_RSA_INCLUDED */ diff --git a/src/ssl.c b/src/ssl.c index ff0a4eb0e5..bff77b2ec1 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -190,6 +190,12 @@ #define WOLFSSL_SSL_SESS_INCLUDED #include "src/ssl_sess.c" + +#define WOLFSSL_SSL_API_CERT_INCLUDED +#include "src/ssl_api_cert.c" + +#define WOLFSSL_SSL_API_PK_INCLUDED +#include "src/ssl_api_pk.c" #endif #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ @@ -359,6 +365,9 @@ WC_RNG* wolfssl_make_rng(WC_RNG* rng, int* local) #define WOLFSSL_PK_INCLUDED #include "src/pk.c" +#define WOLFSSL_EVP_PK_INCLUDED +#include "wolfcrypt/src/evp_pk.c" + #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) /* copies over data of "in" to "out" */ static void wolfSSL_CIPHER_copy(WOLFSSL_CIPHER* in, WOLFSSL_CIPHER* out) @@ -404,710 +413,8 @@ static WOLFSSL_X509_OBJECT* wolfSSL_X509_OBJECT_dup(WOLFSSL_X509_OBJECT* obj) #include -#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) -/* create the hpke key and ech config to send to clients */ -int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName, - word16 kemId, word16 kdfId, word16 aeadId) -{ - int ret = 0; - word16 encLen = DHKEM_X25519_ENC_LEN; - WOLFSSL_EchConfig* newConfig; - WOLFSSL_EchConfig* parentConfig; -#ifdef WOLFSSL_SMALL_STACK - Hpke* hpke = NULL; - WC_RNG* rng; -#else - Hpke hpke[1]; - WC_RNG rng[1]; -#endif - - if (ctx == NULL || publicName == NULL) - return BAD_FUNC_ARG; - - WC_ALLOC_VAR_EX(rng, WC_RNG, 1, ctx->heap, DYNAMIC_TYPE_RNG, - return MEMORY_E); - ret = wc_InitRng(rng); - if (ret != 0) { - WC_FREE_VAR_EX(rng, ctx->heap, DYNAMIC_TYPE_RNG); - return ret; - } - - newConfig = (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), - ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (newConfig == NULL) - ret = MEMORY_E; - else - XMEMSET(newConfig, 0, sizeof(WOLFSSL_EchConfig)); - - /* set random config id */ - if (ret == 0) - ret = wc_RNG_GenerateByte(rng, &newConfig->configId); - - /* if 0 is selected for algorithms use default, may change with draft */ - if (kemId == 0) - kemId = DHKEM_X25519_HKDF_SHA256; - - if (kdfId == 0) - kdfId = HKDF_SHA256; - - if (aeadId == 0) - aeadId = HPKE_AES_128_GCM; - - if (ret == 0) { - /* set the kem id */ - newConfig->kemId = kemId; - - /* set the cipher suite, only 1 for now */ - newConfig->numCipherSuites = 1; - newConfig->cipherSuites = - (EchCipherSuite*)XMALLOC(sizeof(EchCipherSuite), ctx->heap, - DYNAMIC_TYPE_TMP_BUFFER); - - if (newConfig->cipherSuites == NULL) { - ret = MEMORY_E; - } - else { - newConfig->cipherSuites[0].kdfId = kdfId; - newConfig->cipherSuites[0].aeadId = aeadId; - } - } - -#ifdef WOLFSSL_SMALL_STACK - if (ret == 0) { - hpke = (Hpke*)XMALLOC(sizeof(Hpke), ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (hpke == NULL) - ret = MEMORY_E; - } -#endif - - if (ret == 0) - ret = wc_HpkeInit(hpke, kemId, kdfId, aeadId, ctx->heap); - - /* generate the receiver private key */ - if (ret == 0) - ret = wc_HpkeGenerateKeyPair(hpke, &newConfig->receiverPrivkey, rng); - - /* done with RNG */ - wc_FreeRng(rng); - - /* serialize the receiver key */ - if (ret == 0) - ret = wc_HpkeSerializePublicKey(hpke, newConfig->receiverPrivkey, - newConfig->receiverPubkey, &encLen); - - if (ret == 0) { - newConfig->publicName = (char*)XMALLOC(XSTRLEN(publicName) + 1, - ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (newConfig->publicName == NULL) { - ret = MEMORY_E; - } - else { - XMEMCPY(newConfig->publicName, publicName, - XSTRLEN(publicName) + 1); - } - } - - if (ret != 0) { - if (newConfig) { - XFREE(newConfig->cipherSuites, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(newConfig->publicName, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(newConfig, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - } - } - else { - parentConfig = ctx->echConfigs; - - if (parentConfig == NULL) { - ctx->echConfigs = newConfig; - } - else { - while (parentConfig->next != NULL) { - parentConfig = parentConfig->next; - } - - parentConfig->next = newConfig; - } - } - - if (ret == 0) - ret = WOLFSSL_SUCCESS; - - WC_FREE_VAR_EX(hpke, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - WC_FREE_VAR_EX(rng, ctx->heap, DYNAMIC_TYPE_RNG); - - return ret; -} - -int wolfSSL_CTX_SetEchConfigsBase64(WOLFSSL_CTX* ctx, const char* echConfigs64, - word32 echConfigs64Len) -{ - int ret = 0; - word32 decodedLen = echConfigs64Len * 3 / 4 + 1; - byte* decodedConfigs; - - if (ctx == NULL || echConfigs64 == NULL || echConfigs64Len == 0) - return BAD_FUNC_ARG; - - decodedConfigs = (byte*)XMALLOC(decodedLen, ctx->heap, - DYNAMIC_TYPE_TMP_BUFFER); - - if (decodedConfigs == NULL) - return MEMORY_E; - - decodedConfigs[decodedLen - 1] = 0; - - /* decode the echConfigs */ - ret = Base64_Decode((const byte*)echConfigs64, echConfigs64Len, - decodedConfigs, &decodedLen); - - if (ret != 0) { - XFREE(decodedConfigs, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - return ret; - } - - ret = wolfSSL_CTX_SetEchConfigs(ctx, decodedConfigs, decodedLen); - - XFREE(decodedConfigs, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} - -int wolfSSL_CTX_SetEchConfigs(WOLFSSL_CTX* ctx, const byte* echConfigs, - word32 echConfigsLen) -{ - int ret; - - if (ctx == NULL || echConfigs == NULL || echConfigsLen == 0) - return BAD_FUNC_ARG; - - FreeEchConfigs(ctx->echConfigs, ctx->heap); - ctx->echConfigs = NULL; - ret = SetEchConfigsEx(&ctx->echConfigs, ctx->heap, echConfigs, - echConfigsLen); - - if (ret == 0) - return WOLFSSL_SUCCESS; - - return ret; -} - -/* get the ech configs that the server context is using */ -int wolfSSL_CTX_GetEchConfigs(WOLFSSL_CTX* ctx, byte* output, - word32* outputLen) { - if (ctx == NULL || outputLen == NULL) - return BAD_FUNC_ARG; - - /* if we don't have ech configs */ - if (ctx->echConfigs == NULL) - return WOLFSSL_FATAL_ERROR; - - return GetEchConfigsEx(ctx->echConfigs, output, outputLen); -} - -void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable) -{ - if (ctx != NULL) { - ctx->disableECH = !enable; - if (ctx->disableECH) { - TLSX_Remove(&ctx->extensions, TLSX_ECH, ctx->heap); - FreeEchConfigs(ctx->echConfigs, ctx->heap); - ctx->echConfigs = NULL; - } - } -} - -/* set the ech config from base64 for our client ssl object, base64 is the - * format ech configs are sent using dns records */ -int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64, - word32 echConfigs64Len) -{ - int ret = 0; - word32 decodedLen = echConfigs64Len * 3 / 4 + 1; - byte* decodedConfigs; - - if (ssl == NULL || echConfigs64 == NULL || echConfigs64Len == 0) - return BAD_FUNC_ARG; - - /* already have ech configs */ - if (ssl->options.useEch == 1) { - return WOLFSSL_FATAL_ERROR; - } - - decodedConfigs = (byte*)XMALLOC(decodedLen, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - - if (decodedConfigs == NULL) - return MEMORY_E; - - decodedConfigs[decodedLen - 1] = 0; - - /* decode the echConfigs */ - ret = Base64_Decode((byte*)echConfigs64, echConfigs64Len, - decodedConfigs, &decodedLen); - - if (ret != 0) { - XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - return ret; - } - - ret = wolfSSL_SetEchConfigs(ssl, decodedConfigs, decodedLen); - - XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} - -/* set the ech config from a raw buffer, this is the format ech configs are - * sent using retry_configs from the ech server */ -int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs, - word32 echConfigsLen) -{ - int ret; - - if (ssl == NULL || echConfigs == NULL || echConfigsLen == 0) - return BAD_FUNC_ARG; - - /* already have ech configs */ - if (ssl->options.useEch == 1) { - return WOLFSSL_FATAL_ERROR; - } - - ret = SetEchConfigsEx(&ssl->echConfigs, ssl->heap, echConfigs, - echConfigsLen); - - /* if we found valid configs */ - if (ret == 0) { - ssl->options.useEch = 1; - return WOLFSSL_SUCCESS; - } - - return ret; -} - -/* get the raw ech config from our struct */ -int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) -{ - int i; - word16 totalLen = 0; - - if (config == NULL || (output == NULL && outputLen == NULL)) - return BAD_FUNC_ARG; - - /* 2 for version */ - totalLen += 2; - /* 2 for length */ - totalLen += 2; - /* 1 for configId */ - totalLen += 1; - /* 2 for kemId */ - totalLen += 2; - /* 2 for hpke_len */ - totalLen += 2; - - /* hpke_pub_key */ - switch (config->kemId) { - case DHKEM_P256_HKDF_SHA256: - totalLen += DHKEM_P256_ENC_LEN; - break; - case DHKEM_P384_HKDF_SHA384: - totalLen += DHKEM_P384_ENC_LEN; - break; - case DHKEM_P521_HKDF_SHA512: - totalLen += DHKEM_P521_ENC_LEN; - break; - case DHKEM_X25519_HKDF_SHA256: - totalLen += DHKEM_X25519_ENC_LEN; - break; - case DHKEM_X448_HKDF_SHA512: - totalLen += DHKEM_X448_ENC_LEN; - break; - } - - /* cipherSuitesLen */ - totalLen += 2; - /* cipherSuites */ - totalLen += config->numCipherSuites * 4; - /* public name len */ - totalLen += 2; - - /* public name */ - totalLen += XSTRLEN(config->publicName); - /* trailing zeros */ - totalLen += 2; - - if (output == NULL) { - *outputLen = totalLen; - return WC_NO_ERR_TRACE(LENGTH_ONLY_E); - } - - if (totalLen > *outputLen) { - *outputLen = totalLen; - return INPUT_SIZE_E; - } - - /* version */ - c16toa(TLSX_ECH, output); - output += 2; - - /* length - 4 for version and length itself */ - c16toa(totalLen - 4, output); - output += 2; - - /* configId */ - *output = config->configId; - output++; - /* kemId */ - c16toa(config->kemId, output); - output += 2; - - /* length and key itself */ - switch (config->kemId) { - case DHKEM_P256_HKDF_SHA256: - c16toa(DHKEM_P256_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_P256_ENC_LEN); - output += DHKEM_P256_ENC_LEN; - break; - case DHKEM_P384_HKDF_SHA384: - c16toa(DHKEM_P384_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_P384_ENC_LEN); - output += DHKEM_P384_ENC_LEN; - break; - case DHKEM_P521_HKDF_SHA512: - c16toa(DHKEM_P521_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_P521_ENC_LEN); - output += DHKEM_P521_ENC_LEN; - break; - case DHKEM_X25519_HKDF_SHA256: - c16toa(DHKEM_X25519_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_X25519_ENC_LEN); - output += DHKEM_X25519_ENC_LEN; - break; - case DHKEM_X448_HKDF_SHA512: - c16toa(DHKEM_X448_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_X448_ENC_LEN); - output += DHKEM_X448_ENC_LEN; - break; - } - - /* cipherSuites len */ - c16toa(config->numCipherSuites * 4, output); - output += 2; - - /* cipherSuites */ - for (i = 0; i < config->numCipherSuites; i++) { - c16toa(config->cipherSuites[i].kdfId, output); - output += 2; - c16toa(config->cipherSuites[i].aeadId, output); - output += 2; - } - - /* set maximum name length to 0 */ - *output = 0; - output++; - - /* publicName len */ - *output = XSTRLEN(config->publicName); - output++; - - /* publicName */ - XMEMCPY(output, config->publicName, - XSTRLEN(config->publicName)); - output += XSTRLEN(config->publicName); - - /* terminating zeros */ - c16toa(0, output); - /* output += 2; */ - - *outputLen = totalLen; - - return 0; -} - -/* wrapper function to get ech configs from application code */ -int wolfSSL_GetEchConfigs(WOLFSSL* ssl, byte* output, word32* outputLen) -{ - if (ssl == NULL || outputLen == NULL) - return BAD_FUNC_ARG; - - /* if we don't have ech configs */ - if (ssl->options.useEch != 1) { - return WOLFSSL_FATAL_ERROR; - } - - return GetEchConfigsEx(ssl->echConfigs, output, outputLen); -} - -void wolfSSL_SetEchEnable(WOLFSSL* ssl, byte enable) -{ - if (ssl != NULL) { - ssl->options.disableECH = !enable; - if (ssl->options.disableECH) { - TLSX_Remove(&ssl->extensions, TLSX_ECH, ssl->heap); - FreeEchConfigs(ssl->echConfigs, ssl->heap); - ssl->echConfigs = NULL; - } - } -} - -int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap, - const byte* echConfigs, word32 echConfigsLen) -{ - int ret = 0; - int i; - int j; - word16 totalLength; - word16 version; - word16 length; - word16 hpkePubkeyLen; - word16 cipherSuitesLen; - word16 publicNameLen; - WOLFSSL_EchConfig* configList = NULL; - WOLFSSL_EchConfig* workingConfig = NULL; - WOLFSSL_EchConfig* lastConfig = NULL; - byte* echConfig = NULL; - - if (outputConfigs == NULL || echConfigs == NULL || echConfigsLen == 0) - return BAD_FUNC_ARG; - - /* check that the total length is well formed */ - ato16(echConfigs, &totalLength); - - if (totalLength != echConfigsLen - 2) { - return WOLFSSL_FATAL_ERROR; - } - - /* skip the total length uint16_t */ - i = 2; - - do { - echConfig = (byte*)echConfigs + i; - ato16(echConfig, &version); - ato16(echConfig + 2, &length); - - /* if the version does not match */ - if (version != TLSX_ECH) { - /* we hit the end of the configs */ - if ( (word32)i + 2 >= echConfigsLen ) { - break; - } - - /* skip this config, +4 for version and length */ - i += length + 4; - continue; - } - - /* check if the length will overrun the buffer */ - if ((word32)i + length + 4 > echConfigsLen) { - break; - } - - if (workingConfig == NULL) { - workingConfig = - (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), heap, - DYNAMIC_TYPE_TMP_BUFFER); - configList = workingConfig; - if (workingConfig != NULL) { - workingConfig->next = NULL; - } - } - else { - lastConfig = workingConfig; - workingConfig->next = - (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), - heap, DYNAMIC_TYPE_TMP_BUFFER); - workingConfig = workingConfig->next; - } - - if (workingConfig == NULL) { - ret = MEMORY_E; - break; - } - - XMEMSET(workingConfig, 0, sizeof(WOLFSSL_EchConfig)); - - /* rawLen */ - workingConfig->rawLen = length + 4; - - /* raw body */ - workingConfig->raw = (byte*)XMALLOC(workingConfig->rawLen, - heap, DYNAMIC_TYPE_TMP_BUFFER); - if (workingConfig->raw == NULL) { - ret = MEMORY_E; - break; - } - - XMEMCPY(workingConfig->raw, echConfig, workingConfig->rawLen); - - /* skip over version and length */ - echConfig += 4; - - /* configId, 1 byte */ - workingConfig->configId = *(echConfig); - echConfig++; - /* kemId, 2 bytes */ - ato16(echConfig, &workingConfig->kemId); - echConfig += 2; - /* hpke public_key length, 2 bytes */ - ato16(echConfig, &hpkePubkeyLen); - echConfig += 2; - /* hpke public_key */ - XMEMCPY(workingConfig->receiverPubkey, echConfig, hpkePubkeyLen); - echConfig += hpkePubkeyLen; - /* cipherSuitesLen */ - ato16(echConfig, &cipherSuitesLen); - - workingConfig->cipherSuites = (EchCipherSuite*)XMALLOC(cipherSuitesLen, - heap, DYNAMIC_TYPE_TMP_BUFFER); - if (workingConfig->cipherSuites == NULL) { - ret = MEMORY_E; - break; - } - - echConfig += 2; - workingConfig->numCipherSuites = cipherSuitesLen / 4; - /* cipherSuites */ - for (j = 0; j < workingConfig->numCipherSuites; j++) { - ato16(echConfig + j * 4, &workingConfig->cipherSuites[j].kdfId); - ato16(echConfig + j * 4 + 2, - &workingConfig->cipherSuites[j].aeadId); - } - echConfig += cipherSuitesLen; - /* ignore the maximum name length */ - echConfig++; - /* publicNameLen */ - publicNameLen = *(echConfig); - workingConfig->publicName = (char*)XMALLOC(publicNameLen + 1, - heap, DYNAMIC_TYPE_TMP_BUFFER); - if (workingConfig->publicName == NULL) { - ret = MEMORY_E; - break; - } - echConfig++; - /* publicName */ - XMEMCPY(workingConfig->publicName, echConfig, publicNameLen); - /* null terminated */ - workingConfig->publicName[publicNameLen] = 0; - - /* add length to go to next config, +4 for version and length */ - i += length + 4; - - /* check that we support this config */ - for (j = 0; j < HPKE_SUPPORTED_KEM_LEN; j++) { - if (hpkeSupportedKem[j] == workingConfig->kemId) - break; - } - - /* if we don't support the kem or at least one cipher suite */ - if (j >= HPKE_SUPPORTED_KEM_LEN || - EchConfigGetSupportedCipherSuite(workingConfig) < 0) - { - XFREE(workingConfig->cipherSuites, heap, - DYNAMIC_TYPE_TMP_BUFFER); - XFREE(workingConfig->publicName, heap, - DYNAMIC_TYPE_TMP_BUFFER); - XFREE(workingConfig->raw, heap, DYNAMIC_TYPE_TMP_BUFFER); - workingConfig = lastConfig; - } - } while ((word32)i < echConfigsLen); - - /* if we found valid configs */ - if (ret == 0 && configList != NULL) { - *outputConfigs = configList; - - return ret; - } - - workingConfig = configList; - - while (workingConfig != NULL) { - lastConfig = workingConfig; - workingConfig = workingConfig->next; - - XFREE(lastConfig->cipherSuites, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(lastConfig->publicName, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(lastConfig->raw, heap, DYNAMIC_TYPE_TMP_BUFFER); - - XFREE(lastConfig, heap, DYNAMIC_TYPE_TMP_BUFFER); - } - - if (ret == 0) - return WOLFSSL_FATAL_ERROR; - - return ret; -} - -/* get the raw ech configs from our linked list of ech config structs */ -int GetEchConfigsEx(WOLFSSL_EchConfig* configs, byte* output, word32* outputLen) -{ - int ret = 0; - WOLFSSL_EchConfig* workingConfig = NULL; - byte* outputStart = output; - word32 totalLen = 2; - word32 workingOutputLen = 0; - - if (configs == NULL || outputLen == NULL || - (output != NULL && *outputLen < totalLen)) { - return BAD_FUNC_ARG; - } - - - /* skip over total length which we fill in later */ - if (output != NULL) { - workingOutputLen = *outputLen - totalLen; - output += 2; - } - else { - /* caller getting the size only, set current 2 byte length size */ - *outputLen = totalLen; - } - - workingConfig = configs; - - while (workingConfig != NULL) { - /* get this config */ - ret = GetEchConfig(workingConfig, output, &workingOutputLen); - - if (output != NULL) - output += workingOutputLen; - - /* add this config's length to the total length */ - totalLen += workingOutputLen; - - if (totalLen > *outputLen) - workingOutputLen = 0; - else - workingOutputLen = *outputLen - totalLen; - - /* only error we break on, other 2 we need to keep finding length */ - if (ret == WC_NO_ERR_TRACE(BAD_FUNC_ARG)) - return BAD_FUNC_ARG; - - workingConfig = workingConfig->next; - } - - if (output == NULL) { - *outputLen = totalLen; - return WC_NO_ERR_TRACE(LENGTH_ONLY_E); - } - - if (totalLen > *outputLen) { - *outputLen = totalLen; - return INPUT_SIZE_E; - } - - /* total size -2 for size itself */ - c16toa(totalLen - 2, outputStart); - - *outputLen = totalLen; - - return WOLFSSL_SUCCESS; -} -#endif /* WOLFSSL_TLS13 && HAVE_ECH */ +#define WOLFSSL_SSL_ECH_INCLUDED +#include "src/ssl_ech.c" #ifdef OPENSSL_EXTRA static int wolfSSL_parse_cipher_list(WOLFSSL_CTX* ctx, WOLFSSL* ssl, @@ -1858,48 +1165,6 @@ int wolfSSL_dtls(WOLFSSL* ssl) return dtlsOpt; } -#if !defined(NO_CERTS) -/* Set whether mutual authentication is required for connections. - * Server side only. - * - * ctx The SSL/TLS CTX object. - * req 1 to indicate required and 0 when not. - * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a server and - * 0 on success. - */ -int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - if (ctx->method->side != WOLFSSL_SERVER_END) - return SIDE_ERROR; - - ctx->mutualAuth = (byte)req; - - return 0; -} - -/* Set whether mutual authentication is required for the connection. - * Server side only. - * - * ssl The SSL/TLS object. - * req 1 to indicate required and 0 when not. - * returns BAD_FUNC_ARG when ssl is NULL and - * SIDE_ERROR when not a server and 0 on success. - */ -int wolfSSL_mutual_auth(WOLFSSL* ssl, int req) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - if (ssl->options.side != WOLFSSL_SERVER_END) - return SIDE_ERROR; - - ssl->options.mutualAuth = (word16)req; - - return 0; -} -#endif /* NO_CERTS */ - #ifdef WOLFSSL_WOLFSENTRY_HOOKS int wolfSSL_CTX_set_AcceptFilter( @@ -3666,60 +2931,6 @@ int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) #endif /* NO_WOLFSSL_CLIENT */ #endif /* HAVE_TRUNCATED_HMAC */ -#ifndef NO_WOLFSSL_CLIENT -#ifdef HAVE_CERTIFICATE_STATUS_REQUEST - -int wolfSSL_UseOCSPStapling(WOLFSSL* ssl, byte status_type, byte options) -{ - WOLFSSL_ENTER("wolfSSL_UseOCSPStapling"); - - if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) - return BAD_FUNC_ARG; - - return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type, - options, NULL, ssl->heap, ssl->devId); -} - - -int wolfSSL_CTX_UseOCSPStapling(WOLFSSL_CTX* ctx, byte status_type, - byte options) -{ - WOLFSSL_ENTER("wolfSSL_CTX_UseOCSPStapling"); - - if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) - return BAD_FUNC_ARG; - - return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type, - options, NULL, ctx->heap, ctx->devId); -} - -#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ - -#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 - -int wolfSSL_UseOCSPStaplingV2(WOLFSSL* ssl, byte status_type, byte options) -{ - if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) - return BAD_FUNC_ARG; - - return TLSX_UseCertificateStatusRequestV2(&ssl->extensions, status_type, - options, ssl->heap, ssl->devId); -} - - -int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx, byte status_type, - byte options) -{ - if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) - return BAD_FUNC_ARG; - - return TLSX_UseCertificateStatusRequestV2(&ctx->extensions, status_type, - options, ctx->heap, ctx->devId); -} - -#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ -#endif /* !NO_WOLFSSL_CLIENT */ - /* Elliptic Curves */ #if defined(HAVE_SUPPORTED_CURVES) @@ -5202,16 +4413,6 @@ int wolfSSL_GetSequenceNumber(WOLFSSL* ssl, word64 *seq) #endif /* ATOMIC_USER */ -#ifndef NO_CERTS -WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx) -{ - WOLFSSL_CERT_MANAGER* cm = NULL; - if (ctx) - cm = ctx->cm; - return cm; -} -#endif /* NO_CERTS */ - #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) \ && defined(XFPRINTF) @@ -5538,826 +4739,6 @@ int wolfSSL_SetVersion(WOLFSSL* ssl, int version) } #endif /* !leanpsk */ -#ifndef NO_CERTS - -/* hash is the SHA digest of name, just use first 32 bits as hash */ -static WC_INLINE word32 HashSigner(const byte* hash) -{ - return MakeWordFromHash(hash) % CA_TABLE_SIZE; -} - - -/* does CA already exist on signer list */ -int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash) -{ - Signer* signers; - int ret = 0; - word32 row; - - if (cm == NULL || hash == NULL) { - return ret; - } - - row = HashSigner(hash); - - if (wc_LockMutex(&cm->caLock) != 0) { - return ret; - } - signers = cm->caTable[row]; - while (signers) { - byte* subjectHash; - - #ifndef NO_SKID - subjectHash = signers->subjectKeyIdHash; - #else - subjectHash = signers->subjectNameHash; - #endif - - if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { - ret = 1; /* success */ - break; - } - signers = signers->next; - } - wc_UnLockMutex(&cm->caLock); - - return ret; -} - - -#ifdef WOLFSSL_TRUST_PEER_CERT -/* hash is the SHA digest of name, just use first 32 bits as hash */ -static WC_INLINE word32 TrustedPeerHashSigner(const byte* hash) -{ - return MakeWordFromHash(hash) % TP_TABLE_SIZE; -} - -/* does trusted peer already exist on signer list */ -int AlreadyTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DecodedCert* cert) -{ - TrustedPeerCert* tp; - int ret = 0; - word32 row = TrustedPeerHashSigner(cert->subjectHash); - - if (wc_LockMutex(&cm->tpLock) != 0) - return ret; - tp = cm->tpTable[row]; - while (tp) { - if ((XMEMCMP(cert->subjectHash, tp->subjectNameHash, - SIGNER_DIGEST_SIZE) == 0) - #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER - && (XMEMCMP(cert->issuerHash, tp->issuerHash, - SIGNER_DIGEST_SIZE) == 0) - #endif - ) - ret = 1; - #ifndef NO_SKID - if (cert->extSubjKeyIdSet) { - /* Compare SKID as well if available */ - if (ret == 1 && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash, - SIGNER_DIGEST_SIZE) != 0) - ret = 0; - } - #endif - if (ret == 1) - break; - tp = tp->next; - } - wc_UnLockMutex(&cm->tpLock); - - return ret; -} - - -/* return Trusted Peer if found, otherwise NULL - type is what to match on - */ -TrustedPeerCert* GetTrustedPeer(void* vp, DecodedCert* cert) -{ - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - TrustedPeerCert* ret = NULL; - TrustedPeerCert* tp = NULL; - word32 row; - - if (cm == NULL || cert == NULL) - return NULL; - - row = TrustedPeerHashSigner(cert->subjectHash); - - if (wc_LockMutex(&cm->tpLock) != 0) - return ret; - - tp = cm->tpTable[row]; - while (tp) { - if ((XMEMCMP(cert->subjectHash, tp->subjectNameHash, - SIGNER_DIGEST_SIZE) == 0) - #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER - && (XMEMCMP(cert->issuerHash, tp->issuerHash, - SIGNER_DIGEST_SIZE) == 0) - #endif - ) - ret = tp; - #ifndef NO_SKID - if (cert->extSubjKeyIdSet) { - /* Compare SKID as well if available */ - if (ret != NULL && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash, - SIGNER_DIGEST_SIZE) != 0) - ret = NULL; - } - #endif - if (ret != NULL) - break; - tp = tp->next; - } - wc_UnLockMutex(&cm->tpLock); - - return ret; -} - - -int MatchTrustedPeer(TrustedPeerCert* tp, DecodedCert* cert) -{ - if (tp == NULL || cert == NULL) - return BAD_FUNC_ARG; - - /* subject key id or subject hash has been compared when searching - tpTable for the cert from function GetTrustedPeer */ - - /* compare signatures */ - if (tp->sigLen == cert->sigLength) { - if (XMEMCMP(tp->sig, cert->signature, cert->sigLength)) { - return WOLFSSL_FAILURE; - } - } - else { - return WOLFSSL_FAILURE; - } - - return WOLFSSL_SUCCESS; -} -#endif /* WOLFSSL_TRUST_PEER_CERT */ - - -/* return CA if found, otherwise NULL */ -Signer* GetCA(void* vp, byte* hash) -{ - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - Signer* ret = NULL; - Signer* signers; - word32 row = 0; - - if (cm == NULL || hash == NULL) - return NULL; - - row = HashSigner(hash); - - if (wc_LockMutex(&cm->caLock) != 0) - return ret; - - signers = cm->caTable[row]; - while (signers) { - byte* subjectHash; - #ifndef NO_SKID - subjectHash = signers->subjectKeyIdHash; - #else - subjectHash = signers->subjectNameHash; - #endif - if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { - ret = signers; - break; - } - signers = signers->next; - } - wc_UnLockMutex(&cm->caLock); - - return ret; -} - -#if defined(HAVE_OCSP) -Signer* GetCAByKeyHash(void* vp, const byte* keyHash) -{ - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - Signer* ret = NULL; - Signer* signers; - int row; - - if (cm == NULL || keyHash == NULL) - return NULL; - - /* try lookup using keyHash as subjKeyID first */ - ret = GetCA(vp, (byte*)keyHash); - if (ret != NULL && XMEMCMP(ret->subjectKeyHash, keyHash, KEYID_SIZE) == 0) { - return ret; - } - - /* if we can't find the cert, we have to scan the full table */ - if (wc_LockMutex(&cm->caLock) != 0) - return NULL; - - /* Unfortunately we need to look through the entire table */ - for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { - for (signers = cm->caTable[row]; signers != NULL; - signers = signers->next) { - if (XMEMCMP(signers->subjectKeyHash, keyHash, KEYID_SIZE) == 0) { - ret = signers; - break; - } - } - } - - wc_UnLockMutex(&cm->caLock); - return ret; -} -#endif -#ifdef WOLFSSL_AKID_NAME -Signer* GetCAByAKID(void* vp, const byte* issuer, word32 issuerSz, - const byte* serial, word32 serialSz) -{ - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - Signer* ret = NULL; - Signer* signers; - byte nameHash[SIGNER_DIGEST_SIZE]; - byte serialHash[SIGNER_DIGEST_SIZE]; - word32 row; - - if (cm == NULL || issuer == NULL || issuerSz == 0 || - serial == NULL || serialSz == 0) - return NULL; - - if (CalcHashId(issuer, issuerSz, nameHash) != 0 || - CalcHashId(serial, serialSz, serialHash) != 0) - return NULL; - - if (wc_LockMutex(&cm->caLock) != 0) - return ret; - - /* Unfortunately we need to look through the entire table */ - for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { - for (signers = cm->caTable[row]; signers != NULL; - signers = signers->next) { - if (XMEMCMP(signers->issuerNameHash, nameHash, SIGNER_DIGEST_SIZE) - == 0 && XMEMCMP(signers->serialHash, serialHash, - SIGNER_DIGEST_SIZE) == 0) { - ret = signers; - break; - } - } - } - - wc_UnLockMutex(&cm->caLock); - - return ret; -} -#endif - -#ifndef NO_SKID -/* return CA if found, otherwise NULL. Walk through hash table. */ -Signer* GetCAByName(void* vp, byte* hash) -{ - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - Signer* ret = NULL; - Signer* signers; - word32 row; - - if (cm == NULL) - return NULL; - - if (wc_LockMutex(&cm->caLock) != 0) - return ret; - - for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { - signers = cm->caTable[row]; - while (signers && ret == NULL) { - if (XMEMCMP(hash, signers->subjectNameHash, - SIGNER_DIGEST_SIZE) == 0) { - ret = signers; - } - signers = signers->next; - } - } - wc_UnLockMutex(&cm->caLock); - - return ret; -} -#endif - - -#ifdef WOLFSSL_TRUST_PEER_CERT -/* add a trusted peer cert to linked list */ -int AddTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int verify) -{ - int ret = 0; - int row = 0; - TrustedPeerCert* peerCert; - DecodedCert* cert; - DerBuffer* der = *pDer; - - WOLFSSL_MSG("Adding a Trusted Peer Cert"); - - cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, - DYNAMIC_TYPE_DCERT); - if (cert == NULL) { - FreeDer(&der); - return MEMORY_E; - } - - InitDecodedCert(cert, der->buffer, der->length, cm->heap); - if ((ret = ParseCert(cert, TRUSTED_PEER_TYPE, verify, cm)) != 0) { - FreeDecodedCert(cert); - XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); - FreeDer(&der); - return ret; - } - WOLFSSL_MSG("\tParsed new trusted peer cert"); - - peerCert = (TrustedPeerCert*)XMALLOC(sizeof(TrustedPeerCert), cm->heap, - DYNAMIC_TYPE_CERT); - if (peerCert == NULL) { - FreeDecodedCert(cert); - XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); - FreeDer(&der); - return MEMORY_E; - } - XMEMSET(peerCert, 0, sizeof(TrustedPeerCert)); - - #ifndef IGNORE_NAME_CONSTRAINTS - if (peerCert->permittedNames) - FreeNameSubtrees(peerCert->permittedNames, cm->heap); - if (peerCert->excludedNames) - FreeNameSubtrees(peerCert->excludedNames, cm->heap); - #endif - - if (AlreadyTrustedPeer(cm, cert)) { - WOLFSSL_MSG("\tAlready have this CA, not adding again"); - FreeTrustedPeer(peerCert, cm->heap); - (void)ret; - } - else { - /* add trusted peer signature */ - peerCert->sigLen = cert->sigLength; - peerCert->sig = (byte *)XMALLOC(cert->sigLength, cm->heap, - DYNAMIC_TYPE_SIGNATURE); - if (peerCert->sig == NULL) { - FreeDecodedCert(cert); - XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); - FreeTrustedPeer(peerCert, cm->heap); - FreeDer(&der); - return MEMORY_E; - } - XMEMCPY(peerCert->sig, cert->signature, cert->sigLength); - - /* add trusted peer name */ - peerCert->nameLen = cert->subjectCNLen; - peerCert->name = cert->subjectCN; - #ifndef IGNORE_NAME_CONSTRAINTS - peerCert->permittedNames = cert->permittedNames; - peerCert->excludedNames = cert->excludedNames; - #endif - - /* add SKID when available and hash of name */ - #ifndef NO_SKID - XMEMCPY(peerCert->subjectKeyIdHash, cert->extSubjKeyId, - SIGNER_DIGEST_SIZE); - #endif - XMEMCPY(peerCert->subjectNameHash, cert->subjectHash, - SIGNER_DIGEST_SIZE); - #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER - XMEMCPY(peerCert->issuerHash, cert->issuerHash, - SIGNER_DIGEST_SIZE); - #endif - /* If Key Usage not set, all uses valid. */ - peerCert->next = NULL; - cert->subjectCN = 0; - #ifndef IGNORE_NAME_CONSTRAINTS - cert->permittedNames = NULL; - cert->excludedNames = NULL; - #endif - - row = (int)TrustedPeerHashSigner(peerCert->subjectNameHash); - - if (wc_LockMutex(&cm->tpLock) == 0) { - peerCert->next = cm->tpTable[row]; - cm->tpTable[row] = peerCert; /* takes ownership */ - wc_UnLockMutex(&cm->tpLock); - } - else { - WOLFSSL_MSG("\tTrusted Peer Cert Mutex Lock failed"); - FreeDecodedCert(cert); - XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); - FreeTrustedPeer(peerCert, cm->heap); - FreeDer(&der); - return BAD_MUTEX_E; - } - } - - WOLFSSL_MSG("\tFreeing parsed trusted peer cert"); - FreeDecodedCert(cert); - XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); - WOLFSSL_MSG("\tFreeing der trusted peer cert"); - FreeDer(&der); - WOLFSSL_MSG("\t\tOK Freeing der trusted peer cert"); - WOLFSSL_LEAVE("AddTrustedPeer", ret); - - return WOLFSSL_SUCCESS; -} -#endif /* WOLFSSL_TRUST_PEER_CERT */ - -int AddSigner(WOLFSSL_CERT_MANAGER* cm, Signer *s) -{ - byte* subjectHash; - Signer* signers; - word32 row; - - if (cm == NULL || s == NULL) - return BAD_FUNC_ARG; - -#ifndef NO_SKID - subjectHash = s->subjectKeyIdHash; -#else - subjectHash = s->subjectNameHash; -#endif - - if (AlreadySigner(cm, subjectHash)) { - FreeSigner(s, cm->heap); - return 0; - } - - row = HashSigner(subjectHash); - - if (wc_LockMutex(&cm->caLock) != 0) - return BAD_MUTEX_E; - - signers = cm->caTable[row]; - s->next = signers; - cm->caTable[row] = s; - - wc_UnLockMutex(&cm->caLock); - return 0; -} - -/* owns der, internal now uses too */ -/* type flag ids from user or from chain received during verify - don't allow chain ones to be added w/o isCA extension */ -int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) -{ - int ret; - Signer* signer = NULL; - word32 row; - byte* subjectHash; - WC_DECLARE_VAR(cert, DecodedCert, 1, 0); - DerBuffer* der = *pDer; - - WOLFSSL_MSG_CERT_LOG("Adding a CA"); - - if (cm == NULL) { - FreeDer(pDer); - return BAD_FUNC_ARG; - } - - #ifdef WOLFSSL_SMALL_STACK - cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); - if (cert == NULL) { - FreeDer(pDer); - return MEMORY_E; - } - #endif - - InitDecodedCert(cert, der->buffer, der->length, cm->heap); - -#ifdef WC_ASN_UNKNOWN_EXT_CB - if (cm->unknownExtCallback != NULL) { - wc_SetUnknownExtCallback(cert, cm->unknownExtCallback); - } -#endif - - WOLFSSL_MSG_CERT("\tParsing new CA"); - ret = ParseCert(cert, CA_TYPE, verify, cm); - - WOLFSSL_MSG("\tParsed new CA"); -#ifdef WOLFSSL_DEBUG_CERTS - { - const char* err_msg; - if (ret == 0) { - WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "issuer: '%s'", - cert->issuer); - WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "subject: '%s'", - cert->subject); - } - else { - WOLFSSL_MSG_CERT( - WOLFSSL_MSG_CERT_INDENT "Failed during parse of new CA"); - err_msg = wc_GetErrorString(ret); - WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "error ret: %d; %s", - ret, err_msg); - } - } -#endif /* WOLFSSL_DEBUG_CERTS */ - -#ifndef NO_SKID - subjectHash = cert->extSubjKeyId; -#else - subjectHash = cert->subjectHash; -#endif - - /* check CA key size */ - if (verify && (ret == 0 )) { - switch (cert->keyOID) { - #ifndef NO_RSA - #ifdef WC_RSA_PSS - case RSAPSSk: - #endif - case RSAk: - if (cm->minRsaKeySz < 0 || - cert->pubKeySize < (word16)cm->minRsaKeySz) { - ret = RSA_KEY_SIZE_E; - WOLFSSL_MSG_CERT_LOG("\tCA RSA key size error"); - WOLFSSL_MSG_CERT_EX("\tCA RSA pubKeySize = %d; " - "minRsaKeySz = %d", - cert->pubKeySize, cm->minRsaKeySz); - } - break; - #endif /* !NO_RSA */ - #ifdef HAVE_ECC - case ECDSAk: - if (cm->minEccKeySz < 0 || - cert->pubKeySize < (word16)cm->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG_CERT_LOG("\tCA ECC key size error"); - WOLFSSL_MSG_CERT_EX("\tCA ECC pubKeySize = %d; " - "minEccKeySz = %d", - cert->pubKeySize, cm->minEccKeySz); - } - break; - #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 - case ED25519k: - if (cm->minEccKeySz < 0 || - ED25519_KEY_SIZE < (word16)cm->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("\tCA ECC key size error"); - } - break; - #endif /* HAVE_ED25519 */ - #ifdef HAVE_ED448 - case ED448k: - if (cm->minEccKeySz < 0 || - ED448_KEY_SIZE < (word16)cm->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("\tCA ECC key size error"); - } - break; - #endif /* HAVE_ED448 */ - #if defined(HAVE_FALCON) - case FALCON_LEVEL1k: - if (cm->minFalconKeySz < 0 || - FALCON_LEVEL1_KEY_SIZE < (word16)cm->minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Falcon level 1 key size error"); - } - break; - case FALCON_LEVEL5k: - if (cm->minFalconKeySz < 0 || - FALCON_LEVEL5_KEY_SIZE < (word16)cm->minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Falcon level 5 key size error"); - } - break; - #endif /* HAVE_FALCON */ - #if defined(HAVE_DILITHIUM) - #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT - case DILITHIUM_LEVEL2k: - if (cm->minDilithiumKeySz < 0 || - DILITHIUM_LEVEL2_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 2 key size error"); - } - break; - case DILITHIUM_LEVEL3k: - if (cm->minDilithiumKeySz < 0 || - DILITHIUM_LEVEL3_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 3 key size error"); - } - break; - case DILITHIUM_LEVEL5k: - if (cm->minDilithiumKeySz < 0 || - DILITHIUM_LEVEL5_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 5 key size error"); - } - break; - #endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */ - case ML_DSA_LEVEL2k: - if (cm->minDilithiumKeySz < 0 || - ML_DSA_LEVEL2_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 2 key size error"); - } - break; - case ML_DSA_LEVEL3k: - if (cm->minDilithiumKeySz < 0 || - ML_DSA_LEVEL3_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 3 key size error"); - } - break; - case ML_DSA_LEVEL5k: - if (cm->minDilithiumKeySz < 0 || - ML_DSA_LEVEL5_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 5 key size error"); - } - break; - #endif /* HAVE_DILITHIUM */ - - default: - WOLFSSL_MSG("\tNo key size check done on CA"); - break; /* no size check if key type is not in switch */ - } - } - - if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA && - type != WOLFSSL_TEMP_CA) { - WOLFSSL_MSG("\tCan't add as CA if not actually one"); - ret = NOT_CA_ERROR; - } -#ifndef ALLOW_INVALID_CERTSIGN - else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA && - type != WOLFSSL_TEMP_CA && !cert->selfSigned && - (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { - /* Intermediate CA certs are required to have the keyCertSign - * extension set. User loaded root certs are not. */ - WOLFSSL_MSG("\tDoesn't have key usage certificate signing"); - ret = NOT_CA_ERROR; - } -#endif - else if (ret == 0 && AlreadySigner(cm, subjectHash)) { - WOLFSSL_MSG("\tAlready have this CA, not adding again"); - (void)ret; - } - else if (ret == 0) { - /* take over signer parts */ - signer = MakeSigner(cm->heap); - if (!signer) - ret = MEMORY_ERROR; - } - if (ret == 0 && signer != NULL) { - ret = FillSigner(signer, cert, type, der); - - if (ret == 0){ - #ifndef NO_SKID - row = HashSigner(signer->subjectKeyIdHash); - #else - row = HashSigner(signer->subjectNameHash); - #endif - } - - #if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_FSPSM_TLS) - /* Verify CA by TSIP so that generated tsip key is going to */ - /* be able to be used for peer's cert verification */ - /* TSIP is only able to handle USER CA, and only one CA. */ - /* Therefore, it doesn't need to call TSIP again if there is already */ - /* verified CA. */ - if ( ret == 0 && signer != NULL ) { - signer->cm_idx = row; - if (type == WOLFSSL_USER_CA) { - if ((ret = wc_Renesas_cmn_RootCertVerify(cert->source, - cert->maxIdx, - cert->sigCtx.CertAtt.pubkey_n_start, - cert->sigCtx.CertAtt.pubkey_n_len - 1, - cert->sigCtx.CertAtt.pubkey_e_start, - cert->sigCtx.CertAtt.pubkey_e_len - 1, - row/* cm index */)) - < 0) - WOLFSSL_MSG("Renesas_RootCertVerify() failed"); - else - WOLFSSL_MSG("Renesas_RootCertVerify() succeed or skipped"); - } - } - #endif /* TSIP or SCE */ - - if (ret == 0 && wc_LockMutex(&cm->caLock) == 0) { - signer->next = cm->caTable[row]; - cm->caTable[row] = signer; /* takes ownership */ - wc_UnLockMutex(&cm->caLock); - if (cm->caCacheCallback) - cm->caCacheCallback(der->buffer, (int)der->length, type); - } - else { - WOLFSSL_MSG("\tCA Mutex Lock failed"); - ret = BAD_MUTEX_E; - } - } - - WOLFSSL_MSG("\tFreeing Parsed CA"); - FreeDecodedCert(cert); - if (ret != 0 && signer != NULL) - FreeSigner(signer, cm->heap); - WC_FREE_VAR_EX(cert, NULL, DYNAMIC_TYPE_DCERT); - WOLFSSL_MSG("\tFreeing der CA"); - FreeDer(pDer); - WOLFSSL_MSG("\t\tOK Freeing der CA"); - - WOLFSSL_LEAVE("AddCA", ret); - - return ret == 0 ? WOLFSSL_SUCCESS : ret; -} - -/* Removes the CA with the passed in subject hash from the - cert manager's CA cert store. */ -int RemoveCA(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type) -{ - Signer* current; - Signer** prev; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - word32 row; - - WOLFSSL_MSG("Removing a CA"); - - if (cm == NULL || hash == NULL) { - return BAD_FUNC_ARG; - } - - row = HashSigner(hash); - - if (wc_LockMutex(&cm->caLock) != 0) { - return BAD_MUTEX_E; - } - current = cm->caTable[row]; - prev = &cm->caTable[row]; - while (current) { - byte* subjectHash; - - #ifndef NO_SKID - subjectHash = current->subjectKeyIdHash; - #else - subjectHash = current->subjectNameHash; - #endif - - if ((current->type == type) && - (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0)) { - *prev = current->next; - FreeSigner(current, cm->heap); - ret = WOLFSSL_SUCCESS; - break; - } - prev = ¤t->next; - current = current->next; - } - wc_UnLockMutex(&cm->caLock); - - WOLFSSL_LEAVE("RemoveCA", ret); - - return ret; -} - - -/* Sets the CA with the passed in subject hash - to the provided type. */ -int SetCAType(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type) -{ - Signer* current; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - word32 row; - - WOLFSSL_MSG_EX("Setting CA to type %d", type); - - if (cm == NULL || hash == NULL || - type < WOLFSSL_USER_CA || type > WOLFSSL_USER_INTER) { - return ret; - } - - row = HashSigner(hash); - - if (wc_LockMutex(&cm->caLock) != 0) { - return ret; - } - current = cm->caTable[row]; - while (current) { - byte* subjectHash; - - #ifndef NO_SKID - subjectHash = current->subjectKeyIdHash; - #else - subjectHash = current->subjectNameHash; - #endif - - if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { - current->type = (byte)type; - ret = WOLFSSL_SUCCESS; - break; - } - current = current->next; - } - wc_UnLockMutex(&cm->caLock); - - WOLFSSL_LEAVE("SetCAType", ret); - - return ret; -} -#endif /* !NO_CERTS */ - - #if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) static int wolfSSL_RAND_InitMutex(void); #endif @@ -6862,2580 +5243,8 @@ void wolfSSL_set_security_level(WOLFSSL * ssl, int level) #define WOLFSSL_SSL_LOAD_INCLUDED #include -#ifndef NO_CERTS - -#ifdef HAVE_CRL - -int wolfSSL_CTX_LoadCRLBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, - long sz, int type) -{ - WOLFSSL_ENTER("wolfSSL_CTX_LoadCRLBuffer"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - return wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, buff, sz, type); -} - - -int wolfSSL_LoadCRLBuffer(WOLFSSL* ssl, const unsigned char* buff, - long sz, int type) -{ - WOLFSSL_ENTER("wolfSSL_LoadCRLBuffer"); - - if (ssl == NULL || ssl->ctx == NULL) - return BAD_FUNC_ARG; - - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerLoadCRLBuffer(SSL_CM(ssl), buff, sz, type); -} - -#endif /* HAVE_CRL */ - -#ifdef HAVE_OCSP -int wolfSSL_EnableOCSP(WOLFSSL* ssl, int options) -{ - WOLFSSL_ENTER("wolfSSL_EnableOCSP"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerEnableOCSP(SSL_CM(ssl), options); - } - else - return BAD_FUNC_ARG; -} - -int wolfSSL_DisableOCSP(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_DisableOCSP"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerDisableOCSP(SSL_CM(ssl)); - } - else - return BAD_FUNC_ARG; -} - - -int wolfSSL_EnableOCSPStapling(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_EnableOCSPStapling"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerEnableOCSPStapling(SSL_CM(ssl)); - } - else - return BAD_FUNC_ARG; -} - -int wolfSSL_DisableOCSPStapling(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_DisableOCSPStapling"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerDisableOCSPStapling(SSL_CM(ssl)); - } - else - return BAD_FUNC_ARG; -} - -int wolfSSL_SetOCSP_OverrideURL(WOLFSSL* ssl, const char* url) -{ - WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerSetOCSPOverrideURL(SSL_CM(ssl), url); - } - else - return BAD_FUNC_ARG; -} - - -int wolfSSL_SetOCSP_Cb(WOLFSSL* ssl, - CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx) -{ - WOLFSSL_ENTER("wolfSSL_SetOCSP_Cb"); - if (ssl) { - SSL_CM_WARNING(ssl); - ssl->ocspIOCtx = ioCbCtx; /* use SSL specific ioCbCtx */ - return wolfSSL_CertManagerSetOCSP_Cb(SSL_CM(ssl), - ioCb, respFreeCb, NULL); - } - else - return BAD_FUNC_ARG; -} - -int wolfSSL_CTX_EnableOCSP(WOLFSSL_CTX* ctx, int options) -{ - WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSP"); - if (ctx) - return wolfSSL_CertManagerEnableOCSP(ctx->cm, options); - else - return BAD_FUNC_ARG; -} - - -int wolfSSL_CTX_DisableOCSP(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSP"); - if (ctx) - return wolfSSL_CertManagerDisableOCSP(ctx->cm); - else - return BAD_FUNC_ARG; -} - - -int wolfSSL_CTX_SetOCSP_OverrideURL(WOLFSSL_CTX* ctx, const char* url) -{ - WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); - if (ctx) - return wolfSSL_CertManagerSetOCSPOverrideURL(ctx->cm, url); - else - return BAD_FUNC_ARG; -} - - -int wolfSSL_CTX_SetOCSP_Cb(WOLFSSL_CTX* ctx, CbOCSPIO ioCb, - CbOCSPRespFree respFreeCb, void* ioCbCtx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetOCSP_Cb"); - if (ctx) - return wolfSSL_CertManagerSetOCSP_Cb(ctx->cm, ioCb, - respFreeCb, ioCbCtx); - else - return BAD_FUNC_ARG; -} - -#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) -int wolfSSL_CTX_EnableOCSPStapling(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPStapling"); - if (ctx) - return wolfSSL_CertManagerEnableOCSPStapling(ctx->cm); - else - return BAD_FUNC_ARG; -} - -int wolfSSL_CTX_DisableOCSPStapling(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPStapling"); - if (ctx) - return wolfSSL_CertManagerDisableOCSPStapling(ctx->cm); - else - return BAD_FUNC_ARG; -} - -int wolfSSL_CTX_EnableOCSPMustStaple(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPMustStaple"); - if (ctx) - return wolfSSL_CertManagerEnableOCSPMustStaple(ctx->cm); - else - return BAD_FUNC_ARG; -} - -int wolfSSL_CTX_DisableOCSPMustStaple(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPMustStaple"); - if (ctx) - return wolfSSL_CertManagerDisableOCSPMustStaple(ctx->cm); - else - return BAD_FUNC_ARG; -} -#endif /* HAVE_CERTIFICATE_STATUS_REQUEST || \ - * HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ - -#endif /* HAVE_OCSP */ - -#ifdef HAVE_CRL - -int wolfSSL_EnableCRL(WOLFSSL* ssl, int options) -{ - WOLFSSL_ENTER("wolfSSL_EnableCRL"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerEnableCRL(SSL_CM(ssl), options); - } - else - return BAD_FUNC_ARG; -} - - -int wolfSSL_DisableCRL(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_DisableCRL"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerDisableCRL(SSL_CM(ssl)); - } - else - return BAD_FUNC_ARG; -} - -#ifndef NO_FILESYSTEM -int wolfSSL_LoadCRL(WOLFSSL* ssl, const char* path, int type, int monitor) -{ - WOLFSSL_ENTER("wolfSSL_LoadCRL"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerLoadCRL(SSL_CM(ssl), path, type, monitor); - } - else - return BAD_FUNC_ARG; -} - -int wolfSSL_LoadCRLFile(WOLFSSL* ssl, const char* file, int type) -{ - WOLFSSL_ENTER("wolfSSL_LoadCRLFile"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerLoadCRLFile(SSL_CM(ssl), file, type); - } - else - return BAD_FUNC_ARG; -} -#endif - -int wolfSSL_SetCRL_Cb(WOLFSSL* ssl, CbMissingCRL cb) -{ - WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerSetCRL_Cb(SSL_CM(ssl), cb); - } - else - return BAD_FUNC_ARG; -} - -int wolfSSL_SetCRL_ErrorCb(WOLFSSL* ssl, crlErrorCb cb, void* ctx) -{ - WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerSetCRL_ErrorCb(SSL_CM(ssl), cb, ctx); - } - else - return BAD_FUNC_ARG; -} - -#ifdef HAVE_CRL_IO -int wolfSSL_SetCRL_IOCb(WOLFSSL* ssl, CbCrlIO cb) -{ - WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerSetCRL_IOCb(SSL_CM(ssl), cb); - } - else - return BAD_FUNC_ARG; -} -#endif - -int wolfSSL_CTX_EnableCRL(WOLFSSL_CTX* ctx, int options) -{ - WOLFSSL_ENTER("wolfSSL_CTX_EnableCRL"); - if (ctx) - return wolfSSL_CertManagerEnableCRL(ctx->cm, options); - else - return BAD_FUNC_ARG; -} - - -int wolfSSL_CTX_DisableCRL(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_DisableCRL"); - if (ctx) - return wolfSSL_CertManagerDisableCRL(ctx->cm); - else - return BAD_FUNC_ARG; -} - - -#ifndef NO_FILESYSTEM -int wolfSSL_CTX_LoadCRL(WOLFSSL_CTX* ctx, const char* path, - int type, int monitor) -{ - WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); - if (ctx) - return wolfSSL_CertManagerLoadCRL(ctx->cm, path, type, monitor); - else - return BAD_FUNC_ARG; -} - -int wolfSSL_CTX_LoadCRLFile(WOLFSSL_CTX* ctx, const char* file, - int type) -{ - WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); - if (ctx) - return wolfSSL_CertManagerLoadCRLFile(ctx->cm, file, type); - else - return BAD_FUNC_ARG; -} -#endif - - -int wolfSSL_CTX_SetCRL_Cb(WOLFSSL_CTX* ctx, CbMissingCRL cb) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_Cb"); - if (ctx) - return wolfSSL_CertManagerSetCRL_Cb(ctx->cm, cb); - else - return BAD_FUNC_ARG; -} - -int wolfSSL_CTX_SetCRL_ErrorCb(WOLFSSL_CTX* ctx, crlErrorCb cb, void* cbCtx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_ErrorCb"); - if (ctx) - return wolfSSL_CertManagerSetCRL_ErrorCb(ctx->cm, cb, cbCtx); - else - return BAD_FUNC_ARG; -} - -#ifdef HAVE_CRL_IO -int wolfSSL_CTX_SetCRL_IOCb(WOLFSSL_CTX* ctx, CbCrlIO cb) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_IOCb"); - if (ctx) - return wolfSSL_CertManagerSetCRL_IOCb(ctx->cm, cb); - else - return BAD_FUNC_ARG; -} -#endif - - -#endif /* HAVE_CRL */ - - -/* Sets the max chain depth when verifying a certificate chain. Default depth - * is set to MAX_CHAIN_DEPTH. - * - * ctx WOLFSSL_CTX structure to set depth in - * depth max depth - */ -void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) { - WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth"); - - if (ctx == NULL || depth < 0 || depth > MAX_CHAIN_DEPTH) { - WOLFSSL_MSG("Bad depth argument, too large or less than 0"); - return; - } - - ctx->verifyDepth = (byte)depth; -} - - -/* get cert chaining depth using ssl struct */ -long wolfSSL_get_verify_depth(WOLFSSL* ssl) -{ - if(ssl == NULL) { - return BAD_FUNC_ARG; - } -#ifndef OPENSSL_EXTRA - return MAX_CHAIN_DEPTH; -#else - return ssl->options.verifyDepth; -#endif -} - - -/* get cert chaining depth using ctx struct */ -long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) { - return BAD_FUNC_ARG; - } -#ifndef OPENSSL_EXTRA - return MAX_CHAIN_DEPTH; -#else - return ctx->verifyDepth; -#endif -} - -#ifndef NO_CHECK_PRIVATE_KEY - -#ifdef WOLF_PRIVATE_KEY_ID -/* Check private against public in certificate for match using external - * device with given devId */ -static int check_cert_key_dev(word32 keyOID, byte* privKey, word32 privSz, - const byte* pubKey, word32 pubSz, int label, int id, void* heap, int devId) -{ - int ret = 0; - int type = 0; - void *pkey = NULL; - - if (privKey == NULL) { - return MISSING_KEY; - } - -#ifndef NO_RSA - if (keyOID == RSAk) { - type = DYNAMIC_TYPE_RSA; - } -#ifdef WC_RSA_PSS - if (keyOID == RSAPSSk) { - type = DYNAMIC_TYPE_RSA; - } -#endif -#endif -#ifdef HAVE_ECC - if (keyOID == ECDSAk) { - type = DYNAMIC_TYPE_ECC; - } -#endif -#if defined(HAVE_DILITHIUM) - if ((keyOID == ML_DSA_LEVEL2k) || - (keyOID == ML_DSA_LEVEL3k) || - (keyOID == ML_DSA_LEVEL5k) - #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT - || (keyOID == DILITHIUM_LEVEL2k) - || (keyOID == DILITHIUM_LEVEL3k) - || (keyOID == DILITHIUM_LEVEL5k) - #endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */ - ) { - type = DYNAMIC_TYPE_DILITHIUM; - } -#endif -#if defined(HAVE_FALCON) - if ((keyOID == FALCON_LEVEL1k) || - (keyOID == FALCON_LEVEL5k)) { - type = DYNAMIC_TYPE_FALCON; - } -#endif - - ret = CreateDevPrivateKey(&pkey, privKey, privSz, type, label, id, - heap, devId); - #ifdef WOLF_CRYPTO_CB - if (ret == 0) { - #ifndef NO_RSA - if (keyOID == RSAk - #ifdef WC_RSA_PSS - || keyOID == RSAPSSk - #endif - ) { - ret = wc_CryptoCb_RsaCheckPrivKey((RsaKey*)pkey, pubKey, pubSz); - } - #endif - #ifdef HAVE_ECC - if (keyOID == ECDSAk) { - ret = wc_CryptoCb_EccCheckPrivKey((ecc_key*)pkey, pubKey, pubSz); - } - #endif - #if defined(HAVE_DILITHIUM) - if ((keyOID == ML_DSA_LEVEL2k) || - (keyOID == ML_DSA_LEVEL3k) || - (keyOID == ML_DSA_LEVEL5k) - #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT - || (keyOID == DILITHIUM_LEVEL2k) - || (keyOID == DILITHIUM_LEVEL3k) - || (keyOID == DILITHIUM_LEVEL5k) - #endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */ - ) { - ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, - WC_PQC_SIG_TYPE_DILITHIUM, - pubKey, pubSz); - } - #endif - #if defined(HAVE_FALCON) - if ((keyOID == FALCON_LEVEL1k) || - (keyOID == FALCON_LEVEL5k)) { - ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, - WC_PQC_SIG_TYPE_FALCON, - pubKey, pubSz); - } - #endif - } - #else - /* devId was set, don't check, for now */ - /* TODO: Add callback for private key check? */ - (void) pubKey; - (void) pubSz; - #endif - if (pkey != NULL) { - #ifndef NO_RSA - if (keyOID == RSAk - #ifdef WC_RSA_PSS - || keyOID == RSAPSSk - #endif - ) { - wc_FreeRsaKey((RsaKey*)pkey); - } - #endif - #ifdef HAVE_ECC - if (keyOID == ECDSAk) { - wc_ecc_free((ecc_key*)pkey); - } - #endif - #if defined(HAVE_DILITHIUM) - if ((keyOID == ML_DSA_LEVEL2k) || - (keyOID == ML_DSA_LEVEL3k) || - (keyOID == ML_DSA_LEVEL5k) - #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT - || (keyOID == DILITHIUM_LEVEL2k) - || (keyOID == DILITHIUM_LEVEL3k) - || (keyOID == DILITHIUM_LEVEL5k) - #endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */ - ) { - wc_dilithium_free((dilithium_key*)pkey); - } - #endif - #if defined(HAVE_FALCON) - if ((keyOID == FALCON_LEVEL1k) || - (keyOID == FALCON_LEVEL5k)) { - wc_falcon_free((falcon_key*)pkey); - } - #endif - XFREE(pkey, heap, type); - } - - return ret; -} -#endif /* WOLF_PRIVATE_KEY_ID */ - -/* Check private against public in certificate for match - * - * Returns WOLFSSL_SUCCESS on good private key - * WOLFSSL_FAILURE if mismatched */ -static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, - const DerBuffer* altKey, void* heap, int devId, int isKeyLabel, int isKeyId, - int altDevId, int isAltKeyLabel, int isAltKeyId) -{ - WC_DECLARE_VAR(der, DecodedCert, 1, 0); - word32 size; - byte* buff; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - - WOLFSSL_ENTER("check_cert_key"); - - if (cert == NULL || key == NULL) { - return WOLFSSL_FAILURE; - } - - WC_ALLOC_VAR_EX(der, DecodedCert, 1, heap, DYNAMIC_TYPE_DCERT, - return MEMORY_E); - - size = cert->length; - buff = cert->buffer; - InitDecodedCert_ex(der, buff, size, heap, devId); - if (ParseCertRelative(der, CERT_TYPE, NO_VERIFY, NULL, NULL) != 0) { - FreeDecodedCert(der); - WC_FREE_VAR_EX(der, heap, DYNAMIC_TYPE_DCERT); - return WOLFSSL_FAILURE; - } - - size = key->length; - buff = key->buffer; -#ifdef WOLF_PRIVATE_KEY_ID - if (devId != INVALID_DEVID) { - ret = check_cert_key_dev(der->keyOID, buff, size, der->publicKey, - der->pubKeySize, isKeyLabel, isKeyId, heap, - devId); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { - ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; - } - } - else { - /* fall through if unavailable */ - ret = CRYPTOCB_UNAVAILABLE; - } - - if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) -#endif /* WOLF_PRIVATE_KEY_ID */ - { - ret = wc_CheckPrivateKeyCert(buff, size, der, 0, heap); - ret = (ret == 1) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; - } - -#ifdef WOLFSSL_DUAL_ALG_CERTS - if (ret == WOLFSSL_SUCCESS && der->extSapkiSet && der->sapkiDer != NULL) { - /* Certificate contains an alternative public key. Hence, we also - * need an alternative private key. */ - if (altKey == NULL) { - ret = MISSING_KEY; - buff = NULL; - size = 0; - } - else { - size = altKey->length; - buff = altKey->buffer; - } -#ifdef WOLF_PRIVATE_KEY_ID - if (ret == WOLFSSL_SUCCESS && altDevId != INVALID_DEVID) { - /* We have to decode the public key first */ - /* Default to max pub key size. */ - word32 pubKeyLen = MAX_PUBLIC_KEY_SZ; - byte* decodedPubKey = (byte*)XMALLOC(pubKeyLen, heap, - DYNAMIC_TYPE_PUBLIC_KEY); - if (decodedPubKey == NULL) { - ret = MEMORY_E; - } - if (ret == WOLFSSL_SUCCESS) { - if (der->sapkiOID == RSAk || der->sapkiOID == ECDSAk) { - /* Simply copy the data */ - XMEMCPY(decodedPubKey, der->sapkiDer, der->sapkiLen); - pubKeyLen = der->sapkiLen; - ret = 0; - } - else { - #if defined(WC_ENABLE_ASYM_KEY_IMPORT) - word32 idx = 0; - ret = DecodeAsymKeyPublic(der->sapkiDer, &idx, - der->sapkiLen, decodedPubKey, - &pubKeyLen, der->sapkiOID); - #else - ret = NOT_COMPILED_IN; - #endif /* WC_ENABLE_ASYM_KEY_IMPORT */ - } - } - if (ret == 0) { - ret = check_cert_key_dev(der->sapkiOID, buff, size, - decodedPubKey, pubKeyLen, - isAltKeyLabel, isAltKeyId, - heap, altDevId); - } - XFREE(decodedPubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { - ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; - } - } - else { - /* fall through if unavailable */ - ret = CRYPTOCB_UNAVAILABLE; - } - - if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) -#else - if (ret == WOLFSSL_SUCCESS) -#endif /* WOLF_PRIVATE_KEY_ID */ - { - ret = wc_CheckPrivateKeyCert(buff, size, der, 1, heap); - ret = (ret == 1) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; - } - } -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - FreeDecodedCert(der); - WC_FREE_VAR_EX(der, heap, DYNAMIC_TYPE_DCERT); - - (void)devId; - (void)isKeyLabel; - (void)isKeyId; - (void)altKey; - (void)altDevId; - (void)isAltKeyLabel; - (void)isAltKeyId; - - return ret; -} - -/* Check private against public in certificate for match - * - * ctx WOLFSSL_CTX structure to check private key in - * - * Returns WOLFSSL_SUCCESS on good private key - * WOLFSSL_FAILURE if mismatched. */ -int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx) -{ - int res = WOLFSSL_SUCCESS; -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - DerBuffer *privateKey; -#ifdef WOLFSSL_DUAL_ALG_CERTS - DerBuffer *altPrivateKey; -#endif -#else - const DerBuffer *privateKey; -#ifdef WOLFSSL_DUAL_ALG_CERTS - const DerBuffer *altPrivateKey; -#endif -#endif - - if (ctx == NULL) { - return WOLFSSL_FAILURE; - } - -#ifdef WOLFSSL_DUAL_ALG_CERTS -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - privateKey = wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask); - if (privateKey == NULL) { - res = WOLFSSL_FAILURE; - } - if (ctx->altPrivateKey != NULL) { - altPrivateKey = wolfssl_priv_der_unblind(ctx->altPrivateKey, - ctx->altPrivateKeyMask); - if (altPrivateKey == NULL) { - res = WOLFSSL_FAILURE; - } - } - else { - altPrivateKey = NULL; - } -#else - privateKey = ctx->privateKey; - altPrivateKey = ctx->altPrivateKey; -#endif - if (res == WOLFSSL_SUCCESS) { - res = check_cert_key(ctx->certificate, privateKey, altPrivateKey, - ctx->heap, ctx->privateKeyDevId, ctx->privateKeyLabel, - ctx->privateKeyId, ctx->altPrivateKeyDevId, - ctx->altPrivateKeyLabel, ctx->altPrivateKeyId) != 0; - } -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(privateKey); - wolfssl_priv_der_unblind_free(altPrivateKey); -#endif -#else -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - privateKey = wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask); - if (privateKey == NULL) { - res = WOLFSSL_FAILURE; - } -#else - privateKey = ctx->privateKey; -#endif - if (res == WOLFSSL_SUCCESS) { - res = check_cert_key(ctx->certificate, privateKey, NULL, ctx->heap, - ctx->privateKeyDevId, ctx->privateKeyLabel, - ctx->privateKeyId, INVALID_DEVID, 0, 0); - } -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(privateKey); -#endif -#endif - - /* placing error into error queue for Python port */ - if (res != WOLFSSL_SUCCESS) { - WOLFSSL_ERROR(WC_KEY_MISMATCH_E); - } - - return res; -} -#endif /* !NO_CHECK_PRIVATE_KEY */ - -#ifdef OPENSSL_ALL -/** - * Return the private key of the WOLFSSL_CTX struct - * @return WOLFSSL_EVP_PKEY* The caller doesn *NOT*` free the returned object. - * - * Note, even though the supplied ctx pointer is designated const, on success - * ctx->privateKeyPKey is changed by this call. The change is done safely using - * a hardware-synchronized store. - */ -WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(const WOLFSSL_CTX* ctx) -{ - WOLFSSL_EVP_PKEY* res; - const unsigned char *key; - int type; - - WOLFSSL_ENTER("wolfSSL_CTX_get0_privatekey"); - - if (ctx == NULL || ctx->privateKey == NULL || - ctx->privateKey->buffer == NULL) { - WOLFSSL_MSG("Bad parameter or key not set"); - return NULL; - } - - switch (ctx->privateKeyType) { -#ifndef NO_RSA - case rsa_sa_algo: - type = WC_EVP_PKEY_RSA; - break; -#endif -#ifdef HAVE_ECC - case ecc_dsa_sa_algo: - type = WC_EVP_PKEY_EC; - break; -#endif -#ifdef WOLFSSL_SM2 - case sm2_sa_algo: - type = WC_EVP_PKEY_EC; - break; -#endif - default: - /* Other key types not supported either as ssl private keys - * or in the EVP layer */ - WOLFSSL_MSG("Unsupported key type"); - return NULL; - } - - if (ctx->privateKeyPKey != NULL) { - res = ctx->privateKeyPKey; - } - else { - #ifdef WOLFSSL_BLIND_PRIVATE_KEY - DerBuffer *unblinded_privateKey = - wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask); - if (unblinded_privateKey == NULL) - return NULL; - key = unblinded_privateKey->buffer; - #else - key = ctx->privateKey->buffer; - #endif - res = wolfSSL_d2i_PrivateKey(type, NULL, &key, - (long)ctx->privateKey->length); - #ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(unblinded_privateKey); - #endif - if (res) { -#ifdef WOLFSSL_ATOMIC_OPS - WOLFSSL_EVP_PKEY *current_pkey = NULL; - if (! wolfSSL_Atomic_Ptr_CompareExchange( - (void * volatile *)&ctx->privateKeyPKey, - (void **)¤t_pkey, res)) - { - wolfSSL_EVP_PKEY_free(res); - res = current_pkey; - } -#else - ((WOLFSSL_CTX *)ctx)->privateKeyPKey = res; -#endif - } - } - - return res; -} -#endif - -#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) { - WC_FREE_VAR_EX(rsa, NULL, DYNAMIC_TYPE_RSA); - 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); - WC_FREE_VAR_EX(rsa, NULL, DYNAMIC_TYPE_RSA); - - if (!isRsaKey) { - return WOLFSSL_FATAL_ERROR; - } - - 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 = (int)keyIdx; - pkey->pkey.ptr = (char*)XMALLOC((size_t)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 = WC_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) { - WC_FREE_VAR_EX(ecc, NULL, DYNAMIC_TYPE_ECC); - 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); - WC_FREE_VAR_EX(ecc, NULL, DYNAMIC_TYPE_ECC); - - if (!isEccKey) { - return WOLFSSL_FATAL_ERROR; - } - - 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 = (int)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 = WC_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) { - WC_FREE_VAR_EX(dsa, NULL, DYNAMIC_TYPE_DSA); - 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); - WC_FREE_VAR_EX(dsa, NULL, DYNAMIC_TYPE_DSA); - - /* test if DSA key */ - if (!isDsaKey) { - return WOLFSSL_FATAL_ERROR; - } - - 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 = (int)keyIdx; - pkey->pkey.ptr = (char*)XMALLOC((size_t)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 = WC_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) { - WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); - return 0; - } - - isDhKey = (wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz) == 0); - wc_FreeDhKey(dh); - WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); - - /* test if DH key */ - if (!isDhKey) { - return WOLFSSL_FATAL_ERROR; - } - - 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((size_t)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, (size_t)memSz); - pkey->type = WC_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) { - WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); - return 0; - } - - ret = wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz); - wc_FreeDhKey(dh); - WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); - - if (ret != 0) { - return WOLFSSL_FATAL_ERROR; - } - - if (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - return 0; - } - } - - ret = 1; - pkey->type = WC_EVP_PKEY_DH; - pkey->pkey_sz = (int)memSz; - pkey->pkey.ptr = (char*)XMALLOC((size_t)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, (size_t)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_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) { - WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON); - 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); - WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON); - - if (!isFalcon) { - return WOLFSSL_FATAL_ERROR; - } - - 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 = WC_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) { - WC_FREE_VAR_EX(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); - return 0; - } - - /* Test if Dilithium key. Try all levels. */ - if (priv) { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_44) == 0) && - (wc_dilithium_import_private(mem, - (word32)memSz, dilithium) == 0)); - if (!isDilithium) { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_65) == 0) && - (wc_dilithium_import_private(mem, - (word32)memSz, dilithium) == 0)); - } - if (!isDilithium) { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_87) == 0) && - (wc_dilithium_import_private(mem, - (word32)memSz, dilithium) == 0)); - } - } - else { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_44) == 0) && - (wc_dilithium_import_public(mem, (word32)memSz, - dilithium) == 0)); - if (!isDilithium) { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_65) == 0) && - (wc_dilithium_import_public(mem, (word32)memSz, - dilithium) == 0)); - } - if (!isDilithium) { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_87) == 0) && - (wc_dilithium_import_public(mem, (word32)memSz, - dilithium) == 0)); - } - } - wc_dilithium_free(dilithium); - WC_FREE_VAR_EX(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); - - if (!isDilithium) { - return WOLFSSL_FATAL_ERROR; - } - - 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 = WC_EVP_PKEY_DILITHIUM; - pkey->pkey.ptr = NULL; - pkey->pkey_sz = 0; - - *out = pkey; - return 1; -} -#endif /* HAVE_DILITHIUM */ - -static WOLFSSL_EVP_PKEY* d2iGenericKey(WOLFSSL_EVP_PKEY** out, - const unsigned char** in, long inSz, int priv) -{ - WOLFSSL_EVP_PKEY* pkey = NULL; - - WOLFSSL_ENTER("d2iGenericKey"); - - if (in == NULL || *in == NULL || inSz < 0) { - WOLFSSL_MSG("Bad argument"); - return NULL; - } - - if ((out != NULL) && (*out != NULL)) { - pkey = *out; - } - -#if !defined(NO_RSA) - if (d2iTryRsaKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* NO_RSA */ -#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) - if (d2iTryEccKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - 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(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION > 2)) - if (d2iTryAltDhKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ -#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ - -#ifdef HAVE_FALCON - if (d2iTryFalconKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* HAVE_FALCON */ -#ifdef HAVE_DILITHIUM - if (d2iTryDilithiumKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* HAVE_DILITHIUM */ - { - 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* pkcs8 = NULL; -#ifdef WOLFSSL_PEM_TO_DER - int ret; - DerBuffer* pkcs8Der = NULL; - DerBuffer rawDer; - EncryptedInfo info; - int advanceLen = 0; - - XMEMSET(&info, 0, sizeof(info)); - XMEMSET(&rawDer, 0, sizeof(rawDer)); - - if (keyBuf == NULL || *keyBuf == NULL || keyLen <= 0) { - WOLFSSL_MSG("Bad key PEM/DER args"); - return NULL; - } - - ret = PemToDer(*keyBuf, keyLen, PRIVATEKEY_TYPE, &pkcs8Der, NULL, &info, - NULL); - if (ret < 0) { - WOLFSSL_MSG("Not PEM format"); - ret = AllocDer(&pkcs8Der, (word32)keyLen, PRIVATEKEY_TYPE, NULL); - if (ret == 0) { - XMEMCPY(pkcs8Der->buffer, *keyBuf, keyLen); - } - } - else { - advanceLen = (int)info.consumed; - } - - if (ret == 0) { - /* Verify this is PKCS8 Key */ - word32 inOutIdx = 0; - word32 algId; - ret = ToTraditionalInline_ex(pkcs8Der->buffer, &inOutIdx, - pkcs8Der->length, &algId); - if (ret >= 0) { - if (advanceLen == 0) /* Set only if not PEM */ - advanceLen = (int)inOutIdx + ret; - if (algId == DHk) { - /* Special case for DH as we expect the DER buffer to be always - * be in PKCS8 format */ - rawDer.buffer = pkcs8Der->buffer; - rawDer.length = inOutIdx + (word32)ret; - } - else { - rawDer.buffer = pkcs8Der->buffer + inOutIdx; - rawDer.length = (word32)ret; - } - ret = 0; /* good DER */ - } - } - - if (ret == 0) { - pkcs8 = wolfSSL_EVP_PKEY_new(); - if (pkcs8 == NULL) - ret = MEMORY_E; - } - if (ret == 0) { - pkcs8->pkey.ptr = (char*)XMALLOC(rawDer.length, NULL, - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkcs8->pkey.ptr == NULL) - ret = MEMORY_E; - } - if (ret == 0) { - XMEMCPY(pkcs8->pkey.ptr, rawDer.buffer, rawDer.length); - pkcs8->pkey_sz = (int)rawDer.length; - } - - FreeDer(&pkcs8Der); - if (ret != 0) { - wolfSSL_EVP_PKEY_free(pkcs8); - pkcs8 = NULL; - } - else { - *keyBuf += advanceLen; - } - if (pkey != NULL) { - *pkey = pkcs8; - } - -#else - (void)bio; - (void)pkey; -#endif /* WOLFSSL_PEM_TO_DER */ - - return pkcs8; -} - -#ifdef OPENSSL_ALL -int wolfSSL_i2d_PKCS8_PKEY(WOLFSSL_PKCS8_PRIV_KEY_INFO* key, unsigned char** pp) -{ - word32 keySz = 0; - unsigned char* out; - int len; - - WOLFSSL_ENTER("wolfSSL_i2d_PKCS8_PKEY"); - - if (key == NULL) - return WOLFSSL_FATAL_ERROR; - - if (pkcs8_encode(key, NULL, &keySz) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) - return WOLFSSL_FATAL_ERROR; - len = (int)keySz; - - if ((pp == NULL) || (len == 0)) - return len; - - if (*pp == NULL) { - out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1); - if (out == NULL) - return WOLFSSL_FATAL_ERROR; - } - else { - out = *pp; - } - - if (pkcs8_encode(key, out, &keySz) != len) { - if (*pp == NULL) - XFREE(out, NULL, DYNAMIC_TYPE_ASN1); - return WOLFSSL_FATAL_ERROR; - } - - if (*pp == NULL) - *pp = out; - else - *pp += len; - - return len; -} -#endif - -#ifndef NO_BIO -/* put SSL type in extra for now, not very common */ - -/* Converts a DER format key read from "bio" to a PKCS8 structure. - * - * bio input bio to read DER from - * pkey If not NULL then this pointer will be overwritten with a new PKCS8 - * structure. - * - * returns a WOLFSSL_PKCS8_PRIV_KEY_INFO pointer on success and NULL in fail - * case. - */ -WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY_bio(WOLFSSL_BIO* bio, - WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey) -{ - WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL; -#ifdef WOLFSSL_PEM_TO_DER - unsigned char* mem = NULL; - int memSz; - - WOLFSSL_ENTER("wolfSSL_d2i_PKCS8_PKEY_bio"); - - if (bio == NULL) { - return NULL; - } - - if ((memSz = wolfSSL_BIO_get_mem_data(bio, &mem)) < 0) { - return NULL; - } - - pkcs8 = wolfSSL_d2i_PKCS8_PKEY(pkey, (const unsigned char**)&mem, memSz); -#else - (void)bio; - (void)pkey; -#endif /* WOLFSSL_PEM_TO_DER */ - - return pkcs8; -} - - -/* expecting DER format public key - * - * bio input bio to read DER from - * out If not NULL then this pointer will be overwritten with a new - * WOLFSSL_EVP_PKEY pointer - * - * returns a WOLFSSL_EVP_PKEY pointer on success and NULL in fail case. - */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY_bio(WOLFSSL_BIO* bio, - WOLFSSL_EVP_PKEY** out) -{ - unsigned char* mem; - long memSz; - WOLFSSL_EVP_PKEY* pkey = NULL; - - WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY_bio"); - - if (bio == NULL) { - return NULL; - } - (void)out; - - memSz = wolfSSL_BIO_get_len(bio); - if (memSz <= 0) { - return NULL; - } - - mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (mem == NULL) { - return NULL; - } - - if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) { - pkey = wolfSSL_d2i_PUBKEY(NULL, (const unsigned char**)&mem, memSz); - if (out != NULL && pkey != NULL) { - *out = pkey; - } - } - - XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - return pkey; -} - -#endif /* !NO_BIO */ - - -/* Converts a DER encoded public key to a WOLFSSL_EVP_PKEY structure. - * - * out pointer to new WOLFSSL_EVP_PKEY structure. Can be NULL - * in DER buffer to convert - * inSz size of in buffer - * - * returns a pointer to a new WOLFSSL_EVP_PKEY structure on success and NULL - * on fail - */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** out, - const unsigned char** in, long inSz) -{ - WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY"); - return d2iGenericKey(out, in, inSz, 0); -} - -#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_ASN) && \ - !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) -{ - int sz; - word16 pkcs8HeaderSz; - - if (!key || !key->pkey_sz) - return WOLFSSL_FATAL_ERROR; - - /* return the key without PKCS8 for compatibility */ - /* if pkcs8HeaderSz is invalid, use 0 and return all of pkey */ - pkcs8HeaderSz = 0; - if (key->pkey_sz > key->pkcs8HeaderSz) - pkcs8HeaderSz = key->pkcs8HeaderSz; - sz = key->pkey_sz - pkcs8HeaderSz; - if (der) { - unsigned char* pt = (unsigned char*)key->pkey.ptr; - if (*der) { - /* since this function signature has no size value passed in it is - * assumed that the user has allocated a large enough buffer */ - XMEMCPY(*der, pt + pkcs8HeaderSz, (size_t)sz); - *der += sz; - } - else { - *der = (unsigned char*)XMALLOC((size_t)sz, NULL, - DYNAMIC_TYPE_OPENSSL); - if (*der == NULL) { - return WOLFSSL_FATAL_ERROR; - } - XMEMCPY(*der, pt + pkcs8HeaderSz, (size_t)sz); - } - } - return sz; -} - -int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der) -{ - return wolfSSL_i2d_PublicKey(key, der); -} - -#endif /* OPENSSL_EXTRA && !NO_CERTS && !NO_ASN && !NO_PWDBASED */ - -static WOLFSSL_EVP_PKEY* _d2i_PublicKey(int type, WOLFSSL_EVP_PKEY** out, - const unsigned char **in, long inSz, int priv) -{ - int ret = 0; - word32 idx = 0, algId; - word16 pkcs8HeaderSz = 0; - WOLFSSL_EVP_PKEY* local; - int opt = 0; - - (void)opt; - - if (in == NULL || inSz < 0) { - WOLFSSL_MSG("Bad argument"); - return NULL; - } - - if (priv == 1) { - /* Check if input buffer has PKCS8 header. In the case that it does not - * have a PKCS8 header then do not error out. */ - if ((ret = ToTraditionalInline_ex((const byte*)(*in), &idx, - (word32)inSz, &algId)) > 0) { - WOLFSSL_MSG("Found PKCS8 header"); - pkcs8HeaderSz = (word16)idx; - - if ((type == WC_EVP_PKEY_RSA && algId != RSAk - #ifdef WC_RSA_PSS - && algId != RSAPSSk - #endif - ) || - (type == WC_EVP_PKEY_EC && algId != ECDSAk) || - (type == WC_EVP_PKEY_DSA && algId != DSAk) || - (type == WC_EVP_PKEY_DH && algId != DHk)) { - WOLFSSL_MSG("PKCS8 does not match EVP key type"); - return NULL; - } - - (void)idx; /* not used */ - } - else { - if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) { - WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 " - "header"); - return NULL; - } - } - } - - if (out != NULL && *out != NULL) { - wolfSSL_EVP_PKEY_free(*out); - *out = NULL; - } - local = wolfSSL_EVP_PKEY_new(); - if (local == NULL) { - return NULL; - } - - local->type = type; - local->pkey_sz = (int)inSz; - local->pkcs8HeaderSz = pkcs8HeaderSz; - local->pkey.ptr = (char*)XMALLOC((size_t)inSz, NULL, - DYNAMIC_TYPE_PUBLIC_KEY); - if (local->pkey.ptr == NULL) { - wolfSSL_EVP_PKEY_free(local); - local = NULL; - return NULL; - } - else { - XMEMCPY(local->pkey.ptr, *in, (size_t)inSz); - } - - switch (type) { -#ifndef NO_RSA - case WC_EVP_PKEY_RSA: - opt = priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC; - local->ownRsa = 1; - local->rsa = wolfssl_rsa_d2i(NULL, - (const unsigned char*)local->pkey.ptr, local->pkey_sz, opt); - if (local->rsa == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - break; -#endif /* NO_RSA */ -#ifdef HAVE_ECC - case WC_EVP_PKEY_EC: - local->ownEcc = 1; - local->ecc = wolfSSL_EC_KEY_new(); - if (local->ecc == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - opt = priv ? WOLFSSL_EC_KEY_LOAD_PRIVATE : - WOLFSSL_EC_KEY_LOAD_PUBLIC; - if (wolfSSL_EC_KEY_LoadDer_ex(local->ecc, - (const unsigned char*)local->pkey.ptr, local->pkey_sz, - opt) - != WOLFSSL_SUCCESS) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - break; -#endif /* HAVE_ECC */ -#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) -#ifndef NO_DSA - case WC_EVP_PKEY_DSA: - local->ownDsa = 1; - local->dsa = wolfSSL_DSA_new(); - if (local->dsa == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - opt = priv ? WOLFSSL_DSA_LOAD_PRIVATE : WOLFSSL_DSA_LOAD_PUBLIC; - if (wolfSSL_DSA_LoadDer_ex(local->dsa, - (const unsigned char*)local->pkey.ptr, local->pkey_sz, - opt) - != WOLFSSL_SUCCESS) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - break; -#endif /* NO_DSA */ -#ifndef NO_DH -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - case WC_EVP_PKEY_DH: - local->ownDh = 1; - local->dh = wolfSSL_DH_new(); - if (local->dh == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - if (wolfSSL_DH_LoadDer(local->dh, - (const unsigned char*)local->pkey.ptr, local->pkey_sz) - != WOLFSSL_SUCCESS) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - break; -#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ -#endif /* HAVE_DH */ -#endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */ - default: - WOLFSSL_MSG("Unsupported key type"); - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - - /* advance pointer with success */ - if (local != NULL) { - if (local->pkey_sz <= (int)inSz) { - *in += local->pkey_sz; - } - - if (out != NULL) { - *out = local; - } - } - - return local; -} - -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PublicKey(int type, WOLFSSL_EVP_PKEY** out, - const unsigned char **in, long inSz) -{ - WOLFSSL_ENTER("wolfSSL_d2i_PublicKey"); - - return _d2i_PublicKey(type, out, in, inSz, 0); -} -/* Reads in a DER format key. If PKCS8 headers are found they are stripped off. - * - * type type of key - * out newly created WOLFSSL_EVP_PKEY structure - * in pointer to input key DER - * inSz size of in buffer - * - * On success a non null pointer is returned and the pointer in is advanced the - * same number of bytes read. - */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type, WOLFSSL_EVP_PKEY** out, - const unsigned char **in, long inSz) -{ - WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey"); - - return _d2i_PublicKey(type, out, in, inSz, 1); -} - -#ifdef WOLF_PRIVATE_KEY_ID -/* Create an EVP structure for use with crypto callbacks */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_id(int type, WOLFSSL_EVP_PKEY** out, - void* heap, int devId) -{ - WOLFSSL_EVP_PKEY* local; - - if (out != NULL && *out != NULL) { - wolfSSL_EVP_PKEY_free(*out); - *out = NULL; - } - - local = wolfSSL_EVP_PKEY_new_ex(heap); - if (local == NULL) { - return NULL; - } - - local->type = type; - local->pkey_sz = 0; - local->pkcs8HeaderSz = 0; - - switch (type) { -#ifndef NO_RSA - case WC_EVP_PKEY_RSA: - { - RsaKey* key; - local->ownRsa = 1; - local->rsa = wolfSSL_RSA_new_ex(heap, devId); - if (local->rsa == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - key = (RsaKey*)local->rsa->internal; - #ifdef WOLF_CRYPTO_CB - key->devId = devId; - #endif - (void)key; - local->rsa->inSet = 1; - break; - } -#endif /* !NO_RSA */ -#ifdef HAVE_ECC - case WC_EVP_PKEY_EC: - { - ecc_key* key; - local->ownEcc = 1; - local->ecc = wolfSSL_EC_KEY_new_ex(heap, devId); - if (local->ecc == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - key = (ecc_key*)local->ecc->internal; - #ifdef WOLF_CRYPTO_CB - key->devId = devId; - #endif - key->type = ECC_PRIVATEKEY; - /* key is required to have a key size / curve set, although - * actual one used is determined by devId callback function */ - wc_ecc_set_curve(key, ECDHE_SIZE, ECC_CURVE_DEF); - - local->ecc->inSet = 1; - break; - } -#endif /* HAVE_ECC */ - default: - WOLFSSL_MSG("Unsupported private key id type"); - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - - if (local != NULL && out != NULL) { - *out = local; - } - - return local; -} -#endif /* WOLF_PRIVATE_KEY_ID */ - -#ifndef NO_CERTS /* // NOLINT(readability-redundant-preprocessor) */ - -#ifndef NO_CHECK_PRIVATE_KEY -/* Check private against public in certificate for match - * - * ssl WOLFSSL structure to check private key in - * - * Returns WOLFSSL_SUCCESS on good private key - * WOLFSSL_FAILURE if mismatched. */ -int wolfSSL_check_private_key(const WOLFSSL* ssl) -{ - int res = WOLFSSL_SUCCESS; - -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - DerBuffer *privateKey; -#ifdef WOLFSSL_DUAL_ALG_CERTS - DerBuffer *altPrivateKey; -#endif -#else - const DerBuffer *privateKey; -#ifdef WOLFSSL_DUAL_ALG_CERTS - const DerBuffer *altPrivateKey; -#endif -#endif - - if (ssl == NULL) { - return WOLFSSL_FAILURE; - } -#ifdef WOLFSSL_DUAL_ALG_CERTS -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - privateKey = wolfssl_priv_der_unblind(ssl->buffers.key, - ssl->buffers.keyMask); - if (privateKey == NULL) { - res = WOLFSSL_FAILURE; - } - if (ssl->buffers.altKey != NULL) { - altPrivateKey = wolfssl_priv_der_unblind(ssl->buffers.altKey, - ssl->buffers.altKeyMask); - if (altPrivateKey == NULL) { - res = WOLFSSL_FAILURE; - } - } - else { - altPrivateKey = NULL; - } -#else - privateKey = ssl->buffers.key; - altPrivateKey = ssl->buffers.altKey; -#endif - if (res == WOLFSSL_SUCCESS) { - res = check_cert_key(ssl->buffers.certificate, privateKey, - altPrivateKey, ssl->heap, ssl->buffers.keyDevId, - ssl->buffers.keyLabel, ssl->buffers.keyId, ssl->buffers.altKeyDevId, - ssl->buffers.altKeyLabel, ssl->buffers.altKeyId); - } -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(privateKey); - wolfssl_priv_der_unblind_free(altPrivateKey); -#endif -#else -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - privateKey = wolfssl_priv_der_unblind(ssl->buffers.key, - ssl->buffers.keyMask); - if (privateKey == NULL) { - res = WOLFSSL_FAILURE; - } -#else - privateKey = ssl->buffers.key; -#endif - if (res == WOLFSSL_SUCCESS) { - res = check_cert_key(ssl->buffers.certificate, privateKey, NULL, - ssl->heap, ssl->buffers.keyDevId, ssl->buffers.keyLabel, - ssl->buffers.keyId, INVALID_DEVID, 0, 0); - } -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(privateKey); -#endif -#endif - - return res; -} -#endif /* !NO_CHECK_PRIVATE_KEY */ - -#endif /* !NO_CERTS */ - -#endif /* OPENSSL_EXTRA */ - -#if defined(HAVE_RPK) -/* Confirm that all the byte data in the buffer is unique. - * return 1 if all the byte data in the buffer is unique, otherwise 0. - */ -static int isArrayUnique(const char* buf, size_t len) -{ - size_t i, j; - /* check the array is unique */ - for (i = 0; i < len -1; ++i) { - for (j = i+ 1; j < len; ++j) { - if (buf[i] == buf[j]) { - return 0; - } - } - } - return 1; -} - -/* Set user preference for the {client,server}_cert_type extension. - * Takes byte array containing cert types the caller can provide to its peer. - * Cert types are in preferred order in the array. - */ -static int set_cert_type(RpkConfig* cfg, - int client, const char* buf, int bufLen) -{ - int i; - byte* certTypeCnt; - byte* certTypes; - - if (cfg == NULL || bufLen > (client ? MAX_CLIENT_CERT_TYPE_CNT : - MAX_SERVER_CERT_TYPE_CNT)) { - return BAD_FUNC_ARG; - } - - if (client) { - certTypeCnt = &cfg->preferred_ClientCertTypeCnt; - certTypes = cfg->preferred_ClientCertTypes; - } - else { - certTypeCnt = &cfg->preferred_ServerCertTypeCnt; - certTypes = cfg->preferred_ServerCertTypes; - } - /* if buf is set to NULL or bufLen is zero, it defaults the setting*/ - if (buf == NULL || bufLen == 0) { - *certTypeCnt = 1; - for (i = 0; i < 2; i++) - certTypes[i] = WOLFSSL_CERT_TYPE_X509; - return WOLFSSL_SUCCESS; - } - - if (!isArrayUnique(buf, (size_t)bufLen)) - return BAD_FUNC_ARG; - - for (i = 0; i < bufLen; i++) { - if (buf[i] != WOLFSSL_CERT_TYPE_RPK && buf[i] != WOLFSSL_CERT_TYPE_X509) - return BAD_FUNC_ARG; - certTypes[i] = (byte)buf[i]; - } - *certTypeCnt = bufLen; - - return WOLFSSL_SUCCESS; -} -int wolfSSL_set_client_cert_type(WOLFSSL* ssl, const char* buf, int buflen) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - return set_cert_type(&ssl->options.rpkConfig, 1, buf, buflen); -} -int wolfSSL_set_server_cert_type(WOLFSSL* ssl, const char* buf, int buflen) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - return set_cert_type(&ssl->options.rpkConfig, 0, buf, buflen); -} -int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, - const char* buf, int buflen) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - return set_cert_type(&ctx->rpkConfig, 1, buf, buflen); -} -int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, - const char* buf, int buflen) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - return set_cert_type(&ctx->rpkConfig, 0, buf, buflen); -} - -/* get negotiated certificate type value and return it to the second parameter. - * cert type value: - * -1: WOLFSSL_CERT_TYPE_UNKNOWN - * 0: WOLFSSL_CERT_TYPE_X509 - * 2: WOLFSSL_CERT_TYPE_RPK - * return WOLFSSL_SUCCESS on success, otherwise negative value. - * in case no negotiation performed, it returns WOLFSSL_SUCCESS and -1 is for - * cert type. - */ -int wolfSSL_get_negotiated_client_cert_type(WOLFSSL* ssl, int* tp) -{ - int ret = WOLFSSL_SUCCESS; - - if (ssl == NULL || tp == NULL) - return BAD_FUNC_ARG; - - if (ssl->options.side == WOLFSSL_CLIENT_END) { - if (ssl->options.rpkState.received_ClientCertTypeCnt == 1) - *tp = ssl->options.rpkState.received_ClientCertTypes[0]; - else - *tp = WOLFSSL_CERT_TYPE_UNKNOWN; - } - else { - if (ssl->options.rpkState.sending_ClientCertTypeCnt == 1) - *tp = ssl->options.rpkState.sending_ClientCertTypes[0]; - else - *tp = WOLFSSL_CERT_TYPE_UNKNOWN; - } - return ret; -} - -/* get negotiated certificate type value and return it to the second parameter. - * cert type value: - * -1: WOLFSSL_CERT_TYPE_UNKNOWN - * 0: WOLFSSL_CERT_TYPE_X509 - * 2: WOLFSSL_CERT_TYPE_RPK - * return WOLFSSL_SUCCESS on success, otherwise negative value. - * in case no negotiation performed, it returns WOLFSSL_SUCCESS and -1 is for - * cert type. - */ -int wolfSSL_get_negotiated_server_cert_type(WOLFSSL* ssl, int* tp) -{ - int ret = WOLFSSL_SUCCESS; - - if (ssl == NULL || tp == NULL) - return BAD_FUNC_ARG; - - if (ssl->options.side == WOLFSSL_CLIENT_END) { - if (ssl->options.rpkState.received_ServerCertTypeCnt == 1) - *tp = ssl->options.rpkState.received_ServerCertTypes[0]; - else - *tp = WOLFSSL_CERT_TYPE_UNKNOWN; - } - else { - if (ssl->options.rpkState.sending_ServerCertTypeCnt == 1) - *tp = ssl->options.rpkState.sending_ServerCertTypes[0]; - else - *tp = WOLFSSL_CERT_TYPE_UNKNOWN; - } - return ret; -} - -#endif /* HAVE_RPK */ - -#ifdef HAVE_ECC - -/* Set Temp CTX EC-DHE size in octets, can be 14 - 66 (112 - 521 bit) */ -int wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX* ctx, word16 sz) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetTmpEC_DHE_Sz"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - /* if 0 then get from loaded private key */ - if (sz == 0) { - /* applies only to ECDSA */ - if (ctx->privateKeyType != ecc_dsa_sa_algo) - return WOLFSSL_SUCCESS; - - if (ctx->privateKeySz == 0) { - WOLFSSL_MSG("Must set private key/cert first"); - return BAD_FUNC_ARG; - } - - sz = (word16)ctx->privateKeySz; - } - - /* check size */ -#if ECC_MIN_KEY_SZ > 0 - if (sz < ECC_MINSIZE) - return BAD_FUNC_ARG; -#endif - if (sz > ECC_MAXSIZE) - return BAD_FUNC_ARG; - - ctx->eccTempKeySz = sz; - - return WOLFSSL_SUCCESS; -} - - -/* Set Temp SSL EC-DHE size in octets, can be 14 - 66 (112 - 521 bit) */ -int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL* ssl, word16 sz) -{ - WOLFSSL_ENTER("wolfSSL_SetTmpEC_DHE_Sz"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - /* check size */ -#if ECC_MIN_KEY_SZ > 0 - if (sz < ECC_MINSIZE) - return BAD_FUNC_ARG; -#endif - if (sz > ECC_MAXSIZE) - return BAD_FUNC_ARG; - - ssl->eccTempKeySz = sz; - - return WOLFSSL_SUCCESS; -} - -#endif /* HAVE_ECC */ - - -typedef struct { - byte verifyPeer:1; - byte verifyNone:1; - byte failNoCert:1; - byte failNoCertxPSK:1; - byte verifyPostHandshake:1; -} SetVerifyOptions; - -static SetVerifyOptions ModeToVerifyOptions(int mode) -{ - SetVerifyOptions opts; - XMEMSET(&opts, 0, sizeof(SetVerifyOptions)); - - if (mode != WOLFSSL_VERIFY_DEFAULT) { - opts.verifyNone = (mode == WOLFSSL_VERIFY_NONE); - if (!opts.verifyNone) { - opts.verifyPeer = - (mode & WOLFSSL_VERIFY_PEER) != 0; - opts.failNoCertxPSK = - (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) != 0; - opts.failNoCert = - (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) != 0; -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - opts.verifyPostHandshake = - (mode & WOLFSSL_VERIFY_POST_HANDSHAKE) != 0; -#endif - } - } - - return opts; -} - -WOLFSSL_ABI -void wolfSSL_CTX_set_verify(WOLFSSL_CTX* ctx, int mode, VerifyCallback verify_callback) -{ - SetVerifyOptions opts; - - WOLFSSL_ENTER("wolfSSL_CTX_set_verify"); - if (ctx == NULL) - return; - - opts = ModeToVerifyOptions(mode); - - ctx->verifyNone = opts.verifyNone; - ctx->verifyPeer = opts.verifyPeer; - ctx->failNoCert = opts.failNoCert; - ctx->failNoCertxPSK = opts.failNoCertxPSK; -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - ctx->verifyPostHandshake = opts.verifyPostHandshake; -#endif - - ctx->verifyCallback = verify_callback; -} - -#ifdef OPENSSL_ALL -void wolfSSL_CTX_set_cert_verify_callback(WOLFSSL_CTX* ctx, - CertVerifyCallback cb, void* arg) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_cert_verify_callback"); - if (ctx == NULL) - return; - - ctx->verifyCertCb = cb; - ctx->verifyCertCbArg = arg; -} -#endif - - -void wolfSSL_set_verify(WOLFSSL* ssl, int mode, VerifyCallback verify_callback) -{ - SetVerifyOptions opts; - - WOLFSSL_ENTER("wolfSSL_set_verify"); - if (ssl == NULL) - return; - - opts = ModeToVerifyOptions(mode); - - ssl->options.verifyNone = opts.verifyNone; - ssl->options.verifyPeer = opts.verifyPeer; - ssl->options.failNoCert = opts.failNoCert; - ssl->options.failNoCertxPSK = opts.failNoCertxPSK; -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - ssl->options.verifyPostHandshake = opts.verifyPostHandshake; -#endif - - ssl->verifyCallback = verify_callback; -} - -void wolfSSL_set_verify_result(WOLFSSL *ssl, long v) -{ - WOLFSSL_ENTER("wolfSSL_set_verify_result"); - - if (ssl == NULL) - return; - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ - defined(OPENSSL_ALL) - ssl->peerVerifyRet = (unsigned long)v; -#else - (void)v; - WOLFSSL_STUB("wolfSSL_set_verify_result"); -#endif -} - -#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ - defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) -/* For TLS v1.3 send handshake messages after handshake completes. */ -/* Returns 1=WOLFSSL_SUCCESS or 0=WOLFSSL_FAILURE */ -int wolfSSL_verify_client_post_handshake(WOLFSSL* ssl) -{ - int ret = wolfSSL_request_certificate(ssl); - if (ret != WOLFSSL_SUCCESS) { - if (!IsAtLeastTLSv1_3(ssl->version)) { - /* specific error of wrong version expected */ - WOLFSSL_ERROR(UNSUPPORTED_PROTO_VERSION); - - } - else { - WOLFSSL_ERROR(ret); /* log the error in the error queue */ - } - } - return (ret == WOLFSSL_SUCCESS) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} - -int wolfSSL_CTX_set_post_handshake_auth(WOLFSSL_CTX* ctx, int val) -{ - int ret = wolfSSL_CTX_allow_post_handshake_auth(ctx); - if (ret == 0) { - ctx->postHandshakeAuth = (val != 0); - } - return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} -int wolfSSL_set_post_handshake_auth(WOLFSSL* ssl, int val) -{ - int ret = wolfSSL_allow_post_handshake_auth(ssl); - if (ret == 0) { - ssl->options.postHandshakeAuth = (val != 0); - } - return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} -#endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_TLS13 && - * WOLFSSL_POST_HANDSHAKE_AUTH */ - -/* store user ctx for verify callback */ -void wolfSSL_SetCertCbCtx(WOLFSSL* ssl, void* ctx) -{ - WOLFSSL_ENTER("wolfSSL_SetCertCbCtx"); - if (ssl) - ssl->verifyCbCtx = ctx; -} - - -/* store user ctx for verify callback */ -void wolfSSL_CTX_SetCertCbCtx(WOLFSSL_CTX* ctx, void* userCtx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetCertCbCtx"); - if (ctx) - ctx->verifyCbCtx = userCtx; -} - - -/* store context CA Cache addition callback */ -void wolfSSL_CTX_SetCACb(WOLFSSL_CTX* ctx, CallbackCACache cb) -{ - if (ctx && ctx->cm) - ctx->cm->caCacheCallback = cb; -} - - -#if defined(PERSIST_CERT_CACHE) - -#if !defined(NO_FILESYSTEM) - -/* Persist cert cache to file */ -int wolfSSL_CTX_save_cert_cache(WOLFSSL_CTX* ctx, const char* fname) -{ - WOLFSSL_ENTER("wolfSSL_CTX_save_cert_cache"); - - if (ctx == NULL || fname == NULL) - return BAD_FUNC_ARG; - - return CM_SaveCertCache(ctx->cm, fname); -} - - -/* Persist cert cache from file */ -int wolfSSL_CTX_restore_cert_cache(WOLFSSL_CTX* ctx, const char* fname) -{ - WOLFSSL_ENTER("wolfSSL_CTX_restore_cert_cache"); - - if (ctx == NULL || fname == NULL) - return BAD_FUNC_ARG; - - return CM_RestoreCertCache(ctx->cm, fname); -} - -#endif /* NO_FILESYSTEM */ - -/* Persist cert cache to memory */ -int wolfSSL_CTX_memsave_cert_cache(WOLFSSL_CTX* ctx, void* mem, - int sz, int* used) -{ - WOLFSSL_ENTER("wolfSSL_CTX_memsave_cert_cache"); - - if (ctx == NULL || mem == NULL || used == NULL || sz <= 0) - return BAD_FUNC_ARG; - - return CM_MemSaveCertCache(ctx->cm, mem, sz, used); -} - - -/* Restore cert cache from memory */ -int wolfSSL_CTX_memrestore_cert_cache(WOLFSSL_CTX* ctx, const void* mem, int sz) -{ - WOLFSSL_ENTER("wolfSSL_CTX_memrestore_cert_cache"); - - if (ctx == NULL || mem == NULL || sz <= 0) - return BAD_FUNC_ARG; - - return CM_MemRestoreCertCache(ctx->cm, mem, sz); -} - - -/* get how big the the cert cache save buffer needs to be */ -int wolfSSL_CTX_get_cert_cache_memsize(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_get_cert_cache_memsize"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - return CM_GetCertCacheMemSize(ctx->cm); -} - -#endif /* PERSIST_CERT_CACHE */ -#endif /* !NO_CERTS */ +#define WOLFSSL_SSL_API_CRL_OCSP_INCLUDED +#include "src/ssl_api_crl_ocsp.c" void wolfSSL_load_error_strings(void) @@ -12098,126 +7907,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #endif /* HAVE_ANON */ -#ifndef NO_CERTS - - /* unload any certs or keys that SSL owns, leave CTX as is - WOLFSSL_SUCCESS on ok */ - int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) - { - if (ssl == NULL) { - WOLFSSL_MSG("Null function arg"); - return BAD_FUNC_ARG; - } - - if (ssl->buffers.weOwnCert && !ssl->keepCert) { - WOLFSSL_MSG("Unloading cert"); - FreeDer(&ssl->buffers.certificate); - #ifdef KEEP_OUR_CERT - wolfSSL_X509_free(ssl->ourCert); - ssl->ourCert = NULL; - #endif - ssl->buffers.weOwnCert = 0; - } - - if (ssl->buffers.weOwnCertChain) { - WOLFSSL_MSG("Unloading cert chain"); - FreeDer(&ssl->buffers.certChain); - ssl->buffers.weOwnCertChain = 0; - } - - if (ssl->buffers.weOwnKey) { - WOLFSSL_MSG("Unloading key"); - ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); - FreeDer(&ssl->buffers.key); - #ifdef WOLFSSL_BLIND_PRIVATE_KEY - FreeDer(&ssl->buffers.keyMask); - #endif - ssl->buffers.weOwnKey = 0; - } - -#ifdef WOLFSSL_DUAL_ALG_CERTS - if (ssl->buffers.weOwnAltKey) { - WOLFSSL_MSG("Unloading alt key"); - ForceZero(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length); - FreeDer(&ssl->buffers.altKey); - #ifdef WOLFSSL_BLIND_PRIVATE_KEY - FreeDer(&ssl->buffers.altKeyMask); - #endif - ssl->buffers.weOwnAltKey = 0; - } -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - - return WOLFSSL_SUCCESS; - } - - - int wolfSSL_CTX_UnloadCAs(WOLFSSL_CTX* ctx) - { - WOLFSSL_ENTER("wolfSSL_CTX_UnloadCAs"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - return wolfSSL_CertManagerUnloadCAs(ctx->cm); - } - - int wolfSSL_CTX_UnloadIntermediateCerts(WOLFSSL_CTX* ctx) - { - int ret; - - WOLFSSL_ENTER("wolfSSL_CTX_UnloadIntermediateCerts"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - ret = wolfSSL_RefWithMutexLock(&ctx->ref); - if (ret < 0) - return ret; - - if (ctx->ref.count > 1) { - WOLFSSL_MSG("ctx object must have a ref count of 1 before " - "unloading intermediate certs"); - ret = BAD_STATE_E; - } - else { - ret = wolfSSL_CertManagerUnloadIntermediateCerts(ctx->cm); - } - - if (wolfSSL_RefWithMutexUnlock(&ctx->ref) != 0) - WOLFSSL_MSG("Failed to unlock mutex!"); - - return ret; - } - - -#ifdef WOLFSSL_TRUST_PEER_CERT - int wolfSSL_CTX_Unload_trust_peers(WOLFSSL_CTX* ctx) - { - WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - return wolfSSL_CertManagerUnload_trust_peers(ctx->cm); - } - -#ifdef WOLFSSL_LOCAL_X509_STORE - int wolfSSL_Unload_trust_peers(WOLFSSL* ssl) - { - WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerUnload_trust_peers(SSL_CM(ssl)); - } -#endif /* WOLFSSL_LOCAL_X509_STORE */ -#endif /* WOLFSSL_TRUST_PEER_CERT */ -/* old NO_FILESYSTEM end */ -#endif /* !NO_CERTS */ - - #ifdef OPENSSL_EXTRA int wolfSSL_add_all_algorithms(void) @@ -12360,50 +8049,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #endif /* !NO_BIO */ #endif /* OPENSSL_EXTRA */ -#ifndef WOLFSSL_NO_CA_NAMES - void wolfSSL_CTX_set_client_CA_list(WOLFSSL_CTX* ctx, - WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) - { - WOLFSSL_ENTER("wolfSSL_CTX_set_client_CA_list"); - if (ctx != NULL) { - wolfSSL_sk_X509_NAME_pop_free(ctx->client_ca_names, NULL); - ctx->client_ca_names = names; - } - } - - void wolfSSL_set_client_CA_list(WOLFSSL* ssl, - WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) - { - WOLFSSL_ENTER("wolfSSL_set_client_CA_list"); - if (ssl != NULL) { - if (ssl->client_ca_names != ssl->ctx->client_ca_names) - wolfSSL_sk_X509_NAME_pop_free(ssl->client_ca_names, NULL); - ssl->client_ca_names = names; - } - } - - void wolfSSL_CTX_set0_CA_list(WOLFSSL_CTX* ctx, - WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) - { - WOLFSSL_ENTER("wolfSSL_CTX_set0_CA_list"); - if (ctx != NULL) { - wolfSSL_sk_X509_NAME_pop_free(ctx->ca_names, NULL); - ctx->ca_names = names; - } - } - - void wolfSSL_set0_CA_list(WOLFSSL* ssl, - WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) - { - WOLFSSL_ENTER("wolfSSL_set0_CA_list"); - if (ssl != NULL) { - if (ssl->ca_names != ssl->ctx->ca_names) - wolfSSL_sk_X509_NAME_pop_free(ssl->ca_names, NULL); - ssl->ca_names = names; - } - } -#endif /* WOLFSSL_NO_CA_NAMES */ - #ifdef WOLFSSL_CERT_SETUP_CB #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* registers client cert callback, called during handshake if server @@ -12622,249 +8267,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) } #endif /* WOLFSSL_CERT_SETUP_CB */ -#ifndef WOLFSSL_NO_CA_NAMES - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_CTX_get_client_CA_list( - const WOLFSSL_CTX *ctx) - { - WOLFSSL_ENTER("wolfSSL_CTX_get_client_CA_list"); - - if (ctx == NULL) { - WOLFSSL_MSG("Bad argument passed to " - "wolfSSL_CTX_get_client_CA_list"); - return NULL; - } - - return ctx->client_ca_names; - } - - /* On server side: returns the CAs set via *_set_client_CA_list(); - * On client side: returns the CAs received from server -- same as - * wolfSSL_get0_peer_CA_list() */ - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get_client_CA_list( - const WOLFSSL* ssl) - { - WOLFSSL_ENTER("wolfSSL_get_client_CA_list"); - - if (ssl == NULL) { - WOLFSSL_MSG("Bad argument passed to wolfSSL_get_client_CA_list"); - return NULL; - } - - if (ssl->options.side == WOLFSSL_CLIENT_END) - return ssl->peer_ca_names; - else - return SSL_CLIENT_CA_NAMES(ssl); - } - - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_CTX_get0_CA_list( - const WOLFSSL_CTX *ctx) - { - WOLFSSL_ENTER("wolfSSL_CTX_get0_CA_list"); - - if (ctx == NULL) { - WOLFSSL_MSG("Bad argument passed to wolfSSL_CTX_get0_CA_list"); - return NULL; - } - - return ctx->ca_names; - } - - /* Always returns the CA's set via *_set0_CA_list */ - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get0_CA_list(const WOLFSSL *ssl) - { - WOLFSSL_ENTER("wolfSSL_get0_CA_list"); - - if (ssl == NULL) { - WOLFSSL_MSG("Bad argument passed to wolfSSL_get0_CA_list"); - return NULL; - } - - return SSL_CA_NAMES(ssl); - } - - /* Always returns the CA's received from the peer */ - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get0_peer_CA_list( - const WOLFSSL* ssl) - { - WOLFSSL_ENTER("wolfSSL_get0_peer_CA_list"); - - if (ssl == NULL) { - WOLFSSL_MSG("Bad argument passed to wolfSSL_get0_peer_CA_list"); - return NULL; - } - - return ssl->peer_ca_names; - } - - #if !defined(NO_CERTS) - static int add_to_CA_list(WOLFSSL_STACK* ca_names, WOLFSSL_X509* x509) - { - WOLFSSL_X509_NAME *nameCopy = NULL; - - nameCopy = wolfSSL_X509_NAME_dup(wolfSSL_X509_get_subject_name(x509)); - if (nameCopy == NULL) { - WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); - return WOLFSSL_FAILURE; - } - - if (wolfSSL_sk_X509_NAME_push(ca_names, nameCopy) <= 0) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); - wolfSSL_X509_NAME_free(nameCopy); - return WOLFSSL_FAILURE; - } - - return WOLFSSL_SUCCESS; - } - - int wolfSSL_CTX_add_client_CA(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) - { - WOLFSSL_ENTER("wolfSSL_CTX_add_client_CA"); - if (ctx == NULL || x509 == NULL) { - WOLFSSL_MSG("Bad argument"); - return WOLFSSL_FAILURE; - } - if (ctx->client_ca_names == NULL) { - ctx->client_ca_names = wolfSSL_sk_X509_NAME_new(NULL); - if (ctx->client_ca_names == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - return WOLFSSL_FAILURE; - } - } - return add_to_CA_list(ctx->client_ca_names, x509); - } - - int wolfSSL_add_client_CA(WOLFSSL* ssl, WOLFSSL_X509* x509) - { - WOLFSSL_ENTER("wolfSSL_add_client_CA"); - if (ssl == NULL || x509 == NULL) { - WOLFSSL_MSG("Bad argument"); - return WOLFSSL_FAILURE; - } - if (ssl->client_ca_names == NULL) { - ssl->client_ca_names = wolfSSL_sk_X509_NAME_new(NULL); - if (ssl->client_ca_names == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - return WOLFSSL_FAILURE; - } - } - return add_to_CA_list(ssl->client_ca_names, x509); - } - - int wolfSSL_CTX_add1_to_CA_list(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) - { - WOLFSSL_ENTER("wolfSSL_CTX_add1_to_CA_list"); - if (ctx == NULL || x509 == NULL) { - WOLFSSL_MSG("Bad argument"); - return WOLFSSL_FAILURE; - } - if (ctx->ca_names == NULL) { - ctx->ca_names = wolfSSL_sk_X509_NAME_new(NULL); - if (ctx->ca_names == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - return WOLFSSL_FAILURE; - } - } - return add_to_CA_list(ctx->ca_names, x509); - } - - int wolfSSL_add1_to_CA_list(WOLFSSL* ssl, WOLFSSL_X509* x509) - { - WOLFSSL_ENTER("wolfSSL_add1_to_CA_list"); - if (ssl == NULL || x509 == NULL) { - WOLFSSL_MSG("Bad argument"); - return WOLFSSL_FAILURE; - } - if (ssl->ca_names == NULL) { - ssl->ca_names = wolfSSL_sk_X509_NAME_new(NULL); - if (ssl->ca_names == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - return WOLFSSL_FAILURE; - } - } - return add_to_CA_list(ssl->ca_names, x509); - } - #endif /* !NO_CERTS */ - - #ifndef NO_BIO - #if !defined(NO_RSA) && !defined(NO_CERTS) - 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 - * that case. If OPENSSL_EXTRA is enabled, go ahead and include - * the function. */ - #ifdef OPENSSL_EXTRA - WOLFSSL_STACK *list = NULL; - WOLFSSL_BIO* bio = NULL; - WOLFSSL_X509 *cert = NULL; - WOLFSSL_X509_NAME *nameCopy = NULL; - unsigned long err = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - - WOLFSSL_ENTER("wolfSSL_load_client_CA_file"); - - bio = wolfSSL_BIO_new_file(fname, "rb"); - if (bio == NULL) { - WOLFSSL_MSG("wolfSSL_BIO_new_file error"); - goto cleanup; - } - - list = wolfSSL_sk_X509_NAME_new(NULL); - if (list == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - goto cleanup; - } - - /* Read each certificate in the chain out of the file. */ - while (wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL) { - /* Need a persistent copy of the subject name. */ - nameCopy = wolfSSL_X509_NAME_dup( - wolfSSL_X509_get_subject_name(cert)); - if (nameCopy == NULL) { - WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); - goto cleanup; - } - /* - * Original cert will be freed so make sure not to try to access - * it in the future. - */ - nameCopy->x509 = NULL; - - if (wolfSSL_sk_X509_NAME_push(list, nameCopy) <= 0) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); - /* Do free in loop because nameCopy is now responsibility - * of list to free and adding jumps to cleanup after this - * might result in a double free. */ - wolfSSL_X509_NAME_free(nameCopy); - goto cleanup; - } - - wolfSSL_X509_free(cert); - cert = NULL; - } - - CLEAR_ASN_NO_PEM_HEADER_ERROR(err); - - err = WOLFSSL_SUCCESS; -cleanup: - wolfSSL_X509_free(cert); - cert = NULL; - wolfSSL_BIO_free(bio); - if (err != WOLFSSL_SUCCESS) { - /* We failed so return NULL */ - wolfSSL_sk_X509_NAME_pop_free(list, NULL); - list = NULL; - } - return list; - #else - (void)fname; - return NULL; - #endif - } - #endif - #endif /* !NO_BIO */ -#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA */ - #ifdef OPENSSL_EXTRA #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \ @@ -13215,130 +8617,6 @@ cleanup: } #endif /* OPENSSL_EXTRA */ -#if !defined(NO_CERTS) && (defined(OPENSSL_EXTRA) || \ - defined(WOLFSSL_WPAS_SMALL)) - - WOLFSSL_X509_STORE* wolfSSL_CTX_get_cert_store(const WOLFSSL_CTX* ctx) - { - if (ctx == NULL) { - return NULL; - } - - if (ctx->x509_store_pt != NULL) - return ctx->x509_store_pt; - return &((WOLFSSL_CTX*)ctx)->x509_store; - } - - void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str) - { - WOLFSSL_ENTER("wolfSSL_CTX_set_cert_store"); - if (ctx == NULL || str == NULL || ctx->cm == str->cm) { - return; - } - - if (wolfSSL_CertManager_up_ref(str->cm) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_CertManager_up_ref error"); - return; - } - /* free cert manager if have one */ - if (ctx->cm != NULL) { - wolfSSL_CertManagerFree(ctx->cm); - } - ctx->cm = str->cm; - ctx->x509_store.cm = str->cm; - - /* free existing store if it exists */ - wolfSSL_X509_STORE_free(ctx->x509_store_pt); - ctx->x509_store.cache = str->cache; - ctx->x509_store_pt = str; /* take ownership of store and free it - with CTX free */ - ctx->cm->x509_store_p = ctx->x509_store_pt;/* CTX has ownership - and free it with CTX free*/ - } - -#ifdef OPENSSL_ALL - int wolfSSL_CTX_set1_verify_cert_store(WOLFSSL_CTX* ctx, - WOLFSSL_X509_STORE* str) - { - WOLFSSL_ENTER("wolfSSL_CTX_set1_verify_cert_store"); - - if (ctx == NULL || str == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - /* NO-OP when setting existing store */ - if (str == CTX_STORE(ctx)) - return WOLFSSL_SUCCESS; - - if (wolfSSL_X509_STORE_up_ref(str) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_X509_STORE_up_ref error"); - return WOLFSSL_FAILURE; - } - - /* free existing store if it exists */ - wolfSSL_X509_STORE_free(ctx->x509_store_pt); - ctx->x509_store_pt = str; /* take ownership of store and free it - with CTX free */ - return WOLFSSL_SUCCESS; - } -#endif - - int wolfSSL_set0_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str) - { - WOLFSSL_ENTER("wolfSSL_set0_verify_cert_store"); - - if (ssl == NULL || str == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - /* NO-OP when setting existing store */ - if (str == SSL_STORE(ssl)) - return WOLFSSL_SUCCESS; - - /* free existing store if it exists */ - wolfSSL_X509_STORE_free(ssl->x509_store_pt); - if (str == ssl->ctx->x509_store_pt) - ssl->x509_store_pt = NULL; /* if setting ctx store then just revert - to using that instead */ - else - ssl->x509_store_pt = str; /* take ownership of store and free it - with SSL free */ - return WOLFSSL_SUCCESS; - } - - - int wolfSSL_set1_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str) - { - WOLFSSL_ENTER("wolfSSL_set1_verify_cert_store"); - - if (ssl == NULL || str == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - /* NO-OP when setting existing store */ - if (str == SSL_STORE(ssl)) - return WOLFSSL_SUCCESS; - - if (wolfSSL_X509_STORE_up_ref(str) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_X509_STORE_up_ref error"); - return WOLFSSL_FAILURE; - } - - /* free existing store if it exists */ - wolfSSL_X509_STORE_free(ssl->x509_store_pt); - if (str == ssl->ctx->x509_store_pt) - ssl->x509_store_pt = NULL; /* if setting ctx store then just revert - to using that instead */ - else - ssl->x509_store_pt = str; /* take ownership of store and free it - with SSL free */ - return WOLFSSL_SUCCESS; - } -#endif /* !NO_CERTS && (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) */ - #ifdef WOLFSSL_ENCRYPTED_KEYS void wolfSSL_CTX_set_default_passwd_cb_userdata(WOLFSSL_CTX* ctx, @@ -14975,78 +10253,6 @@ WOLF_STACK_OF(WOLFSSL_X509) *wolfSSL_get0_verified_chain(const WOLFSSL *ssl) #endif /* KEEP_PEER_CERT */ #endif /* SESSION_CERTS && OPENSSL_EXTRA */ -#ifndef NO_CERTS - -/* OPENSSL_EXTRA is needed for wolfSSL_X509_d21 function - KEEP_OUR_CERT is to insure ability for returning ssl certificate */ -#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ - defined(KEEP_OUR_CERT) -WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) -{ - if (ssl == NULL) { - return NULL; - } - - if (ssl->buffers.weOwnCert) { - if (ssl->ourCert == NULL) { - if (ssl->buffers.certificate == NULL) { - WOLFSSL_MSG("Certificate buffer not set!"); - return NULL; - } - #ifndef WOLFSSL_X509_STORE_CERTS - ssl->ourCert = wolfSSL_X509_d2i_ex(NULL, - ssl->buffers.certificate->buffer, - (int)ssl->buffers.certificate->length, - ssl->heap); - #endif - } - return ssl->ourCert; - } - else { /* if cert not owned get parent ctx cert or return null */ - if (ssl->ctx) { - if (ssl->ctx->ourCert == NULL) { - if (ssl->ctx->certificate == NULL) { - WOLFSSL_MSG("Ctx Certificate buffer not set!"); - return NULL; - } - #ifndef WOLFSSL_X509_STORE_CERTS - ssl->ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, - ssl->ctx->certificate->buffer, - (int)ssl->ctx->certificate->length, - ssl->heap); - #endif - ssl->ctx->ownOurCert = 1; - } - return ssl->ctx->ourCert; - } - } - - return NULL; -} - -WOLFSSL_X509* wolfSSL_CTX_get0_certificate(WOLFSSL_CTX* ctx) -{ - if (ctx) { - if (ctx->ourCert == NULL) { - if (ctx->certificate == NULL) { - WOLFSSL_MSG("Ctx Certificate buffer not set!"); - return NULL; - } - #ifndef WOLFSSL_X509_STORE_CERTS - ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, - ctx->certificate->buffer, - (int)ctx->certificate->length, - ctx->heap); - #endif - ctx->ownOurCert = 1; - } - return ctx->ourCert; - } - return NULL; -} -#endif /* OPENSSL_EXTRA && KEEP_OUR_CERT */ -#endif /* NO_CERTS */ - #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) void wolfSSL_set_connect_state(WOLFSSL* ssl) { @@ -16299,201 +11505,6 @@ void wolfSSL_set_dynlock_destroy_callback( } -#endif /* OPENSSL_EXTRA */ - -#ifdef OPENSSL_EXTRA -#ifndef NO_CERTS - -#if !defined(NO_ASN) && !defined(NO_PWDBASED) -/* Copies unencrypted DER key buffer into "der". If "der" is null then the size - * of buffer needed is returned. If *der == NULL then it allocates a buffer. - * NOTE: This also advances the "der" pointer to be at the end of buffer. - * - * Returns size of key buffer on success - */ -int wolfSSL_i2d_PrivateKey(const WOLFSSL_EVP_PKEY* key, unsigned char** der) -{ - return wolfSSL_EVP_PKEY_get_der(key, der); -} - -int wolfSSL_i2d_PrivateKey_bio(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - int derSz = 0; - byte* der = NULL; - - if (bio == NULL || key == NULL) { - return WOLFSSL_FAILURE; - } - - derSz = wolfSSL_i2d_PrivateKey(key, NULL); - if (derSz <= 0) { - WOLFSSL_MSG("wolfSSL_i2d_PrivateKey (for getting size) failed"); - return WOLFSSL_FAILURE; - } - - der = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (!der) { - WOLFSSL_MSG("malloc failed"); - return WOLFSSL_FAILURE; - } - - derSz = wolfSSL_i2d_PrivateKey(key, &der); - if (derSz <= 0) { - WOLFSSL_MSG("wolfSSL_i2d_PrivateKey failed"); - goto cleanup; - } - - if (wolfSSL_BIO_write(bio, der, derSz) != derSz) { - goto cleanup; - } - - ret = WOLFSSL_SUCCESS; - -cleanup: - XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return ret; -} - -int wolfSSL_i2d_PublicKey(const WOLFSSL_EVP_PKEY *key, unsigned char **der) -{ -#if !defined(NO_RSA) || defined(HAVE_ECC) -#ifdef HAVE_ECC - unsigned char *local_der = NULL; - word32 local_derSz = 0; - unsigned char *pub_der = NULL; - ecc_key *eccKey = NULL; - word32 inOutIdx = 0; -#endif - word32 pub_derSz = 0; - int ret; - int key_type = 0; - - if (key == NULL) { - return WOLFSSL_FATAL_ERROR; - } - - key_type = key->type; - if ((key_type != WC_EVP_PKEY_EC) && (key_type != WC_EVP_PKEY_RSA)) { - return WOLFSSL_FATAL_ERROR; - } - -#ifndef NO_RSA - if (key_type == WC_EVP_PKEY_RSA) { - return wolfSSL_i2d_RSAPublicKey(key->rsa, der); - } -#endif - - /* Now that RSA is taken care of, we only need to consider the ECC case. */ - -#ifdef HAVE_ECC - - /* We need to get the DER, then convert it to a public key. But what we get - * might be a buffered private key so we need to decode it and then encode - * the public part. */ - ret = wolfSSL_EVP_PKEY_get_der(key, &local_der); - if (ret <= 0) { - /* In this case, there was no buffered DER at all. This could be the - * case where the key that was passed in was generated. So now we - * have to create the local DER. */ - local_derSz = (word32)wolfSSL_i2d_ECPrivateKey(key->ecc, &local_der); - if (local_derSz == 0) { - ret = WOLFSSL_FATAL_ERROR; - } - } else { - local_derSz = (word32)ret; - ret = 0; - } - - if (ret == 0) { - eccKey = (ecc_key *)XMALLOC(sizeof(*eccKey), NULL, DYNAMIC_TYPE_ECC); - if (eccKey == NULL) { - WOLFSSL_MSG("Failed to allocate key buffer."); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 0) { - ret = wc_ecc_init(eccKey); - } - - if (ret == 0) { - ret = wc_EccPublicKeyDecode(local_der, &inOutIdx, eccKey, local_derSz); - if (ret < 0) { - /* We now try again as x.963 [point type][x][opt y]. */ - ret = wc_ecc_import_x963(local_der, local_derSz, eccKey); - } - } - - if (ret == 0) { - pub_derSz = (word32)wc_EccPublicKeyDerSize(eccKey, 1); - if ((int)pub_derSz <= 0) { - ret = WOLFSSL_FAILURE; - } - } - - if (ret == 0) { - pub_der = (unsigned char*)XMALLOC(pub_derSz, NULL, - DYNAMIC_TYPE_PUBLIC_KEY); - if (pub_der == NULL) { - WOLFSSL_MSG("Failed to allocate output buffer."); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 0) { - pub_derSz = (word32)wc_EccPublicKeyToDer(eccKey, pub_der, pub_derSz, 1); - if ((int)pub_derSz <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - } - - /* This block is for actually returning the DER of the public key */ - if ((ret == 0) && (der != NULL)) { - if (*der == NULL) { - *der = (unsigned char*)XMALLOC(pub_derSz, NULL, - DYNAMIC_TYPE_PUBLIC_KEY); - if (*der == NULL) { - WOLFSSL_MSG("Failed to allocate output buffer."); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - XMEMCPY(*der, pub_der, pub_derSz); - } - } - else { - XMEMCPY(*der, pub_der, pub_derSz); - *der += pub_derSz; - } - } - - XFREE(pub_der, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - XFREE(local_der, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - - wc_ecc_free(eccKey); - XFREE(eccKey, NULL, DYNAMIC_TYPE_ECC); - -#else - ret = WOLFSSL_FATAL_ERROR; -#endif /* HAVE_ECC */ - - if (ret == 0) { - return (int)pub_derSz; - } - - return ret; -#else - return WOLFSSL_FATAL_ERROR; -#endif /* !NO_RSA || HAVE_ECC */ -} -#endif /* !NO_ASN && !NO_PWDBASED */ - -#endif /* !NO_CERTS */ -#endif /* OPENSSL_EXTRA */ - -#ifdef OPENSSL_EXTRA - /* Sets the DNS hostname to name. * Hostname is cleared if name is NULL or empty. */ int wolfSSL_set1_host(WOLFSSL * ssl, const char* name) @@ -17335,38 +12346,6 @@ long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) } #endif /* HAVE_PK_CALLBACKS */ -#ifdef HAVE_CERTIFICATE_STATUS_REQUEST -long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type) -{ - WOLFSSL_ENTER("wolfSSL_set_tlsext_status_type"); - - if (s == NULL){ - return BAD_FUNC_ARG; - } - - if (type == WOLFSSL_TLSEXT_STATUSTYPE_ocsp){ - int r = TLSX_UseCertificateStatusRequest(&s->extensions, (byte)type, 0, - s, s->heap, s->devId); - return (long)r; - } else { - WOLFSSL_MSG( - "SSL_set_tlsext_status_type only supports TLSEXT_STATUSTYPE_ocsp type."); - return WOLFSSL_FAILURE; - } - -} - -long wolfSSL_get_tlsext_status_type(WOLFSSL *s) -{ - TLSX* extension; - - if (s == NULL) - return WOLFSSL_FATAL_ERROR; - extension = TLSX_Find(s->extensions, TLSX_STATUS_REQUEST); - return extension != NULL ? WOLFSSL_TLSEXT_STATUSTYPE_ocsp : WOLFSSL_FATAL_ERROR; -} -#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ - #ifndef NO_WOLFSSL_STUB long wolfSSL_get_tlsext_status_exts(WOLFSSL *s, void *arg) { @@ -18773,374 +13752,6 @@ void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx) #ifndef NO_CERTS #ifdef HAVE_PK_CALLBACKS -#ifdef HAVE_ECC -void wolfSSL_CTX_SetEccKeyGenCb(WOLFSSL_CTX* ctx, CallbackEccKeyGen cb) -{ - if (ctx) - ctx->EccKeyGenCb = cb; -} -void wolfSSL_SetEccKeyGenCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->EccKeyGenCtx = ctx; -} -void* wolfSSL_GetEccKeyGenCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->EccKeyGenCtx; - - return NULL; -} -void wolfSSL_CTX_SetEccSignCtx(WOLFSSL_CTX* ctx, void *userCtx) -{ - if (ctx) - ctx->EccSignCtx = userCtx; -} -void* wolfSSL_CTX_GetEccSignCtx(WOLFSSL_CTX* ctx) -{ - if (ctx) - return ctx->EccSignCtx; - - return NULL; -} - -WOLFSSL_ABI -void wolfSSL_CTX_SetEccSignCb(WOLFSSL_CTX* ctx, CallbackEccSign cb) -{ - if (ctx) - ctx->EccSignCb = cb; -} -void wolfSSL_SetEccSignCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->EccSignCtx = ctx; -} -void* wolfSSL_GetEccSignCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->EccSignCtx; - - return NULL; -} - -void wolfSSL_CTX_SetEccVerifyCb(WOLFSSL_CTX* ctx, CallbackEccVerify cb) -{ - if (ctx) - ctx->EccVerifyCb = cb; -} -void wolfSSL_SetEccVerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->EccVerifyCtx = ctx; -} -void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->EccVerifyCtx; - - return NULL; -} - -void wolfSSL_CTX_SetEccSharedSecretCb(WOLFSSL_CTX* ctx, - CallbackEccSharedSecret cb) -{ - if (ctx) - ctx->EccSharedSecretCb = cb; -} -void wolfSSL_SetEccSharedSecretCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->EccSharedSecretCtx = ctx; -} -void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->EccSharedSecretCtx; - - return NULL; -} -#endif /* HAVE_ECC */ - -#ifdef HAVE_ED25519 -void wolfSSL_CTX_SetEd25519SignCb(WOLFSSL_CTX* ctx, CallbackEd25519Sign cb) -{ - if (ctx) - ctx->Ed25519SignCb = cb; -} -void wolfSSL_SetEd25519SignCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->Ed25519SignCtx = ctx; -} -void* wolfSSL_GetEd25519SignCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->Ed25519SignCtx; - - return NULL; -} - -void wolfSSL_CTX_SetEd25519VerifyCb(WOLFSSL_CTX* ctx, CallbackEd25519Verify cb) -{ - if (ctx) - ctx->Ed25519VerifyCb = cb; -} -void wolfSSL_SetEd25519VerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->Ed25519VerifyCtx = ctx; -} -void* wolfSSL_GetEd25519VerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->Ed25519VerifyCtx; - - return NULL; -} -#endif /* HAVE_ED25519 */ - -#ifdef HAVE_CURVE25519 -void wolfSSL_CTX_SetX25519KeyGenCb(WOLFSSL_CTX* ctx, - CallbackX25519KeyGen cb) -{ - if (ctx) - ctx->X25519KeyGenCb = cb; -} -void wolfSSL_SetX25519KeyGenCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->X25519KeyGenCtx = ctx; -} -void* wolfSSL_GetX25519KeyGenCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->X25519KeyGenCtx; - - return NULL; -} - -void wolfSSL_CTX_SetX25519SharedSecretCb(WOLFSSL_CTX* ctx, - CallbackX25519SharedSecret cb) -{ - if (ctx) - ctx->X25519SharedSecretCb = cb; -} -void wolfSSL_SetX25519SharedSecretCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->X25519SharedSecretCtx = ctx; -} -void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->X25519SharedSecretCtx; - - return NULL; -} -#endif /* HAVE_CURVE25519 */ - -#ifdef HAVE_ED448 -void wolfSSL_CTX_SetEd448SignCb(WOLFSSL_CTX* ctx, CallbackEd448Sign cb) -{ - if (ctx) - ctx->Ed448SignCb = cb; -} -void wolfSSL_SetEd448SignCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->Ed448SignCtx = ctx; -} -void* wolfSSL_GetEd448SignCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->Ed448SignCtx; - - return NULL; -} - -void wolfSSL_CTX_SetEd448VerifyCb(WOLFSSL_CTX* ctx, CallbackEd448Verify cb) -{ - if (ctx) - ctx->Ed448VerifyCb = cb; -} -void wolfSSL_SetEd448VerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->Ed448VerifyCtx = ctx; -} -void* wolfSSL_GetEd448VerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->Ed448VerifyCtx; - - return NULL; -} -#endif /* HAVE_ED448 */ - -#ifdef HAVE_CURVE448 -void wolfSSL_CTX_SetX448KeyGenCb(WOLFSSL_CTX* ctx, - CallbackX448KeyGen cb) -{ - if (ctx) - ctx->X448KeyGenCb = cb; -} -void wolfSSL_SetX448KeyGenCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->X448KeyGenCtx = ctx; -} -void* wolfSSL_GetX448KeyGenCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->X448KeyGenCtx; - - return NULL; -} - -void wolfSSL_CTX_SetX448SharedSecretCb(WOLFSSL_CTX* ctx, - CallbackX448SharedSecret cb) -{ - if (ctx) - ctx->X448SharedSecretCb = cb; -} -void wolfSSL_SetX448SharedSecretCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->X448SharedSecretCtx = ctx; -} -void* wolfSSL_GetX448SharedSecretCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->X448SharedSecretCtx; - - return NULL; -} -#endif /* HAVE_CURVE448 */ - -#ifndef NO_RSA -void wolfSSL_CTX_SetRsaSignCb(WOLFSSL_CTX* ctx, CallbackRsaSign cb) -{ - if (ctx) - ctx->RsaSignCb = cb; -} -void wolfSSL_CTX_SetRsaSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) -{ - if (ctx) - ctx->RsaSignCheckCb = cb; -} -void wolfSSL_SetRsaSignCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaSignCtx = ctx; -} -void* wolfSSL_GetRsaSignCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaSignCtx; - - return NULL; -} - - -void wolfSSL_CTX_SetRsaVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) -{ - if (ctx) - ctx->RsaVerifyCb = cb; -} -void wolfSSL_SetRsaVerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaVerifyCtx = ctx; -} -void* wolfSSL_GetRsaVerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaVerifyCtx; - - return NULL; -} - -#ifdef WC_RSA_PSS -void wolfSSL_CTX_SetRsaPssSignCb(WOLFSSL_CTX* ctx, CallbackRsaPssSign cb) -{ - if (ctx) - ctx->RsaPssSignCb = cb; -} -void wolfSSL_CTX_SetRsaPssSignCheckCb(WOLFSSL_CTX* ctx, - CallbackRsaPssVerify cb) -{ - if (ctx) - ctx->RsaPssSignCheckCb = cb; -} -void wolfSSL_SetRsaPssSignCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaPssSignCtx = ctx; -} -void* wolfSSL_GetRsaPssSignCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaPssSignCtx; - - return NULL; -} - -void wolfSSL_CTX_SetRsaPssVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb) -{ - if (ctx) - ctx->RsaPssVerifyCb = cb; -} -void wolfSSL_SetRsaPssVerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaPssVerifyCtx = ctx; -} -void* wolfSSL_GetRsaPssVerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaPssVerifyCtx; - - return NULL; -} -#endif /* WC_RSA_PSS */ - -void wolfSSL_CTX_SetRsaEncCb(WOLFSSL_CTX* ctx, CallbackRsaEnc cb) -{ - if (ctx) - ctx->RsaEncCb = cb; -} -void wolfSSL_SetRsaEncCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaEncCtx = ctx; -} -void* wolfSSL_GetRsaEncCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaEncCtx; - - return NULL; -} - -void wolfSSL_CTX_SetRsaDecCb(WOLFSSL_CTX* ctx, CallbackRsaDec cb) -{ - if (ctx) - ctx->RsaDecCb = cb; -} -void wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaDecCtx = ctx; -} -void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaDecCtx; - - return NULL; -} -#endif /* NO_RSA */ - /* callback for premaster secret generation */ void wolfSSL_CTX_SetGenPreMasterCb(WOLFSSL_CTX* ctx, CallbackGenPreMaster cb) { @@ -19323,31 +13934,6 @@ void wolfSSL_CTX_SetPerformTlsRecordProcessingCb(WOLFSSL_CTX* ctx, #endif /* HAVE_PK_CALLBACKS */ #endif /* NO_CERTS */ -#if defined(HAVE_PK_CALLBACKS) && !defined(NO_DH) -void wolfSSL_CTX_SetDhGenerateKeyPair(WOLFSSL_CTX* ctx, - CallbackDhGenerateKeyPair cb) { - if (ctx) - ctx->DhGenerateKeyPairCb = cb; -} -void wolfSSL_CTX_SetDhAgreeCb(WOLFSSL_CTX* ctx, CallbackDhAgree cb) -{ - if (ctx) - ctx->DhAgreeCb = cb; -} -void wolfSSL_SetDhAgreeCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->DhAgreeCtx = ctx; -} -void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->DhAgreeCtx; - - return NULL; -} -#endif /* HAVE_PK_CALLBACKS && !NO_DH */ - #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_HKDF) void wolfSSL_CTX_SetHKDFExtractCb(WOLFSSL_CTX* ctx, CallbackHKDFExtract cb) @@ -20644,114 +15230,9 @@ VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl) return NULL; } -#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 -is a failure.*/ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO* bio, - WOLFSSL_EVP_PKEY** out) -{ - unsigned char* mem = NULL; - int memSz = 0; - WOLFSSL_EVP_PKEY* key = NULL; - unsigned char* extraBioMem = NULL; - - WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_bio"); - - if (bio == NULL) { - return NULL; - } - (void)out; - - memSz = wolfSSL_BIO_get_len(bio); - if (memSz <= 0) { - WOLFSSL_MSG("wolfSSL_BIO_get_len() failure"); - return NULL; - } - - mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (mem == NULL) { - WOLFSSL_MSG("Malloc failure"); - return NULL; - } - - if (wolfSSL_BIO_read(bio, (unsigned char*)mem, memSz) == memSz) { - int extraBioMemSz; - int derLength; - - /* Determines key type and returns the new private EVP_PKEY object */ - 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; - } - - /* Write extra data back into bio object if necessary. */ - derLength = key->pkey_sz; - extraBioMemSz = (memSz - derLength); - if (extraBioMemSz > 0) { - int i; - int j = 0; - - extraBioMem = (unsigned char *)XMALLOC((size_t)extraBioMemSz, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (extraBioMem == NULL) { - WOLFSSL_MSG("Malloc failure"); - XFREE((unsigned char*)extraBioMem, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - return NULL; - } - - for (i = derLength; i < memSz; i++) { - *(extraBioMem + j) = *(mem + i); - j++; - } - - wolfSSL_BIO_write(bio, extraBioMem, extraBioMemSz); - if (wolfSSL_BIO_get_len(bio) <= 0) { - WOLFSSL_MSG("Failed to write memory to bio"); - XFREE((unsigned char*)extraBioMem, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - return NULL; - } - XFREE((unsigned char*)extraBioMem, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - } - - if (out != NULL) { - *out = key; - } - } - XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - return key; -} -#endif /* !NO_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) - -/* 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 - * on fail */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_EVP(WOLFSSL_EVP_PKEY** out, - unsigned char** in, long inSz) -{ - WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_EVP"); - return d2iGenericKey(out, (const unsigned char**)in, inSz, 1); -} - -#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) || \ @@ -22046,182 +16527,6 @@ long wolfSSL_CTX_set_tlsext_ticket_keys(WOLFSSL_CTX *ctx, } #endif -#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) -#ifdef HAVE_OCSP -/* Not an OpenSSL API. */ -int wolfSSL_get_ocsp_response(WOLFSSL* ssl, byte** response) -{ - *response = ssl->ocspCsrResp[0].buffer; - return ssl->ocspCsrResp[0].length; -} - -/* Not an OpenSSL API. */ -char* wolfSSL_get_ocsp_url(WOLFSSL* ssl) -{ - return ssl->url; -} - -/* Not an OpenSSL API. */ -int wolfSSL_set_ocsp_url(WOLFSSL* ssl, char* url) -{ - if (ssl == NULL) - return WOLFSSL_FAILURE; - - ssl->url = url; - return WOLFSSL_SUCCESS; -} -#endif /* OCSP */ -#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ - -#if defined(HAVE_OCSP) && !defined(NO_ASN_TIME) -int wolfSSL_get_ocsp_producedDate( - WOLFSSL *ssl, - byte *producedDate, - size_t producedDate_space, - int *producedDateFormat) -{ - if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) && - (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME)) - return BAD_FUNC_ARG; - - if ((producedDate == NULL) || (producedDateFormat == NULL)) - return BAD_FUNC_ARG; - - if (XSTRLEN((char *)ssl->ocspProducedDate) >= producedDate_space) - return BUFFER_E; - - XSTRNCPY((char *)producedDate, (const char *)ssl->ocspProducedDate, - producedDate_space); - *producedDateFormat = ssl->ocspProducedDateFormat; - - return 0; -} - -int wolfSSL_get_ocsp_producedDate_tm(WOLFSSL *ssl, struct tm *produced_tm) { - int idx = 0; - - if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) && - (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME)) - return BAD_FUNC_ARG; - - if (produced_tm == NULL) - return BAD_FUNC_ARG; - - if (ExtractDate(ssl->ocspProducedDate, - (unsigned char)ssl->ocspProducedDateFormat, produced_tm, &idx, - MAX_DATE_SZ)) - return 0; - else - return ASN_PARSE_E; -} -#endif - -#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) -int wolfSSL_CTX_get_tlsext_status_cb(WOLFSSL_CTX* ctx, tlsextStatusCb* cb) -{ - if (ctx == NULL || ctx->cm == NULL || cb == NULL) - return WOLFSSL_FAILURE; - -#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) - if (ctx->cm->ocsp_stapling == NULL) - return WOLFSSL_FAILURE; - - *cb = ctx->cm->ocsp_stapling->statusCb; -#else - (void)cb; - *cb = NULL; -#endif - - return WOLFSSL_SUCCESS; - -} - -int wolfSSL_CTX_set_tlsext_status_cb(WOLFSSL_CTX* ctx, tlsextStatusCb cb) -{ - if (ctx == NULL || ctx->cm == NULL) - return WOLFSSL_FAILURE; - -#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) - /* Ensure stapling is on for callback to be used. */ - wolfSSL_CTX_EnableOCSPStapling(ctx); - - if (ctx->cm->ocsp_stapling == NULL) - return WOLFSSL_FAILURE; - - ctx->cm->ocsp_stapling->statusCb = cb; -#else - (void)cb; -#endif - - return WOLFSSL_SUCCESS; -} - -long wolfSSL_CTX_set_tlsext_status_arg(WOLFSSL_CTX* ctx, void* arg) -{ - if (ctx == NULL || ctx->cm == NULL) - return WOLFSSL_FAILURE; - -#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) - /* Ensure stapling is on for callback to be used. */ - wolfSSL_CTX_EnableOCSPStapling(ctx); - - if (ctx->cm->ocsp_stapling == NULL) - return WOLFSSL_FAILURE; - - ctx->cm->ocsp_stapling->statusCbArg = arg; -#else - (void)arg; -#endif - - return WOLFSSL_SUCCESS; -} - -long wolfSSL_get_tlsext_status_ocsp_resp(WOLFSSL *ssl, unsigned char **resp) -{ - if (ssl == NULL || resp == NULL) - return 0; - - *resp = ssl->ocspCsrResp[0].buffer; - return (long)ssl->ocspCsrResp[0].length; -} - -long wolfSSL_set_tlsext_status_ocsp_resp(WOLFSSL *ssl, unsigned char *resp, - int len) -{ - return wolfSSL_set_tlsext_status_ocsp_resp_multi(ssl, resp, len, 0); -} - -int wolfSSL_set_tlsext_status_ocsp_resp_multi(WOLFSSL* ssl, unsigned char *resp, - int len, word32 idx) -{ - if (ssl == NULL || idx >= XELEM_CNT(ssl->ocspCsrResp) || len < 0) - return WOLFSSL_FAILURE; - if (!((resp == NULL) ^ (len > 0))) - return WOLFSSL_FAILURE; - - XFREE(ssl->ocspCsrResp[idx].buffer, NULL, 0); - ssl->ocspCsrResp[idx].buffer = resp; - ssl->ocspCsrResp[idx].length = (word32)len; - - return WOLFSSL_SUCCESS; -} - -#ifndef NO_WOLFSSL_SERVER -void wolfSSL_CTX_set_ocsp_status_verify_cb(WOLFSSL_CTX* ctx, - ocspVerifyStatusCb cb, void* cbArg) -{ - if (ctx != NULL) { - ctx->ocspStatusVerifyCb = cb; - ctx->ocspStatusVerifyCbArg = cbArg; - } -} -#endif -#endif - #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, @@ -23745,144 +18050,6 @@ void wolfSSL_ERR_remove_state(unsigned long id) #endif /* OPENSSL_EXTRA */ -#ifdef OPENSSL_ALL - -#if !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) - -static int bio_get_data(WOLFSSL_BIO* bio, byte** data) -{ - int ret = 0; - byte* mem = NULL; - - ret = wolfSSL_BIO_get_len(bio); - if (ret > 0) { - mem = (byte*)XMALLOC((size_t)ret, bio->heap, DYNAMIC_TYPE_OPENSSL); - if (mem == NULL) { - WOLFSSL_MSG("Memory error"); - ret = MEMORY_E; - } - if (ret >= 0) { - if ((ret = wolfSSL_BIO_read(bio, mem, ret)) <= 0) { - XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); - ret = MEMORY_E; - mem = NULL; - } - } - } - - *data = mem; - - return ret; -} - -/* DER data is PKCS#8 encrypted. */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PKCS8PrivateKey_bio(WOLFSSL_BIO* bio, - WOLFSSL_EVP_PKEY** pkey, - wc_pem_password_cb* cb, - void* ctx) -{ - int ret; - byte* der; - int len; - byte* p; - word32 algId; - WOLFSSL_EVP_PKEY* key; - - if ((len = bio_get_data(bio, &der)) < 0) - return NULL; - - if (cb != NULL) { - char password[NAME_SZ]; - int passwordSz = cb(password, sizeof(password), PEM_PASS_READ, ctx); - if (passwordSz < 0) { - XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); - return NULL; - } - #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("wolfSSL_d2i_PKCS8PrivateKey_bio password", password, - passwordSz); - #endif - - ret = ToTraditionalEnc(der, (word32)len, password, passwordSz, &algId); - if (ret < 0) { - XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); - return NULL; - } - - ForceZero(password, (word32)passwordSz); - #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Check(password, passwordSz); - #endif - } - - p = der; - key = wolfSSL_d2i_PrivateKey_EVP(pkey, &p, len); - XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); - return key; -} - -#endif /* !NO_BIO && !NO_PWDBASED && HAVE_PKCS8 */ - -/* Detect which type of key it is before decoding. */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey(WOLFSSL_EVP_PKEY** pkey, - const unsigned char** pp, - long length) -{ - int ret; - WOLFSSL_EVP_PKEY* key = NULL; - const byte* der = *pp; - word32 idx = 0; - int len = 0; - int cnt = 0; - word32 algId; - word32 keyLen = (word32)length; - - /* Take off PKCS#8 wrapper if found. */ - if ((len = ToTraditionalInline_ex(der, &idx, keyLen, &algId)) >= 0) { - der += idx; - keyLen = (word32)len; - } - idx = 0; - len = 0; - - /* Use the number of elements in the outer sequence to determine key type. - */ - ret = GetSequence(der, &idx, &len, keyLen); - if (ret >= 0) { - word32 end = idx + (word32)len; - while (ret >= 0 && idx < end) { - /* Skip type */ - idx++; - /* Get length and skip over - keeping count */ - len = 0; - ret = GetLength(der, &idx, &len, keyLen); - if (ret >= 0) { - if (idx + (word32)len > end) - ret = ASN_PARSE_E; - else { - idx += (word32)len; - cnt++; - } - } - } - } - - if (ret >= 0) { - int type; - /* ECC includes version, private[, curve][, public key] */ - if (cnt >= 2 && cnt <= 4) - type = WC_EVP_PKEY_EC; - else - type = WC_EVP_PKEY_RSA; - - key = wolfSSL_d2i_PrivateKey(type, pkey, &der, keyLen); - *pp = der; - } - - return key; -} -#endif /* OPENSSL_ALL */ - #ifdef WOLFSSL_STATIC_EPHEMERAL int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr) { diff --git a/src/ssl_api_cert.c b/src/ssl_api_cert.c new file mode 100644 index 0000000000..5871525dc4 --- /dev/null +++ b/src/ssl_api_cert.c @@ -0,0 +1,1740 @@ +/* ssl_api_cert.c + * + * Copyright (C) 2006-2025 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 3 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 + */ + +#include + +#if !defined(WOLFSSL_SSL_API_CERT_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_cert.c is not compiled separately from ssl.c + #endif +#else + +#ifndef NO_CERTS + +/* Set whether mutual authentication is required for connections. + * Server side only. + * + * @param [in] ctx The SSL/TLS CTX object. + * @param [in] req 1 to indicate required and 0 when not. + * @return 0 on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return SIDE_ERROR when not a server. + */ +int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + if (ctx->method->side != WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ctx->mutualAuth = (byte)req; + + return 0; +} + +/* Set whether mutual authentication is required for the connection. + * Server side only. + * + * @param [in] ssl The SSL/TLS object. + * @param [in] req 1 to indicate required and 0 when not. + * @return 0 on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return SIDE_ERROR when not a server + */ +int wolfSSL_mutual_auth(WOLFSSL* ssl, int req) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + if (ssl->options.side != WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ssl->options.mutualAuth = (word16)req; + + return 0; +} + +/* Get the certificate manager from the WOLFSSL_CTX. + * + * @param [in] ctx SSL/TLS CTX object. + * @return Certificate manager object on success. + * @return NULL when ctx is NULL. + */ +WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx) +{ + WOLFSSL_CERT_MANAGER* cm = NULL; + + if (ctx) + cm = ctx->cm; + + return cm; +} + +/* Sets the max chain depth when verifying a certificate chain. + * + * Default depth is set to MAX_CHAIN_DEPTH. + * + * @param [in] ctx WOLFSSL_CTX structure to set depth in + * @param [in] depth max depth + */ +void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth"); + + if ((ctx == NULL) || (depth < 0) || (depth > MAX_CHAIN_DEPTH)) { + WOLFSSL_MSG("Bad depth argument, too large or less than 0"); + } + else { + ctx->verifyDepth = (byte)depth; + } +} + + +/* Get certificate chaining depth of SSL/TLS context object + * + * @param [in] ctx SSL/TLS context object. + * @return Verification depth on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx) +{ + long ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + #ifndef OPENSSL_EXTRA + ret = MAX_CHAIN_DEPTH; + #else + ret = ctx->verifyDepth; + #endif + } + + return ret; +} + +/* Get certificate chaining depth of SSL/TLS object + * + * @param [in] ssl SSL/TLS object. + * @return Verification depth on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +long wolfSSL_get_verify_depth(WOLFSSL* ssl) +{ + long ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + #ifndef OPENSSL_EXTRA + ret = MAX_CHAIN_DEPTH; + #else + ret = ssl->options.verifyDepth; + #endif + } + + return ret; +} + +#if defined(HAVE_RPK) +/* TODO: Change this to use a bitfield. */ + +/* Confirm that all the byte data in the buffer is unique. + * + * @param [in] buf Buffer to check. + * @param [in] len Length of buffer in bytes. + * @return 1 if all the byte data in the buffer is unique. + * @return 0 otherwise. + */ +static int isArrayUnique(const char* buf, size_t len) +{ + size_t i; + /* check the array is unique */ + for (i = 0; i < len - 1; ++i) { + size_t j; + for (j = i + 1; j < len; ++j) { + if (buf[i] == buf[j]) { + return 0; + } + } + } + return 1; +} +/* Set user preference for the {client,server}_cert_type extension. + * + * Takes byte array containing cert types the caller can provide to its peer. + * Cert types are in preferred order in the array. + * + * @param [in] cfg Raw Public Key configuration. + * @param [in] client Indicates whether this is the client side. + * @param [in] buf List of certificate types. + * @param [in] len Length of certificate types. + * @return 1 on success. + * @return BAD_FUNC_ARG when cfg is NULL. + * @return BAD_FUNC_ARG when len is too long. + * @return BAD_FUNC_ARG when buffer values are not unique. + * @return BAD_FUNC_ARG when buffer contains unrecognized certificate type. + */ +static int set_cert_type(RpkConfig* cfg, int client, const char* buf, + int len) +{ + int i; + byte* certTypeCnt; + byte* certTypes; + + /* Validate parameters. */ + if ((cfg == NULL) || (len > (client ? MAX_CLIENT_CERT_TYPE_CNT : + MAX_SERVER_CERT_TYPE_CNT))) { + return BAD_FUNC_ARG; + } + + /* Get preferred certificate types for side. */ + if (client) { + certTypeCnt = &cfg->preferred_ClientCertTypeCnt; + certTypes = cfg->preferred_ClientCertTypes; + } + else { + certTypeCnt = &cfg->preferred_ServerCertTypeCnt; + certTypes = cfg->preferred_ServerCertTypes; + } + /* If no buffer or empty buffer passed in, set the defaults. */ + if ((buf == NULL) || (len == 0)) { + *certTypeCnt = 1; + for (i = 0; i < 2; i++) { + certTypes[i] = WOLFSSL_CERT_TYPE_X509; + } + return 1; + } + + /* Check that the certificate types set are unique. */ + if (!isArrayUnique(buf, (size_t)len)) + return BAD_FUNC_ARG; + + /* Check that the certificate types being set are known and then set. */ + for (i = 0; i < len; i++) { + if ((buf[i] != WOLFSSL_CERT_TYPE_RPK) && + (buf[i] != WOLFSSL_CERT_TYPE_X509)) { + return BAD_FUNC_ARG; + } + certTypes[i] = (byte)buf[i]; + } + *certTypeCnt = len; + + return 1; +} +/* Set the client certificate types against the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] buf List of certificate types. + * @param [in] len Length of certificate types. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return BAD_FUNC_ARG when len is too long. + * @return BAD_FUNC_ARG when buffer values are not unique. + * @return BAD_FUNC_ARG when buffer contains unrecognized certificate type. + */ +int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = set_cert_type(&ctx->rpkConfig, 1, buf, len); + } + + return ret; +} +/* Set the server certificate types against the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] buf List of certificate types. + * @param [in] len Length of certificate types. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return BAD_FUNC_ARG when len is too long. + * @return BAD_FUNC_ARG when buffer values are not unique. + * @return BAD_FUNC_ARG when buffer contains unrecognized certificate type. + */ +int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = set_cert_type(&ctx->rpkConfig, 0, buf, len); + } + + return ret; +} +/* Set the client certificate types against the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] buf List of certificate types. + * @param [in] len Length of certificate types. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return BAD_FUNC_ARG when len is too long. + * @return BAD_FUNC_ARG when buffer values are not unique. + * @return BAD_FUNC_ARG when buffer contains unrecognized certificate type. + */ +int wolfSSL_set_client_cert_type(WOLFSSL* ssl, const char* buf, int len) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = set_cert_type(&ssl->options.rpkConfig, 1, buf, len); + } + + return ret; +} +/* Set the server certificate types against the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] buf List of certificate types. + * @param [in] len Length of certificate types. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return BAD_FUNC_ARG when len is too long. + * @return BAD_FUNC_ARG when buffer values are not unique. + * @return BAD_FUNC_ARG when buffer contains unrecognized certificate type. + */ +int wolfSSL_set_server_cert_type(WOLFSSL* ssl, const char* buf, int len) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = set_cert_type(&ssl->options.rpkConfig, 0, buf, len); + } + + return ret; +} + +/* Get negotiated client certificate type value. + * + * WOLFSSL_CERT_TYPE_UNKNOWN returned when no negotiation has been performed. + * + * @param [in] ssl SSL/TLS object. + * @param [out] tp Certificate type. One of: + * -1: WOLFSSL_CERT_TYPE_UNKNOWN + * 0: WOLFSSL_CERT_TYPE_X509 + * 2: WOLFSSL_CERT_TYPE_RPK + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl or tp is NULL. + */ +int wolfSSL_get_negotiated_client_cert_type(WOLFSSL* ssl, int* tp) +{ + int ret = 1; + + /* Validate parameters. */ + if ((ssl == NULL) || (tp == NULL)) { + ret = BAD_FUNC_ARG; + } + /* Check side. */ + else if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* Check certificate type negotiated. */ + if (ssl->options.rpkState.received_ClientCertTypeCnt == 1) { + *tp = ssl->options.rpkState.received_ClientCertTypes[0]; + } + else { + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + } + /* Check certificate type negotiated. */ + else if (ssl->options.rpkState.sending_ClientCertTypeCnt == 1) { + *tp = ssl->options.rpkState.sending_ClientCertTypes[0]; + } + else { + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + + return ret; +} + +/* Get negotiated server certificate type value. + * + * WOLFSSL_CERT_TYPE_UNKNOWN returned when no negotiation has been performed. + * + * @param [in] ssl SSL/TLS object. + * @param [out] tp Certificate type. One of: + * -1: WOLFSSL_CERT_TYPE_UNKNOWN + * 0: WOLFSSL_CERT_TYPE_X509 + * 2: WOLFSSL_CERT_TYPE_RPK + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl or tp is NULL. + */ +int wolfSSL_get_negotiated_server_cert_type(WOLFSSL* ssl, int* tp) +{ + int ret = 1; + + /* Validate parameters. */ + if ((ssl == NULL) || (tp == NULL)) { + ret = BAD_FUNC_ARG; + } + /* Check side. */ + else if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* Check certificate type negotiated. */ + if (ssl->options.rpkState.received_ServerCertTypeCnt == 1) { + *tp = ssl->options.rpkState.received_ServerCertTypes[0]; + } + else { + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + } + /* Check certificate type negotiated. */ + else if (ssl->options.rpkState.sending_ServerCertTypeCnt == 1) { + *tp = ssl->options.rpkState.sending_ServerCertTypes[0]; + } + else { + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + return ret; +} +#endif /* HAVE_RPK */ + +/* Certificate verification options. */ +typedef struct { + /* Verify the peer certificate. */ + byte verifyPeer:1; + /* No peer certificate verification. */ + byte verifyNone:1; + /* Fail when no peer certificate seen. */ + byte failNoCert:1; + /* Fail when no peer certificate except when PSK handshake performed. */ + byte failNoCertxPSK:1; +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + /* Verify peer certificate post handshake. */ + byte verifyPostHandshake:1; +#endif +} SetVerifyOptions; + +/* Convert the mode flags into certificate verification options. + * + * @param [in] mode Certificate verification mode flags. + * @return Certificate verification options. + */ +static SetVerifyOptions ModeToVerifyOptions(int mode) +{ + SetVerifyOptions opts; + + /* Set the options to the default - none set. */ + XMEMSET(&opts, 0, sizeof(SetVerifyOptions)); + + /* When the mode is not default - set the options. */ + if (mode != WOLFSSL_VERIFY_DEFAULT) { + opts.verifyNone = (mode == WOLFSSL_VERIFY_NONE); + /* When not no verification, set the chosen options. */ + if (!opts.verifyNone) { + opts.verifyPeer = + (mode & WOLFSSL_VERIFY_PEER) != 0; + opts.failNoCertxPSK = + (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) != 0; + opts.failNoCert = + (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) != 0; +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + opts.verifyPostHandshake = + (mode & WOLFSSL_VERIFY_POST_HANDSHAKE) != 0; +#endif + } + } + + return opts; +} + +/* Set the verification options against the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] mode Verification mode options. + * @param [in] verify_callback Verification callback. + */ +WOLFSSL_ABI void wolfSSL_CTX_set_verify(WOLFSSL_CTX* ctx, int mode, + VerifyCallback verify_callback) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_verify"); + + /* Ensure we have an SSL/TLS context to work with. */ + if (ctx != NULL) { + SetVerifyOptions opts = ModeToVerifyOptions(mode); + + /* Set the bitfield options. */ + ctx->verifyNone = opts.verifyNone; + ctx->verifyPeer = opts.verifyPeer; + ctx->failNoCert = opts.failNoCert; + ctx->failNoCertxPSK = opts.failNoCertxPSK; + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + ctx->verifyPostHandshake = opts.verifyPostHandshake; + #endif + + /* Store the user verification callback against the context. */ + ctx->verifyCallback = verify_callback; + } +} + +#ifdef OPENSSL_ALL +/* Set certificate verification callback and context against SSL/TLS context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb Certificate verification callback. + * @param [in] arg Context for certification verification callback. + */ +void wolfSSL_CTX_set_cert_verify_callback(WOLFSSL_CTX* ctx, + CertVerifyCallback cb, void* arg) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_cert_verify_callback"); + + /* Ensure we have an SSL/TLS context to work with. */ + if (ctx != NULL) { + ctx->verifyCertCb = cb; + ctx->verifyCertCbArg = arg; + } +} +#endif + +/* Set the verification options against the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] mode Verification mode options. + * @param [in] verify_callback Verification callback. + */ +void wolfSSL_set_verify(WOLFSSL* ssl, int mode, VerifyCallback verify_callback) +{ + WOLFSSL_ENTER("wolfSSL_set_verify"); + + /* Ensure we have an SSL/TLS object to work with. */ + if (ssl != NULL) { + SetVerifyOptions opts = ModeToVerifyOptions(mode); + + /* Set the bitfield options. */ + ssl->options.verifyNone = opts.verifyNone; + ssl->options.verifyPeer = opts.verifyPeer; + ssl->options.failNoCert = opts.failNoCert; + ssl->options.failNoCertxPSK = opts.failNoCertxPSK; + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + ssl->options.verifyPostHandshake = opts.verifyPostHandshake; + #endif + + /* Store the user verification callback against the object. */ + ssl->verifyCallback = verify_callback; + } +} + +/* Set the certificate verification result for the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] v Verification result. + */ +void wolfSSL_set_verify_result(WOLFSSL *ssl, long v) +{ + WOLFSSL_ENTER("wolfSSL_set_verify_result"); + + /* Ensure we have an SSL/TLS object to work with. */ + if (ssl != NULL) { + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ssl->peerVerifyRet = (unsigned long)v; + #else + WOLFSSL_STUB("wolfSSL_set_verify_result"); + (void)v; + #endif + } +} + +/* Store user ctx for verify callback into SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] userCtx User context for verify callback. + */ +void wolfSSL_CTX_SetCertCbCtx(WOLFSSL_CTX* ctx, void* userCtx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetCertCbCtx"); + + /* Validate parameters. */ + if (ctx != NULL) { + ctx->verifyCbCtx = userCtx; + } +} + +/* Store user ctx for verify callback into SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx User context for verify callback. + */ +void wolfSSL_SetCertCbCtx(WOLFSSL* ssl, void* ctx) +{ + WOLFSSL_ENTER("wolfSSL_SetCertCbCtx"); + + /* Validate parameters. */ + if (ssl != NULL) { + ssl->verifyCbCtx = ctx; + } +} + + + +/* Store context CA Cache addition callback into SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] userCtx User context for verify callback. + */ +void wolfSSL_CTX_SetCACb(WOLFSSL_CTX* ctx, CallbackCACache cb) +{ + /* Validate parameters. */ + if ((ctx != NULL) && (ctx->cm != NULL)) { + ctx->cm->caCacheCallback = cb; + } +} + +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_POST_HANDSHAKE_AUTH) +/* For TLS v1.3, send authentication messages after handshake completes. + * + * @return 1 on success. + * @return UNSUPPORTED_PROTO_VERSION when not a TLSv1.3 handshake. + * @return 0 on other failure. + */ +int wolfSSL_verify_client_post_handshake(WOLFSSL* ssl) +{ + int ret; + + /* Do request of certificate. */ + ret = wolfSSL_request_certificate(ssl); + if (ret != 1) { + /* Special logging for wrong protocol version. */ + if ((ssl != NULL) && !IsAtLeastTLSv1_3(ssl->version)) { + WOLFSSL_ERROR(UNSUPPORTED_PROTO_VERSION); + } + else { + /* Other errors - return 0. */ + WOLFSSL_ERROR(ret); + } + ret = 0; + } + + return ret; +} + +/* Set whether handshakes from this SSL/TLS context allow auth post handshake. + * + * @param [in] ctx SSL/TLS context. + * @param [in] val Whether to allow post handshake authentication. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_set_post_handshake_auth(WOLFSSL_CTX* ctx, int val) +{ + int ret; + + /* Try to allow - really just checking conditions. */ + if (wolfSSL_CTX_allow_post_handshake_auth(ctx) == 0) { + /* Set value as a bit. */ + ctx->postHandshakeAuth = (val != 0); + ret = 1; + } + else { + ret = 0; + } + + return ret; +} +/* Set whether handshakes with this SSL/TLS object allow auth post handshake. + * + * @param [in] ctx SSL/TLS context. + * @param [in] val Whether to allow post handshake authentication. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_set_post_handshake_auth(WOLFSSL* ssl, int val) +{ + int ret; + + /* Try to allow - really just checking conditions. */ + if (wolfSSL_allow_post_handshake_auth(ssl) == 0) { + /* Set value as a bit. */ + ssl->options.postHandshakeAuth = (val != 0); + ret = 1; + } + else { + ret = 0; + } + + return ret; +} +#endif /* OPENSSL_EXTRA && WOLFSSL_TLS13 && WOLFSSL_POST_HANDSHAKE_AUTH */ + +#if defined(PERSIST_CERT_CACHE) + +#if !defined(NO_FILESYSTEM) + +/* Persist certificate cache in SSL/TLS context to file. + * + * @param [in] ctx SSL/TLS context. + * @param [in] fname Filename so store certificate cache to. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or fname is NULL. + * @return Other values on failure. + */ +int wolfSSL_CTX_save_cert_cache(WOLFSSL_CTX* ctx, const char* fname) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_save_cert_cache"); + + /* Validate parameters. */ + if ((ctx == NULL) || (fname == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + /* Save certificate cache. */ + ret = CM_SaveCertCache(ctx->cm, fname); + } + + return ret; +} + + +/* Load certificate cache into SSL/TLS context from file. + * + * @param [in] ctx SSL/TLS context. + * @param [in] fname Filename so store certificate cache to. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or fname is NULL. + * @return Other values on failure. + */ +int wolfSSL_CTX_restore_cert_cache(WOLFSSL_CTX* ctx, const char* fname) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_restore_cert_cache"); + + /* Validate parameters. */ + if ((ctx == NULL) || (fname == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + /* Restore certificate cache. */ + ret = CM_RestoreCertCache(ctx->cm, fname); + } + + return ret; +} + +#endif /* NO_FILESYSTEM */ + +/* Persist certificate cache in SSL/TLS context to memory. + * + * @param [in] ctx SSL/TLS context. + * @param [in] mem Memory to fill with certificate cache. + * @param [in] sz Size of memory to fill in bytes. + * @param [out] used The number of bytes of memory used. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx, mem or used is NULL. + * @return BAD_FUNC_ARG when sz is less than or equal to zero. + * @return Other values on failure. + */ +int wolfSSL_CTX_memsave_cert_cache(WOLFSSL_CTX* ctx, void* mem, + int sz, int* used) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_memsave_cert_cache"); + + /* Validate parameters. */ + if ((ctx == NULL) || (mem == NULL) || (used == NULL) || (sz <= 0)) { + ret = BAD_FUNC_ARG; + } + else { + /* Persist certificate change to memory. */ + ret = CM_MemSaveCertCache(ctx->cm, mem, sz, used); + } + + return ret; +} + + +/* Load certificate cache into SSL/TLS context from memory. + * + * @param [in] ctx SSL/TLS context. + * @param [in] mem Memory with certificate cache. + * @param [in] sz Size of certificate cache in bytes + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or mem is NULL. + * @return BAD_FUNC_ARG when sz is less than or equal to zero. + * @return Other values on failure. + */ +int wolfSSL_CTX_memrestore_cert_cache(WOLFSSL_CTX* ctx, const void* mem, int sz) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_memrestore_cert_cache"); + + /* Validate parameters. */ + if ((ctx == NULL) || (mem == NULL) || (sz <= 0)) { + ret = BAD_FUNC_ARG; + } + else { + /* Restore certificate cache. */ + ret = CM_MemRestoreCertCache(ctx->cm, mem, sz); + } + + return ret; +} + + +/* Get size of certificate cache when persisted. + * + * @param [in] ctx SSL/TLS context. + * @return Size of certificate cache when pesisted in bytes. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_get_cert_cache_memsize(WOLFSSL_CTX* ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_get_cert_cache_memsize"); + + /* Validate parameter. */ + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Get size. */ + ret = CM_GetCertCacheMemSize(ctx->cm); + } + + return ret; +} + +#endif /* PERSIST_CERT_CACHE */ + +/* Unload certificates and keys that the SSL/TLS object owns. + * + * The WOLFSSL_CTX referenced is untouched. + * + * @param [in] ssl SSL/TLS object. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) +{ + int ret = 1; + + /* Validate parameter. */ + if (ssl == NULL) { + WOLFSSL_MSG("Null function arg"); + ret = BAD_FUNC_ARG; + } + else { + if (ssl->buffers.weOwnCert && !ssl->keepCert) { + WOLFSSL_MSG("Unloading cert"); + FreeDer(&ssl->buffers.certificate); + #ifdef KEEP_OUR_CERT + wolfSSL_X509_free(ssl->ourCert); + ssl->ourCert = NULL; + #endif + ssl->buffers.weOwnCert = 0; + } + + if (ssl->buffers.weOwnCertChain) { + WOLFSSL_MSG("Unloading cert chain"); + FreeDer(&ssl->buffers.certChain); + ssl->buffers.weOwnCertChain = 0; + } + + if (ssl->buffers.weOwnKey) { + WOLFSSL_MSG("Unloading key"); + ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); + FreeDer(&ssl->buffers.key); + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + FreeDer(&ssl->buffers.keyMask); + #endif + ssl->buffers.weOwnKey = 0; + } + + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->buffers.weOwnAltKey) { + WOLFSSL_MSG("Unloading alt key"); + ForceZero(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length); + FreeDer(&ssl->buffers.altKey); + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + FreeDer(&ssl->buffers.altKeyMask); + #endif + ssl->buffers.weOwnAltKey = 0; + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + } + + return ret; +} + +/* Unload CAs from the certificate manager of the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or ctx->cm is NULL. + * @return BAD_MUTEX_E when locking fails. + */ +int wolfSSL_CTX_UnloadCAs(WOLFSSL_CTX* ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_UnloadCAs"); + + /* Validate parameter. */ + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = wolfSSL_CertManagerUnloadCAs(ctx->cm); + } + + return ret; +} + +/* Unload Intermediate CAs from the certificate manager of the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or ctx->cm is NULL. + * @return BAD_MUTEX_E when locking fails. + */ +int wolfSSL_CTX_UnloadIntermediateCerts(WOLFSSL_CTX* ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_UnloadIntermediateCerts"); + + /* Validate parameter. */ + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + /* Lock reference count. */ + else if ((ret = wolfSSL_RefWithMutexLock(&ctx->ref)) == 0) { + /* Must not have another reference for this operation to be done. */ + if (ctx->ref.count > 1) { + WOLFSSL_MSG("ctx object must have a ref count of 1 before " + "unloading intermediate certs"); + ret = BAD_STATE_E; + } + else { + ret = wolfSSL_CertManagerUnloadIntermediateCerts(ctx->cm); + } + + /* Unlock reference count. */ + if (wolfSSL_RefWithMutexUnlock(&ctx->ref) != 0) { + WOLFSSL_MSG("Failed to unlock mutex!"); + } + } + + return ret; +} + + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* Unload trusted peers from the certificate manager of the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or ctx->cm is NULL. + * @return BAD_MUTEX_E when locking fails. + */ +int wolfSSL_CTX_Unload_trust_peers(WOLFSSL_CTX* ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); + + /* Validate parameter. */ + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = wolfSSL_CertManagerUnload_trust_peers(ctx->cm); + } + + return ret; +} + +#ifdef WOLFSSL_LOCAL_X509_STORE +/* Unload trusted peers from the certificate manager of the SSL/TLS object. + * + * @param [in] ctx SSL/TLS context. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return BAD_MUTEX_E when locking fails. + */ +int wolfSSL_Unload_trust_peers(WOLFSSL* ssl) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); + + /* Validate parameter. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Output message when certificate manager for object. */ + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerUnload_trust_peers(SSL_CM(ssl)); + } + + return ret; +} +#endif /* WOLFSSL_LOCAL_X509_STORE */ +#endif /* WOLFSSL_TRUST_PEER_CERT */ + +#ifndef WOLFSSL_NO_CA_NAMES +/* Add a CA certificate to the list of CA names. + * + * @param [in, out] ca_names List of CA certificate subject names. + * @param [in] x509 X509 certificate. + * @return 1 on success. + * @return 0 on failure. + */ +static int add_to_ca_names_list(WOLFSSL_STACK* ca_names, WOLFSSL_X509* x509) +{ + int ret = 1; + WOLFSSL_X509_NAME *nameCopy = NULL; + + nameCopy = wolfSSL_X509_NAME_dup(wolfSSL_X509_get_subject_name(x509)); + if (nameCopy == NULL) { + WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); + ret = 0; + } + else if (wolfSSL_sk_X509_NAME_push(ca_names, nameCopy) <= 0) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); + wolfSSL_X509_NAME_free(nameCopy); + ret = 0; + } + + return ret; +} + +/* Add a client's CA to SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] x509 X509 certificate. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_add_client_CA(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_CTX_add_client_CA"); + + /* Validate parameters. */ + if ((ctx == NULL) || (x509 == NULL)) { + WOLFSSL_MSG("Bad argument"); + ret = 0; + } + /* Create a stack of names if not present. */ + else if (ctx->client_ca_names == NULL) { + ctx->client_ca_names = wolfSSL_sk_X509_NAME_new(NULL); + if (ctx->client_ca_names == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); + ret = 0; + } + } + if (ret == 1) { + /* Add certificate's subject name to client CA name list. */ + ret = add_to_ca_names_list(ctx->client_ca_names, x509); + } + + return ret; +} + +/* Add a client's CA to SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] x509 X509 certificate. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_add_client_CA(WOLFSSL* ssl, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_add_client_CA"); + + /* Validate parameters. */ + if ((ssl == NULL) || (x509 == NULL)) { + WOLFSSL_MSG("Bad argument"); + ret = 0; + } + /* Create a stack of names if not present. */ + else if (ssl->client_ca_names == NULL) { + ssl->client_ca_names = wolfSSL_sk_X509_NAME_new(NULL); + if (ssl->client_ca_names == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); + ret = 0; + } + } + if (ret == 1) { + /* Add certificate's subject name to client CA name list. */ + ret = add_to_ca_names_list(ssl->client_ca_names, x509); + } + + return ret; +} + +/* Add a CA to SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] x509 X509 certificate. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_add1_to_CA_list(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_CTX_add1_to_CA_list"); + + /* Validate parameters. */ + if ((ctx == NULL) || (x509 == NULL)) { + WOLFSSL_MSG("Bad argument"); + ret = 0; + } + /* Create a stack of names if not present. */ + else if (ctx->ca_names == NULL) { + ctx->ca_names = wolfSSL_sk_X509_NAME_new(NULL); + if (ctx->ca_names == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); + ret = 0; + } + } + if (ret == 1) { + /* Add certificate's subject name to CA name list. */ + ret = add_to_ca_names_list(ctx->ca_names, x509); + } + + return ret; +} + +/* Add a CA to SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] x509 X509 certificate. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_add1_to_CA_list(WOLFSSL* ssl, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_add1_to_CA_list"); + + /* Validate parameters. */ + if ((ssl == NULL) || (x509 == NULL)) { + WOLFSSL_MSG("Bad argument"); + ret = 0; + } + /* Create a stack of names if not present. */ + else if (ssl->ca_names == NULL) { + ssl->ca_names = wolfSSL_sk_X509_NAME_new(NULL); + if (ssl->ca_names == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); + ret = 0; + } + } + if (ret == 1) { + /* Add certificate's subject name to CA name list. */ + ret = add_to_ca_names_list(ssl->ca_names, x509); + } + + return ret; +} + +/* Set the client CA list into SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] names List of CA subject names. + */ +void wolfSSL_CTX_set_client_CA_list(WOLFSSL_CTX* ctx, + WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_client_CA_list"); + + /* Validate parameters. */ + if (ctx != NULL) { + /* Dispose of any existing list. */ + wolfSSL_sk_X509_NAME_pop_free(ctx->client_ca_names, NULL); + /* Take ownership of names list. */ + ctx->client_ca_names = names; + } +} + +/* Set the client CA list into SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] names List of CA subject names. + */ +void wolfSSL_set_client_CA_list(WOLFSSL* ssl, + WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) +{ + WOLFSSL_ENTER("wolfSSL_set_client_CA_list"); + + /* Validate parameters. */ + if (ssl != NULL) { + /* Dispose of any existing list if the object owns it. */ + if (ssl->client_ca_names != ssl->ctx->client_ca_names) { + wolfSSL_sk_X509_NAME_pop_free(ssl->client_ca_names, NULL); + } + /* Take ownership of names list. */ + ssl->client_ca_names = names; + } +} + +/* Set the CA list into SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] names List of CA subject names. + */ +void wolfSSL_CTX_set0_CA_list(WOLFSSL_CTX* ctx, + WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set0_CA_list"); + + /* Validate parameters. */ + if (ctx != NULL) { + /* Dispose of any existing list. */ + wolfSSL_sk_X509_NAME_pop_free(ctx->ca_names, NULL); + /* Take ownership of names list. */ + ctx->ca_names = names; + } +} + +/* Set the client CA list into SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] names List of CA subject names. + */ +void wolfSSL_set0_CA_list(WOLFSSL* ssl, + WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) +{ + WOLFSSL_ENTER("wolfSSL_set0_CA_list"); + + /* Validate parameters. */ + if (ssl != NULL) { + /* Dispose of any existing list if the object owns it. */ + if (ssl->ca_names != ssl->ctx->ca_names) { + wolfSSL_sk_X509_NAME_pop_free(ssl->ca_names, NULL); + } + /* Take ownership of names list. */ + ssl->ca_names = names; + } +} + +/* Get the list of client CA subject names from the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return List of CA subject names on success. + * @return NULL when ctx is NULL or no names set. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_CTX_get_client_CA_list( + const WOLFSSL_CTX *ctx) +{ + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + + WOLFSSL_ENTER("wolfSSL_CTX_get_client_CA_list"); + + /* Validate parameter. */ + if (ctx == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_CTX_get_client_CA_list"); + ret = NULL; + } + else { + ret = ctx->client_ca_names; + } + + return ret; +} + +/* Get the list of client CA subject names from the SSL/TLS object. + * + * On server side: returns the CAs set via *_set_client_CA_list(); + * On client side: returns the CAs received from server -- same as + * wolfSSL_get0_peer_CA_list(). + * + * @param [in] ssl SSL/TLS object. + * @return List of CA subject names on success. + * @return NULL when ssl is NULL or no names set. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get_client_CA_list(const WOLFSSL* ssl) +{ + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + + WOLFSSL_ENTER("wolfSSL_get_client_CA_list"); + + /* Validate parameter. */ + if (ssl == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_get_client_CA_list"); + ret = NULL; + } + /* Client side return peer CA names. */ + else if (ssl->options.side == WOLFSSL_CLIENT_END) { + ret = ssl->peer_ca_names; + } + /* Server side return client CA names. */ + else { + ret = SSL_CLIENT_CA_NAMES(ssl); + } + + return ret; +} + +/* Get the list of CA subject names from the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return List of CA subject names on success. + * @return NULL when ctx is NULL or no names set. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_CTX_get0_CA_list( + const WOLFSSL_CTX *ctx) +{ + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + + WOLFSSL_ENTER("wolfSSL_CTX_get0_CA_list"); + + /* Validate parameter. */ + if (ctx == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_CTX_get0_CA_list"); + ret = NULL; + } + else { + /* Return list directly. */ + ret = ctx->ca_names; + } + + return ret; +} + +/* Get the list of CA subject names from the SSL/TLS object. + * + * Always returns the CA's set via *_set0_CA_list. + * + * @param [in] ssl SSL/TLS object. + * @return List of CA subject names on success. + * @return NULL when ssl is NULL or no names set. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get0_CA_list(const WOLFSSL *ssl) +{ + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + + WOLFSSL_ENTER("wolfSSL_get0_CA_list"); + + /* Validate parameter. */ + if (ssl == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_get0_CA_list"); + ret = NULL; + } + else { + /* Return list directly from object, if available, or context. */ + ret = SSL_CA_NAMES(ssl); + } + + return ret; +} + +/* Get the list of peer CA subject names from the SSL/TLS object. + * + * Always returns the CA's received from the peer. + * + * @param [in] ssl SSL/TLS object. + * @return List of CA subject names on success. + * @return NULL when ssl is NULL or no names set. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get0_peer_CA_list(const WOLFSSL* ssl) +{ + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + + WOLFSSL_ENTER("wolfSSL_get0_peer_CA_list"); + + /* Validate parameter. */ + if (ssl == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_get0_peer_CA_list"); + ret = NULL; + } + else { + /* Return list directly from object. */ + ret = ssl->peer_ca_names; + } + + return ret; +} + +#ifndef NO_BIO +/* Load the client CA subject names from file. + * + * @param [in] fname Name of file containing client CA certificates. + * @return A list of certificate names on success. + * @return NULL on error. + */ +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 + * that case. If OPENSSL_EXTRA is enabled, go ahead and include + * the function. */ +#ifdef OPENSSL_EXTRA + WOLFSSL_STACK *list = NULL; + WOLFSSL_BIO* bio = NULL; + WOLFSSL_X509 *cert = NULL; + int err = 0; + unsigned long error; + + WOLFSSL_ENTER("wolfSSL_load_client_CA_file"); + + /* Create a file BIO to read. */ + bio = wolfSSL_BIO_new_file(fname, "rb"); + if (bio == NULL) { + WOLFSSL_MSG("wolfSSL_BIO_new_file error"); + err = 1; + } + + if (!err) { + /* Create an empty list of certificate names - default compare cb. */ + list = wolfSSL_sk_X509_NAME_new(NULL); + if (list == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); + err = 1; + } + } + + /* Read each certificate in the chain out of the file. */ + while (!err && wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL) { + WOLFSSL_X509_NAME *nameCopy; + + /* Need a persistent copy of the subject name. */ + nameCopy = wolfSSL_X509_NAME_dup(wolfSSL_X509_get_subject_name(cert)); + if (nameCopy == NULL) { + WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); + err = 1; + } + else { + /* Original certificate will be freed - clear reference to it. */ + nameCopy->x509 = NULL; + + if (wolfSSL_sk_X509_NAME_push(list, nameCopy) <= 0) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); + /* Name not stored - free now as only place needing to. */ + wolfSSL_X509_NAME_free(nameCopy); + err = 1; + } + } + + /* Dispose of certificate read. */ + wolfSSL_X509_free(cert); + cert = NULL; + } + + /* Clear any error due to no more certificates. */ + CLEAR_ASN_NO_PEM_HEADER_ERROR(error); + + if (err) { + /* Error occurred so return NULL. */ + wolfSSL_sk_X509_NAME_pop_free(list, NULL); + list = NULL; + } + wolfSSL_BIO_free(bio); + return list; +#else + (void)fname; + return NULL; +#endif +} +#endif /* !NO_BIO */ +#endif /* WOLFSSL_NO_CA_NAMES */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/* Get the certificate store of the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return X509 certificate store on success. + * @return NULL when ctx is NULL. + */ +WOLFSSL_X509_STORE* wolfSSL_CTX_get_cert_store(const WOLFSSL_CTX* ctx) +{ + WOLFSSL_X509_STORE* ret; + + /* Validate parameter. */ + if (ctx == NULL) { + ret = NULL; + } + /* Use pointer to external store if set. */ + else if (ctx->x509_store_pt != NULL) { + ret = ctx->x509_store_pt; + } + else { + /* Return reference to store that is part of the context. */ + ret = (WOLFSSL_X509_STORE*)&ctx->x509_store; + } + + return ret; +} + +/* Set the certificate store of the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return X509 certificate store on success. + * @return NULL when ctx is NULL. + */ +void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_cert_store"); + + /* Validate parameters. */ + if ((ctx == NULL) || (str == NULL) || (ctx->cm == str->cm)) { + WOLFSSL_MSG("Invalid parameters"); + } + else if (wolfSSL_CertManager_up_ref(str->cm) != 1) { + WOLFSSL_MSG("wolfSSL_CertManager_up_ref error"); + } + else { + /* Free any cert manager. */ + wolfSSL_CertManagerFree(ctx->cm); + /* Free any external store. */ + wolfSSL_X509_STORE_free(ctx->x509_store_pt); + /* Set the certificate manager into context. */ + ctx->cm = str->cm; + ctx->x509_store.cm = str->cm; + ctx->x509_store.cache = str->cache; + /* Take ownership of store and free it with context free. */ + ctx->x509_store_pt = str; + /* Context has ownership and free it with context free. */ + ctx->cm->x509_store_p = ctx->x509_store_pt; + } +} + +#ifdef OPENSSL_ALL +/* Set certificate store into SSL/TLS context but don't take ownership. + * + * @param [in] ctx SSL/TLS context. + * @param [in] str Certificate store. + * @return 1 on success. + * @return 0 when ctx or str is NULL or on other error. + */ +int wolfSSL_CTX_set1_verify_cert_store(WOLFSSL_CTX* ctx, + WOLFSSL_X509_STORE* str) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_set1_verify_cert_store"); + + /* Validate parameters. */ + if ((ctx == NULL) || (str == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = 0; + } + /* Nothing to do when store being set is the same as existing in context. */ + else if (str == CTX_STORE(ctx)) { + ret = 1; + } + /* Increase ref so we can store pointer and free it with context free. */ + else if (wolfSSL_X509_STORE_up_ref(str) != 1) { + WOLFSSL_MSG("wolfSSL_X509_STORE_up_ref error"); + ret = 0; + } + else { + /* Free any external store. */ + wolfSSL_X509_STORE_free(ctx->x509_store_pt); + /* Ref count increased - store pointer and free with context free. */ + ctx->x509_store_pt = str; + ret = 1; + } + + return ret; +} +#endif + + +/* Set certificate store into SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] str Certificate store. + * @param [in] ref Take a reference to passed in certificate store. + * @return 1 on success. + * @return 0 when ssl or str is NULL or on other error. + */ +static int wolfssl_set_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str, + int ref) +{ + int ret; + + WOLFSSL_ENTER("wolfssl_set_verify_cert_store"); + + /* Validate parameters. */ + if ((ssl == NULL) || (str == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = 0; + } + /* Nothing to do when store being set is the same as existing in object. */ + else if (str == SSL_STORE(ssl)) { + ret = 1; + } + else if (ref && (wolfSSL_X509_STORE_up_ref(str) != 1)) { + WOLFSSL_MSG("wolfSSL_X509_STORE_up_ref error"); + ret = 0; + } + else { + /* Free any external store. */ + wolfSSL_X509_STORE_free(ssl->x509_store_pt); + if (str == ssl->ctx->x509_store_pt) { + /* Setting ctx store - just revert to using that instead. */ + ssl->x509_store_pt = NULL; + } + else { + /* Ref count increased - store pointer and free with object free. */ + ssl->x509_store_pt = str; + } + ret = 1; + } + + return ret; +} + +/* Set certificate store into SSL/TLS object and take ownership. + * + * @param [in] ssl SSL/TLS object. + * @param [in] str Certificate store. + * @return 1 on success. + * @return 0 when ssl or str is NULL or on other error. + */ +int wolfSSL_set0_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str) +{ + WOLFSSL_ENTER("wolfSSL_set0_verify_cert_store"); + + return wolfssl_set_verify_cert_store(ssl, str, 0); +} + +/* Set certificate store into SSL/TLS object but don't take ownership. + * + * @param [in] ssl SSL/TLS object. + * @param [in] str Certificate store. + * @return 1 on success. + * @return 0 when ssl or str is NULL or on other error. + */ +int wolfSSL_set1_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str) +{ + WOLFSSL_ENTER("wolfSSL_set1_verify_cert_store"); + + return wolfssl_set_verify_cert_store(ssl, str, 1); +} +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + +/* OPENSSL_EXTRA is needed for wolfSSL_X509_d21 function + KEEP_OUR_CERT is to ensure ability to return ssl certificate */ +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ + defined(KEEP_OUR_CERT) +/* Get the certificate in the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return Certificate being sent to peer. + * @return NULL when ctx is NULL, no certificate set or on other error. + */ +WOLFSSL_X509* wolfSSL_CTX_get0_certificate(WOLFSSL_CTX* ctx) +{ + WOLFSSL_X509* ret = NULL; + + /* Validate parameters. */ + if (ctx == NULL) { + WOLFSSL_MSG("Invalid parameter"); + } + else { + /* Check if we already have a certificate allocated. */ + if (ctx->ourCert == NULL) { + /* Check if there is a raw certificate. */ + if (ctx->certificate == NULL) { + WOLFSSL_MSG("Ctx Certificate buffer not set!"); + } + #ifndef WOLFSSL_X509_STORE_CERTS + else { + /* Create a certificate object from raw data. */ + ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, + ctx->certificate->buffer, (int)ctx->certificate->length, + ctx->heap); + ctx->ownOurCert = 1; + } + #endif + } + /* Return certificate cached against SSL/TLS context. */ + ret = ctx->ourCert; + } + + return ret; +} + +/* Get the certificate in the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Certificate being sent to peer. + * @return NULL when ssl is NULL, no certificate set or on other error. + */ +WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) +{ + WOLFSSL_X509* ret = NULL; + + /* Validate parameters. */ + if (ssl == NULL) { + WOLFSSL_MSG("Invalid parameter"); + } + /* Use certificate in SSL/TLS object if we own it. */ + else if (ssl->buffers.weOwnCert) { + /* Check if we already have a certificate allocated. */ + if (ssl->ourCert == NULL) { + /* We own certificate so this should never happen. */ + if (ssl->buffers.certificate == NULL) { + WOLFSSL_MSG("Certificate buffer not set!"); + } + #ifndef WOLFSSL_X509_STORE_CERTS + else { + /* Create a certificate object from raw data. */ + ssl->ourCert = wolfSSL_X509_d2i_ex(NULL, + ssl->buffers.certificate->buffer, + (int)ssl->buffers.certificate->length, ssl->heap); + } + #endif + } + /* Return certificate cached against SSL/TLS object. */ + ret = ssl->ourCert; + } + else { + /* Use any certificate in SSL/TLS context instead. */ + ret = wolfSSL_CTX_get0_certificate(ssl->ctx); + } + + return ret; +} +#endif /* (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) && KEEP_OUR_CERT */ + +#endif /* !NO_CERTS */ + +#endif /* !WOLFSSL_SSL_API_CERT_INCLUDED */ diff --git a/src/ssl_api_crl_ocsp.c b/src/ssl_api_crl_ocsp.c new file mode 100644 index 0000000000..b0791dc6a9 --- /dev/null +++ b/src/ssl_api_crl_ocsp.c @@ -0,0 +1,634 @@ +/* ssl_api_crl_ocsp.c + * + * Copyright (C) 2006-2025 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 3 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 + */ + +#include + +#if !defined(WOLFSSL_SSL_API_CRL_OCSP_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_crl_ocsp.c is not compiled separately from ssl.c + #endif +#else + +#ifndef NO_CERTS + +#ifdef HAVE_CRL + +int wolfSSL_CTX_LoadCRLBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, + long sz, int type) +{ + WOLFSSL_ENTER("wolfSSL_CTX_LoadCRLBuffer"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + return wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, buff, sz, type); +} + + +int wolfSSL_LoadCRLBuffer(WOLFSSL* ssl, const unsigned char* buff, + long sz, int type) +{ + WOLFSSL_ENTER("wolfSSL_LoadCRLBuffer"); + + if (ssl == NULL || ssl->ctx == NULL) + return BAD_FUNC_ARG; + + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerLoadCRLBuffer(SSL_CM(ssl), buff, sz, type); +} + +int wolfSSL_EnableCRL(WOLFSSL* ssl, int options) +{ + WOLFSSL_ENTER("wolfSSL_EnableCRL"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerEnableCRL(SSL_CM(ssl), options); + } + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_DisableCRL(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_DisableCRL"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerDisableCRL(SSL_CM(ssl)); + } + else + return BAD_FUNC_ARG; +} + +#ifndef NO_FILESYSTEM +int wolfSSL_LoadCRL(WOLFSSL* ssl, const char* path, int type, int monitor) +{ + WOLFSSL_ENTER("wolfSSL_LoadCRL"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerLoadCRL(SSL_CM(ssl), path, type, monitor); + } + else + return BAD_FUNC_ARG; +} + +int wolfSSL_LoadCRLFile(WOLFSSL* ssl, const char* file, int type) +{ + WOLFSSL_ENTER("wolfSSL_LoadCRLFile"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerLoadCRLFile(SSL_CM(ssl), file, type); + } + else + return BAD_FUNC_ARG; +} +#endif + +int wolfSSL_SetCRL_Cb(WOLFSSL* ssl, CbMissingCRL cb) +{ + WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerSetCRL_Cb(SSL_CM(ssl), cb); + } + else + return BAD_FUNC_ARG; +} + +int wolfSSL_SetCRL_ErrorCb(WOLFSSL* ssl, crlErrorCb cb, void* ctx) +{ + WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerSetCRL_ErrorCb(SSL_CM(ssl), cb, ctx); + } + else + return BAD_FUNC_ARG; +} + +#ifdef HAVE_CRL_IO +int wolfSSL_SetCRL_IOCb(WOLFSSL* ssl, CbCrlIO cb) +{ + WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerSetCRL_IOCb(SSL_CM(ssl), cb); + } + else + return BAD_FUNC_ARG; +} +#endif + +int wolfSSL_CTX_EnableCRL(WOLFSSL_CTX* ctx, int options) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableCRL"); + if (ctx) + return wolfSSL_CertManagerEnableCRL(ctx->cm, options); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_DisableCRL(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableCRL"); + if (ctx) + return wolfSSL_CertManagerDisableCRL(ctx->cm); + else + return BAD_FUNC_ARG; +} + + +#ifndef NO_FILESYSTEM +int wolfSSL_CTX_LoadCRL(WOLFSSL_CTX* ctx, const char* path, + int type, int monitor) +{ + WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); + if (ctx) + return wolfSSL_CertManagerLoadCRL(ctx->cm, path, type, monitor); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_LoadCRLFile(WOLFSSL_CTX* ctx, const char* file, + int type) +{ + WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); + if (ctx) + return wolfSSL_CertManagerLoadCRLFile(ctx->cm, file, type); + else + return BAD_FUNC_ARG; +} +#endif + + +int wolfSSL_CTX_SetCRL_Cb(WOLFSSL_CTX* ctx, CbMissingCRL cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_Cb"); + if (ctx) + return wolfSSL_CertManagerSetCRL_Cb(ctx->cm, cb); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_SetCRL_ErrorCb(WOLFSSL_CTX* ctx, crlErrorCb cb, void* cbCtx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_ErrorCb"); + if (ctx) + return wolfSSL_CertManagerSetCRL_ErrorCb(ctx->cm, cb, cbCtx); + else + return BAD_FUNC_ARG; +} + +#ifdef HAVE_CRL_IO +int wolfSSL_CTX_SetCRL_IOCb(WOLFSSL_CTX* ctx, CbCrlIO cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_IOCb"); + if (ctx) + return wolfSSL_CertManagerSetCRL_IOCb(ctx->cm, cb); + else + return BAD_FUNC_ARG; +} +#endif + +#endif /* HAVE_CRL */ + + +#ifdef HAVE_OCSP +int wolfSSL_EnableOCSP(WOLFSSL* ssl, int options) +{ + WOLFSSL_ENTER("wolfSSL_EnableOCSP"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerEnableOCSP(SSL_CM(ssl), options); + } + else + return BAD_FUNC_ARG; +} + +int wolfSSL_DisableOCSP(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_DisableOCSP"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerDisableOCSP(SSL_CM(ssl)); + } + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_EnableOCSPStapling(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_EnableOCSPStapling"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerEnableOCSPStapling(SSL_CM(ssl)); + } + else + return BAD_FUNC_ARG; +} + +int wolfSSL_DisableOCSPStapling(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_DisableOCSPStapling"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerDisableOCSPStapling(SSL_CM(ssl)); + } + else + return BAD_FUNC_ARG; +} +int wolfSSL_SetOCSP_OverrideURL(WOLFSSL* ssl, const char* url) +{ + WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerSetOCSPOverrideURL(SSL_CM(ssl), url); + } + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_SetOCSP_Cb(WOLFSSL* ssl, + CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx) +{ + WOLFSSL_ENTER("wolfSSL_SetOCSP_Cb"); + if (ssl) { + SSL_CM_WARNING(ssl); + ssl->ocspIOCtx = ioCbCtx; /* use SSL specific ioCbCtx */ + return wolfSSL_CertManagerSetOCSP_Cb(SSL_CM(ssl), + ioCb, respFreeCb, NULL); + } + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_EnableOCSP(WOLFSSL_CTX* ctx, int options) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSP"); + if (ctx) + return wolfSSL_CertManagerEnableOCSP(ctx->cm, options); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_DisableOCSP(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSP"); + if (ctx) + return wolfSSL_CertManagerDisableOCSP(ctx->cm); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_SetOCSP_OverrideURL(WOLFSSL_CTX* ctx, const char* url) +{ + WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); + if (ctx) + return wolfSSL_CertManagerSetOCSPOverrideURL(ctx->cm, url); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_SetOCSP_Cb(WOLFSSL_CTX* ctx, CbOCSPIO ioCb, + CbOCSPRespFree respFreeCb, void* ioCbCtx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetOCSP_Cb"); + if (ctx) + return wolfSSL_CertManagerSetOCSP_Cb(ctx->cm, ioCb, + respFreeCb, ioCbCtx); + else + return BAD_FUNC_ARG; +} + +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) +int wolfSSL_CTX_EnableOCSPStapling(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPStapling"); + if (ctx) + return wolfSSL_CertManagerEnableOCSPStapling(ctx->cm); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_DisableOCSPStapling(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPStapling"); + if (ctx) + return wolfSSL_CertManagerDisableOCSPStapling(ctx->cm); + else + return BAD_FUNC_ARG; +} +int wolfSSL_CTX_EnableOCSPMustStaple(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPMustStaple"); + if (ctx) + return wolfSSL_CertManagerEnableOCSPMustStaple(ctx->cm); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_DisableOCSPMustStaple(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPMustStaple"); + if (ctx) + return wolfSSL_CertManagerDisableOCSPMustStaple(ctx->cm); + else + return BAD_FUNC_ARG; +} +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST || \ + * HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) +/* Not an OpenSSL API. */ +int wolfSSL_get_ocsp_response(WOLFSSL* ssl, byte** response) +{ + *response = ssl->ocspCsrResp[0].buffer; + return ssl->ocspCsrResp[0].length; +} + +/* Not an OpenSSL API. */ +char* wolfSSL_get_ocsp_url(WOLFSSL* ssl) +{ + return ssl->url; +} + +/* Not an OpenSSL API. */ +int wolfSSL_set_ocsp_url(WOLFSSL* ssl, char* url) +{ + if (ssl == NULL) + return WOLFSSL_FAILURE; + + ssl->url = url; + return WOLFSSL_SUCCESS; +} +#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ + +#if !defined(NO_ASN_TIME) +int wolfSSL_get_ocsp_producedDate( + WOLFSSL *ssl, + byte *producedDate, + size_t producedDate_space, + int *producedDateFormat) +{ + if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) && + (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME)) + return BAD_FUNC_ARG; + + if ((producedDate == NULL) || (producedDateFormat == NULL)) + return BAD_FUNC_ARG; + + if (XSTRLEN((char *)ssl->ocspProducedDate) >= producedDate_space) + return BUFFER_E; + + XSTRNCPY((char *)producedDate, (const char *)ssl->ocspProducedDate, + producedDate_space); + *producedDateFormat = ssl->ocspProducedDateFormat; + + return 0; +} + +int wolfSSL_get_ocsp_producedDate_tm(WOLFSSL *ssl, struct tm *produced_tm) { + int idx = 0; + + if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) && + (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME)) + return BAD_FUNC_ARG; + + if (produced_tm == NULL) + return BAD_FUNC_ARG; + + if (ExtractDate(ssl->ocspProducedDate, + (unsigned char)ssl->ocspProducedDateFormat, produced_tm, &idx, + MAX_DATE_SZ)) + return 0; + else + return ASN_PARSE_E; +} +#endif /* !NO_ASN_TIME */ +#endif /* HAVE_OCSP */ + +#if !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST + +int wolfSSL_UseOCSPStapling(WOLFSSL* ssl, byte status_type, byte options) +{ + WOLFSSL_ENTER("wolfSSL_UseOCSPStapling"); + + if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type, + options, NULL, ssl->heap, ssl->devId); +} + + +int wolfSSL_CTX_UseOCSPStapling(WOLFSSL_CTX* ctx, byte status_type, + byte options) +{ + WOLFSSL_ENTER("wolfSSL_CTX_UseOCSPStapling"); + + if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type, + options, NULL, ctx->heap, ctx->devId); +} + +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + +int wolfSSL_UseOCSPStaplingV2(WOLFSSL* ssl, byte status_type, byte options) +{ + if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequestV2(&ssl->extensions, status_type, + options, ssl->heap, ssl->devId); +} + + +int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx, byte status_type, + byte options) +{ + if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequestV2(&ctx->extensions, status_type, + options, ctx->heap, ctx->devId); +} + +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ +#endif /* !NO_TLS && !NO_WOLFSSL_CLIENT */ + +#ifdef OPENSSL_EXTRA +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST +long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type) +{ + WOLFSSL_ENTER("wolfSSL_set_tlsext_status_type"); + + if (s == NULL){ + return BAD_FUNC_ARG; + } + + if (type == WOLFSSL_TLSEXT_STATUSTYPE_ocsp){ + int r = TLSX_UseCertificateStatusRequest(&s->extensions, (byte)type, 0, + s, s->heap, s->devId); + return (long)r; + } else { + WOLFSSL_MSG( + "SSL_set_tlsext_status_type only supports TLSEXT_STATUSTYPE_ocsp type."); + return WOLFSSL_FAILURE; + } + +} + +long wolfSSL_get_tlsext_status_type(WOLFSSL *s) +{ + TLSX* extension; + + if (s == NULL) + return WOLFSSL_FATAL_ERROR; + extension = TLSX_Find(s->extensions, TLSX_STATUS_REQUEST); + return (extension != NULL) ? WOLFSSL_TLSEXT_STATUSTYPE_ocsp : + WOLFSSL_FATAL_ERROR; +} +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ +#endif /* OPENSSL_EXTRA */ + +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) +int wolfSSL_CTX_get_tlsext_status_cb(WOLFSSL_CTX* ctx, tlsextStatusCb* cb) +{ + if (ctx == NULL || ctx->cm == NULL || cb == NULL) + return WOLFSSL_FAILURE; + +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) + if (ctx->cm->ocsp_stapling == NULL) + return WOLFSSL_FAILURE; + + *cb = ctx->cm->ocsp_stapling->statusCb; +#else + (void)cb; + *cb = NULL; +#endif + + return WOLFSSL_SUCCESS; + +} + +int wolfSSL_CTX_set_tlsext_status_cb(WOLFSSL_CTX* ctx, tlsextStatusCb cb) +{ + if (ctx == NULL || ctx->cm == NULL) + return WOLFSSL_FAILURE; + +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) + /* Ensure stapling is on for callback to be used. */ + wolfSSL_CTX_EnableOCSPStapling(ctx); + + if (ctx->cm->ocsp_stapling == NULL) + return WOLFSSL_FAILURE; + + ctx->cm->ocsp_stapling->statusCb = cb; +#else + (void)cb; +#endif + + return WOLFSSL_SUCCESS; +} + +long wolfSSL_CTX_set_tlsext_status_arg(WOLFSSL_CTX* ctx, void* arg) +{ + if (ctx == NULL || ctx->cm == NULL) + return WOLFSSL_FAILURE; + +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) + /* Ensure stapling is on for callback to be used. */ + wolfSSL_CTX_EnableOCSPStapling(ctx); + + if (ctx->cm->ocsp_stapling == NULL) + return WOLFSSL_FAILURE; + + ctx->cm->ocsp_stapling->statusCbArg = arg; +#else + (void)arg; +#endif + + return WOLFSSL_SUCCESS; +} + +long wolfSSL_get_tlsext_status_ocsp_resp(WOLFSSL *ssl, unsigned char **resp) +{ + if (ssl == NULL || resp == NULL) + return 0; + + *resp = ssl->ocspCsrResp[0].buffer; + return (long)ssl->ocspCsrResp[0].length; +} + +long wolfSSL_set_tlsext_status_ocsp_resp(WOLFSSL *ssl, unsigned char *resp, + int len) +{ + return wolfSSL_set_tlsext_status_ocsp_resp_multi(ssl, resp, len, 0); +} + +int wolfSSL_set_tlsext_status_ocsp_resp_multi(WOLFSSL* ssl, unsigned char *resp, + int len, word32 idx) +{ + if (ssl == NULL || idx >= XELEM_CNT(ssl->ocspCsrResp) || len < 0) + return WOLFSSL_FAILURE; + if (!((resp == NULL) ^ (len > 0))) + return WOLFSSL_FAILURE; + + XFREE(ssl->ocspCsrResp[idx].buffer, NULL, 0); + ssl->ocspCsrResp[idx].buffer = resp; + ssl->ocspCsrResp[idx].length = (word32)len; + + return WOLFSSL_SUCCESS; +} + +#ifndef NO_WOLFSSL_SERVER +void wolfSSL_CTX_set_ocsp_status_verify_cb(WOLFSSL_CTX* ctx, + ocspVerifyStatusCb cb, void* cbArg) +{ + if (ctx != NULL) { + ctx->ocspStatusVerifyCb = cb; + ctx->ocspStatusVerifyCbArg = cbArg; + } +} +#endif /* NO_WOLFSSL_SERVER */ +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST || + * HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + +#endif /* !NO_CERTS */ + +#endif /* !WOLFSSL_SSL_API_CRL_OCSP_INCLUDED */ + diff --git a/src/ssl_api_pk.c b/src/ssl_api_pk.c new file mode 100644 index 0000000000..92bdd522c1 --- /dev/null +++ b/src/ssl_api_pk.c @@ -0,0 +1,1611 @@ +/* ssl_api_pk.c + * + * Copyright (C) 2006-2025 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 3 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 + */ + +#include + +#if !defined(WOLFSSL_SSL_API_PK_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_pk.c is not compiled separately from ssl.c + #endif +#else + +#ifndef NO_CERTS + +#ifndef NO_CHECK_PRIVATE_KEY + +#ifdef WOLF_PRIVATE_KEY_ID +/* Check priv against pub for match using external device with given devId + * + * @param [in] keyOID Public key OID. + * @param [in] privKey Private key data. + * @param [in] privSz Length of private key data in bytes. + * @param [in] pubKey Public key data. + * @param [in] pubSz Length of public key data in bytes. + * @param [in] label Key data is a hardware label. + * @param [in] id Key data is a hardware id. + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] devId Device Id. + * @return 0 on success. + * @return MISSING_KEY when privKey is NULL. + * @return Other negative value on error. + */ +static int check_cert_key_dev(word32 keyOID, byte* privKey, word32 privSz, + const byte* pubKey, word32 pubSz, int label, int id, void* heap, int devId) +{ + int ret = 0; + int type; + void *pkey = NULL; + + if (privKey == NULL) { + ret = MISSING_KEY; + } + else { + switch (keyOID) { + #ifndef NO_RSA + case RSAk: + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + type = DYNAMIC_TYPE_RSA; + break; + #endif + #ifdef HAVE_ECC + case ECDSAk: + type = DYNAMIC_TYPE_ECC; + break; + #endif + #if defined(HAVE_DILITHIUM) + case ML_DSA_LEVEL2k: + case ML_DSA_LEVEL3k: + case ML_DSA_LEVEL5k: + #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT + case DILITHIUM_LEVEL2k: + case DILITHIUM_LEVEL3k: + case DILITHIUM_LEVEL5k: + #endif + type = DYNAMIC_TYPE_DILITHIUM; + break; + #endif + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + case FALCON_LEVEL5k: + type = DYNAMIC_TYPE_FALCON; + break; + #endif + default: + type = 0; + } + + ret = CreateDevPrivateKey(&pkey, privKey, privSz, type, label, id, heap, + devId); + } +#ifdef WOLF_CRYPTO_CB + if (ret == 0) { + switch (keyOID) { + #ifndef NO_RSA + case RSAk: + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + ret = wc_CryptoCb_RsaCheckPrivKey((RsaKey*)pkey, pubKey, pubSz); + break; + #endif + #ifdef HAVE_ECC + case ECDSAk: + ret = wc_CryptoCb_EccCheckPrivKey((ecc_key*)pkey, pubKey, + pubSz); + break; + #endif + #if defined(HAVE_DILITHIUM) + case ML_DSA_LEVEL2k: + case ML_DSA_LEVEL3k: + case ML_DSA_LEVEL5k: + #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT + case DILITHIUM_LEVEL2k: + case DILITHIUM_LEVEL3k: + case DILITHIUM_LEVEL5k: + #endif + ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, + WC_PQC_SIG_TYPE_DILITHIUM, pubKey, pubSz); + break; + #endif + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + case FALCON_LEVEL5k: + ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, + WC_PQC_SIG_TYPE_FALCON, pubKey, pubSz); + break; + #endif + default: + ret = 0; + } + } +#else + /* devId was set, don't check, for now */ + /* TODO: Add callback for private key check? */ + (void) pubKey; + (void) pubSz; +#endif + + switch (keyOID) { +#ifndef NO_RSA + case RSAk: + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + wc_FreeRsaKey((RsaKey*)pkey); + break; +#endif + #ifdef HAVE_ECC + case ECDSAk: + wc_ecc_free((ecc_key*)pkey); + break; + #endif +#if defined(HAVE_DILITHIUM) + case ML_DSA_LEVEL2k: + case ML_DSA_LEVEL3k: + case ML_DSA_LEVEL5k: + #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT + case DILITHIUM_LEVEL2k: + case DILITHIUM_LEVEL3k: + case DILITHIUM_LEVEL5k: + #endif + wc_dilithium_free((dilithium_key*)pkey); + break; +#endif + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + case FALCON_LEVEL5k: + wc_falcon_free((falcon_key*)pkey); + break; + #endif + default: + WC_DO_NOTHING; + } + XFREE(pkey, heap, type); + + return ret; +} +#endif /* WOLF_PRIVATE_KEY_ID */ + +/* Check private against public in certificate for match. + * + * @param [in] cert DER encoded certificate. + * @param [in] key DER encoded private key. + * @param [in] altKey Alternative DER encoded key. + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] devId Device Id. + * @param [in] isKeyLabel Whether key is label. + * @param [in] isKeyId Whether key is an id. + * @param [in] altDevId Alternative key's device id. + * @param [in] isAltKeyLabel Is alternative key a label. + * @param [in] isAltKeyId Is alternative key an id. + * @return 1 on success. + * @return 0 on failure. + * @return MEMORY_E when memory allocation fails. + */ +static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, + const DerBuffer* altKey, void* heap, int devId, int isKeyLabel, int isKeyId, + int altDevId, int isAltKeyLabel, int isAltKeyId) +{ + WC_DECLARE_VAR(der, DecodedCert, 1, 0); + word32 size; + byte* buff; + int ret = 1; + + WOLFSSL_ENTER("check_cert_key"); + + /* Validate parameters. */ + if ((cert == NULL) || (key == NULL)) { + return 0; + } + if (ret == 1) { + /* Make a decoded certificate object available. */ + WC_ALLOC_VAR_EX(der, DecodedCert, 1, heap, DYNAMIC_TYPE_DCERT, + return MEMORY_E); + } + + if (ret == 1) { + /* Decode certificate. */ + InitDecodedCert_ex(der, cert->buffer, cert->length, heap, devId); + /* Parse certificate. */ + if (ParseCertRelative(der, CERT_TYPE, NO_VERIFY, NULL, NULL) != 0) { + WC_FREE_VAR_EX(der, heap, DYNAMIC_TYPE_DCERT); + ret = 0; + } + } + + if (ret == 1) { + buff = key->buffer; + size = key->length; + #ifdef WOLF_PRIVATE_KEY_ID + if (devId != INVALID_DEVID) { + ret = check_cert_key_dev(der->keyOID, buff, size, der->publicKey, + der->pubKeySize, isKeyLabel, isKeyId, heap, devId); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; + } + } + else { + /* fall through if unavailable */ + ret = CRYPTOCB_UNAVAILABLE; + } + + if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + #endif /* WOLF_PRIVATE_KEY_ID */ + { + ret = wc_CheckPrivateKeyCert(buff, size, der, 0, heap); + if (ret != 1) { + ret = 0; + } + } + + #ifdef WOLFSSL_DUAL_ALG_CERTS + if ((ret == 1) && der->extSapkiSet && (der->sapkiDer != NULL)) { + /* Certificate contains an alternative public key. Hence, we also + * need an alternative private key. */ + if (altKey == NULL) { + ret = MISSING_KEY; + buff = NULL; + size = 0; + } + else { + size = altKey->length; + buff = altKey->buffer; + } + #ifdef WOLF_PRIVATE_KEY_ID + if (altDevId != INVALID_DEVID) { + /* We have to decode the public key first */ + /* Default to max pub key size. */ + word32 pubKeyLen = MAX_PUBLIC_KEY_SZ; + byte* decodedPubKey = (byte*)XMALLOC(pubKeyLen, heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (decodedPubKey == NULL) { + ret = MEMORY_E; + } + if (ret == WOLFSSL_SUCCESS) { + if ((der->sapkiOID == RSAk) || (der->sapkiOID == ECDSAk)) { + /* Simply copy the data */ + XMEMCPY(decodedPubKey, der->sapkiDer, der->sapkiLen); + pubKeyLen = der->sapkiLen; + ret = 0; + } + else { + #if defined(WC_ENABLE_ASYM_KEY_IMPORT) + word32 idx = 0; + ret = DecodeAsymKeyPublic(der->sapkiDer, &idx, + der->sapkiLen, decodedPubKey, + &pubKeyLen, der->sapkiOID); + #else + ret = NOT_COMPILED_IN; + #endif /* WC_ENABLE_ASYM_KEY_IMPORT */ + } + } + if (ret == 0) { + ret = check_cert_key_dev(der->sapkiOID, buff, size, + decodedPubKey, pubKeyLen, isAltKeyLabel, isAltKeyId, + heap, altDevId); + } + XFREE(decodedPubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + ret = (ret == 0) ? 1: 0; + } + } + else { + /* fall through if unavailable */ + ret = CRYPTOCB_UNAVAILABLE; + } + + if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + #else + if (ret == 1) + #endif /* WOLF_PRIVATE_KEY_ID */ + { + ret = wc_CheckPrivateKeyCert(buff, size, der, 1, heap); + if (ret != 1) { + ret = 0; + } + } + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + } + + FreeDecodedCert(der); + WC_FREE_VAR_EX(der, heap, DYNAMIC_TYPE_DCERT); + + (void)devId; + (void)isKeyLabel; + (void)isKeyId; + (void)altKey; + (void)altDevId; + (void)isAltKeyLabel; + (void)isAltKeyId; + + return ret; +} + +/* Check private against public in certificate for match + * + * @param [in] ctx SSL/TLS context with a private key and certificate. + * + * @return 1 on good private key + * @return 0 if mismatched. + */ +int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx) +{ + int res = 1; +#ifdef WOLFSSL_BLIND_PRIVATE_KEY + DerBuffer *privateKey; +#ifdef WOLFSSL_DUAL_ALG_CERTS + DerBuffer *altPrivateKey; +#endif +#else + const DerBuffer *privateKey; +#ifdef WOLFSSL_DUAL_ALG_CERTS + const DerBuffer *altPrivateKey; +#endif +#endif + + /* Validate parameter. */ + if (ctx == NULL) { + res = 0; + } + else { +#ifdef WOLFSSL_DUAL_ALG_CERTS + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Unblind private keys. */ + privateKey = wolfssl_priv_der_unblind(ctx->privateKey, + ctx->privateKeyMask); + if (privateKey == NULL) { + res = 0; + } + if (ctx->altPrivateKey != NULL) { + altPrivateKey = wolfssl_priv_der_unblind(ctx->altPrivateKey, + ctx->altPrivateKeyMask); + if (altPrivateKey == NULL) { + res = 0; + } + } + else { + altPrivateKey = NULL; + } + #else + privateKey = ctx->privateKey; + altPrivateKey = ctx->altPrivateKey; + #endif + if (res == 1) { + /* Check certificate and private keys. */ + res = check_cert_key(ctx->certificate, privateKey, altPrivateKey, + ctx->heap, ctx->privateKeyDevId, ctx->privateKeyLabel, + ctx->privateKeyId, ctx->altPrivateKeyDevId, + ctx->altPrivateKeyLabel, ctx->altPrivateKeyId) != 0; + } + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Dispose of the unblinded buffers. */ + wolfssl_priv_der_unblind_free(privateKey); + wolfssl_priv_der_unblind_free(altPrivateKey); + #endif +#else + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Unblind private key. */ + privateKey = wolfssl_priv_der_unblind(ctx->privateKey, + ctx->privateKeyMask); + if (privateKey == NULL) { + res = 0; + } + #else + privateKey = ctx->privateKey; + #endif + if (res == WOLFSSL_SUCCESS) { + /* Check certificate and private key. */ + res = check_cert_key(ctx->certificate, privateKey, NULL, ctx->heap, + ctx->privateKeyDevId, ctx->privateKeyLabel, ctx->privateKeyId, + INVALID_DEVID, 0, 0); + } + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Dispose of the unblinded buffer. */ + wolfssl_priv_der_unblind_free(privateKey); + #endif +#endif + } + + /* Place error into queue for Python port. */ + if (res != 1) { + WOLFSSL_ERROR(WC_KEY_MISMATCH_E); + } + + return res; +} + +#ifdef OPENSSL_EXTRA +/* Check private against public in certificate for match. + * + * @param [in] ssl SSL/TLS object with a private key and certificate. + * + * @return 1 on good private key + * @return 0 if mismatched. + */ +int wolfSSL_check_private_key(const WOLFSSL* ssl) +{ + int res = 1; +#ifdef WOLFSSL_BLIND_PRIVATE_KEY + DerBuffer *privateKey; +#ifdef WOLFSSL_DUAL_ALG_CERTS + DerBuffer *altPrivateKey; +#endif +#else + const DerBuffer *privateKey; +#ifdef WOLFSSL_DUAL_ALG_CERTS + const DerBuffer *altPrivateKey; +#endif +#endif + + /* Validate parameter. */ + if (ssl == NULL) { + res = 0; + } + else { +#ifdef WOLFSSL_DUAL_ALG_CERTS + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Unblind private keys. */ + privateKey = wolfssl_priv_der_unblind(ssl->buffers.key, + ssl->buffers.keyMask); + if (privateKey == NULL) { + res = 0; + } + if (ssl->buffers.altKey != NULL) { + altPrivateKey = wolfssl_priv_der_unblind(ssl->buffers.altKey, + ssl->buffers.altKeyMask); + if (altPrivateKey == NULL) { + res = 0; + } + } + else { + altPrivateKey = NULL; + } + #else + privateKey = ssl->buffers.key; + altPrivateKey = ssl->buffers.altKey; + #endif + if (res == 1) { + /* Check certificate and private keys. */ + res = check_cert_key(ssl->buffers.certificate, privateKey, + altPrivateKey, ssl->heap, ssl->buffers.keyDevId, + ssl->buffers.keyLabel, ssl->buffers.keyId, + ssl->buffers.altKeyDevId, ssl->buffers.altKeyLabel, + ssl->buffers.altKeyId); + } + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Dispose of the unblinded buffers. */ + wolfssl_priv_der_unblind_free(privateKey); + wolfssl_priv_der_unblind_free(altPrivateKey); + #endif +#else + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Unblind private key. */ + privateKey = wolfssl_priv_der_unblind(ssl->buffers.key, + ssl->buffers.keyMask); + if (privateKey == NULL) { + res = 0; + } + #else + privateKey = ssl->buffers.key; + #endif + if (res == 1) { + /* Check certificate and private key. */ + res = check_cert_key(ssl->buffers.certificate, privateKey, NULL, + ssl->heap, ssl->buffers.keyDevId, ssl->buffers.keyLabel, + ssl->buffers.keyId, INVALID_DEVID, 0, 0); + } + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Dispose of the unblinded buffer. */ + wolfssl_priv_der_unblind_free(privateKey); + #endif +#endif + } + + return res; +} +#endif /* OPENSSL_EXTRA */ +#endif /* !NO_CHECK_PRIVATE_KEY */ + + +#ifdef OPENSSL_ALL +/** + * Return the private key of the SSL/TLS context. + * + * The caller doesn *NOT*` free the returned object. + * + * Note, even though the supplied ctx pointer is designated const, on success + * ctx->privateKeyPKey is changed by this call. The change is done safely using + * a hardware-synchronized store. + * + * @param [in] ctx SSL/TLS context. + * @return A WOFLSSL_EVP_PKEY on success. + * @return NULL on error. + */ +WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(const WOLFSSL_CTX* ctx) +{ + WOLFSSL_EVP_PKEY* res = NULL; + const unsigned char *key; + int type = WC_EVP_PKEY_NONE; + + WOLFSSL_ENTER("wolfSSL_CTX_get0_privatekey"); + + if ((ctx == NULL) || (ctx->privateKey == NULL) || + (ctx->privateKey->buffer == NULL)) { + WOLFSSL_MSG("Bad parameter or key not set"); + } + else { + switch (ctx->privateKeyType) { + #ifndef NO_RSA + case rsa_sa_algo: + type = WC_EVP_PKEY_RSA; + break; + #endif + #ifdef HAVE_ECC + case ecc_dsa_sa_algo: + type = WC_EVP_PKEY_EC; + break; + #endif + #ifdef WOLFSSL_SM2 + case sm2_sa_algo: + type = WC_EVP_PKEY_EC; + break; + #endif + default: + /* Other key types not supported either as ssl private keys + * or in the EVP layer */ + WOLFSSL_MSG("Unsupported key type"); + } + } + + if (type != WC_EVP_PKEY_NONE) { + if (ctx->privateKeyPKey != NULL) { + res = ctx->privateKeyPKey; + } + else { + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + DerBuffer* unblinded_privateKey = wolfssl_priv_der_unblind( + ctx->privateKey, ctx->privateKeyMask); + if (unblinded_privateKey != NULL) { + key = unblinded_privateKey->buffer; + } + else { + key = NULL; + } + #else + key = ctx->privateKey->buffer; + #endif + if (key != NULL) { + res = wolfSSL_d2i_PrivateKey(type, NULL, &key, + (long)ctx->privateKey->length); + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + wolfssl_priv_der_unblind_free(unblinded_privateKey); + #endif + } + if (res != NULL) { + #ifdef WOLFSSL_ATOMIC_OPS + WOLFSSL_EVP_PKEY *current_pkey = NULL; + if (!wolfSSL_Atomic_Ptr_CompareExchange( + (void * volatile *)&ctx->privateKeyPKey, + (void **)¤t_pkey, res)) { + wolfSSL_EVP_PKEY_free(res); + res = current_pkey; + } + #else + ((WOLFSSL_CTX *)ctx)->privateKeyPKey = res; + #endif + } + } + } + + return res; +} +#endif /* OPENSSL_ALL */ + +#ifdef HAVE_ECC + +/* Set size, in bytes, of temporary ECDHE key into SSL/TLS context. + * + * Values can be: 14 - 66 (112 - 521 bit) + * Uses the private key length if sz is 0. + * + * @param [in] ctx SSL/TLS context. + * @param [in] sz Size of EC key in bytes. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx is NULL or sz is invalid. + */ +int wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX* ctx, word16 sz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_SetTmpEC_DHE_Sz"); + + /* Validate parameters. */ + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + /* If size is 0 then get value from loaded private key. */ + else if (sz == 0) { + /* Applies only to ECDSA. */ + if (ctx->privateKeyType != ecc_dsa_sa_algo) { + ret = 1; + } + /* Must have a key set. */ + else if (ctx->privateKeySz == 0) { + WOLFSSL_MSG("Must set private key/cert first"); + ret = BAD_FUNC_ARG; + } + else { + sz = (word16)ctx->privateKeySz; + } + } + if (ret == 0) { + /* Check size against bounds. */ + #if ECC_MIN_KEY_SZ > 0 + if (sz < ECC_MINSIZE) { + ret = BAD_FUNC_ARG; + } + #endif + else if (sz > ECC_MAXSIZE) { + ret = BAD_FUNC_ARG; + } + else { + /* Store the size requested. */ + ctx->eccTempKeySz = sz; + ret = 1; + } + } + + return ret; +} + + +/* Set size, in bytes, of temporary ECDHE key into SSL/TLS object. + * + * Values can be: 14 - 66 (112 - 521 bit) + * Uses the private key length if sz is 0. + * + * @param [in] ssl SSL/TLS object. + * @param [in] sz Size of EC key in bytes. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl is NULL or sz is invalid. + */ +int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL* ssl, word16 sz) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_SetTmpEC_DHE_Sz"); + + /* Validate parameters. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + /* Check size against bounds. */ +#if ECC_MIN_KEY_SZ > 0 + else if (sz < ECC_MINSIZE) { + ret = BAD_FUNC_ARG; + } +#endif + else if (sz > ECC_MAXSIZE) { + ret = BAD_FUNC_ARG; + } + else { + /* Store the size requested. */ + ssl->eccTempKeySz = sz; + } + + return ret; +} + +#endif /* HAVE_ECC */ + +#ifdef HAVE_PK_CALLBACKS + +#ifdef HAVE_ECC +/* Set the ECC key generation callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb ECC key generation callback. + */ +void wolfSSL_CTX_SetEccKeyGenCb(WOLFSSL_CTX* ctx, CallbackEccKeyGen cb) +{ + if (ctx != NULL) { + ctx->EccKeyGenCb = cb; + } +} +/* Set the context for ECC key generation callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for ECC key generation callback. + */ +void wolfSSL_SetEccKeyGenCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->EccKeyGenCtx = ctx; + } +} +/* Get the context for ECC key generation callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for ECC key generation callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEccKeyGenCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->EccKeyGenCtx; + } + + return ret; +} +/* Set the context for ECC sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] userCtx Context for ECC sign callback. + */ +void wolfSSL_CTX_SetEccSignCtx(WOLFSSL_CTX* ctx, void *userCtx) +{ + if (ctx != NULL) { + ctx->EccSignCtx = userCtx; + } +} +/* Get the context for ECC sign callback from the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return Context for ECC sign for callback. + * @return NULL when ctx is NULL. + */ +void* wolfSSL_CTX_GetEccSignCtx(WOLFSSL_CTX* ctx) +{ + void* ret; + + if (ctx == NULL) { + ret = NULL; + } + else { + ret = ctx->EccSignCtx; + } + + return ret; +} + +/* Set the ECC sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb ECC sign callback. + */ +WOLFSSL_ABI void wolfSSL_CTX_SetEccSignCb(WOLFSSL_CTX* ctx, CallbackEccSign cb) +{ + if (ctx != NULL) { + ctx->EccSignCb = cb; + } +} +/* Set the context for ECC sign callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for ECC sign callback. + */ +void wolfSSL_SetEccSignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->EccSignCtx = ctx; + } +} +/* Get the context for ECC sign callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for ECC sign for callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEccSignCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->EccSignCtx; + } + + return ret; +} + +/* Set the ECC verify callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb ECC verify callback. + */ +void wolfSSL_CTX_SetEccVerifyCb(WOLFSSL_CTX* ctx, CallbackEccVerify cb) +{ + if (ctx != NULL) { + ctx->EccVerifyCb = cb; + } +} +/* Set the context for ECC verify callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for ECC verify callback. + */ +void wolfSSL_SetEccVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->EccVerifyCtx = ctx; + } +} +/* Get the context for ECC verify callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for ECC verify for callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->EccVerifyCtx; + } + + return ret; +} + +/* Set the ECC shared secret callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb ECC shared secret callback. + */ +void wolfSSL_CTX_SetEccSharedSecretCb(WOLFSSL_CTX* ctx, + CallbackEccSharedSecret cb) +{ + if (ctx != NULL) { + ctx->EccSharedSecretCb = cb; + } +} +/* Set the context for ECC shared secret callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for ECC shared secret callback. + */ +void wolfSSL_SetEccSharedSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->EccSharedSecretCtx = ctx; + } +} +/* Get the context for ECC shared secret callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for ECC shared secret callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->EccSharedSecretCtx; + } + + return ret; +} +#endif /* HAVE_ECC */ + +#ifdef HAVE_ED25519 +/* Set the Ed25519 sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb Ed25519 sign callback. + */ +void wolfSSL_CTX_SetEd25519SignCb(WOLFSSL_CTX* ctx, CallbackEd25519Sign cb) +{ + if (ctx != NULL) { + ctx->Ed25519SignCb = cb; + } +} +/* Set the context for Ed25519 sign callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for Ed25519 sign callback. + */ +void wolfSSL_SetEd25519SignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->Ed25519SignCtx = ctx; + } +} +/* Get the context for Ed25519 sign callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for Ed25519 sign callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEd25519SignCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->Ed25519SignCtx; + } + + return ret; +} + +/* Set the Ed25519 verify callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb Ed25519 verify callback. + */ +void wolfSSL_CTX_SetEd25519VerifyCb(WOLFSSL_CTX* ctx, CallbackEd25519Verify cb) +{ + if (ctx != NULL) { + ctx->Ed25519VerifyCb = cb; + } +} +/* Set the context for Ed25519 verify callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for Ed25519 verify callback. + */ +void wolfSSL_SetEd25519VerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->Ed25519VerifyCtx = ctx; + } +} +/* Get the context for Ed25519 verify callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for Ed25519 verify callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEd25519VerifyCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->Ed25519VerifyCtx; + } + + return ret; +} +#endif /* HAVE_ED25519 */ + +#ifdef HAVE_CURVE25519 +/* Set the X25519 key generation callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb X25519 key generation callback. + */ +void wolfSSL_CTX_SetX25519KeyGenCb(WOLFSSL_CTX* ctx, CallbackX25519KeyGen cb) +{ + if (ctx != NULL) { + ctx->X25519KeyGenCb = cb; + } +} +/* Set the context for X25519 key generation callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for X25519 key generation callback. + */ +void wolfSSL_SetX25519KeyGenCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->X25519KeyGenCtx = ctx; + } +} +/* Get the context for X25519 key generation callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for X25519 key generation callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetX25519KeyGenCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->X25519KeyGenCtx; + } + + return ret; +} + +/* Set the X25519 shared secret callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb X25519 shared secret callback. + */ +void wolfSSL_CTX_SetX25519SharedSecretCb(WOLFSSL_CTX* ctx, + CallbackX25519SharedSecret cb) +{ + if (ctx != NULL) { + ctx->X25519SharedSecretCb = cb; + } +} +/* Set the context for X25519 shared secret callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for X25519 shared secret callback. + */ +void wolfSSL_SetX25519SharedSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->X25519SharedSecretCtx = ctx; + } +} +/* Get the context for X25519 shared secret callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for X25519 shared secret callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->X25519SharedSecretCtx; + } + + return ret; +} +#endif /* HAVE_CURVE25519 */ + +#ifdef HAVE_ED448 +/* Set the Ed448 sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb Ed448 sign callback. + */ +void wolfSSL_CTX_SetEd448SignCb(WOLFSSL_CTX* ctx, CallbackEd448Sign cb) +{ + if (ctx != NULL) { + ctx->Ed448SignCb = cb; + } +} +/* Set the context for Ed448 sign callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for Ed448 sign callback. + */ +void wolfSSL_SetEd448SignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->Ed448SignCtx = ctx; + } +} +/* Get the context for Ed448 sign callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for Ed448 sign callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEd448SignCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->Ed448SignCtx; + } + + return ret; +} + +/* Set the Ed448 verify callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb Ed448 verify callback. + */ +void wolfSSL_CTX_SetEd448VerifyCb(WOLFSSL_CTX* ctx, CallbackEd448Verify cb) +{ + if (ctx != NULL) { + ctx->Ed448VerifyCb = cb; + } +} +/* Set the context for Ed448 verify callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for Ed448 verify callback. + */ +void wolfSSL_SetEd448VerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->Ed448VerifyCtx = ctx; + } +} +/* Get the context for Ed448 verify callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for Ed448 verify callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEd448VerifyCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->Ed448VerifyCtx; + } + + return ret; +} +#endif /* HAVE_ED448 */ + +#ifdef HAVE_CURVE448 +/* Set the X448 key generation callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb X448 key generation callback. + */ +void wolfSSL_CTX_SetX448KeyGenCb(WOLFSSL_CTX* ctx, + CallbackX448KeyGen cb) +{ + if (ctx != NULL) { + ctx->X448KeyGenCb = cb; + } +} +/* Set the context for X448 key generation callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for X448 key generation callback. + */ +void wolfSSL_SetX448KeyGenCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->X448KeyGenCtx = ctx; + } +} +/* Get the context for X448 key generation callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for X448 key generation callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetX448KeyGenCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->X448KeyGenCtx; + } + + return ret; +} + +/* Set the X448 shared secret callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb X448 shared secret callback. + */ +void wolfSSL_CTX_SetX448SharedSecretCb(WOLFSSL_CTX* ctx, + CallbackX448SharedSecret cb) +{ + if (ctx != NULL) { + ctx->X448SharedSecretCb = cb; + } +} +/* Set the context for X448 shared secret callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for X448 shared secret callback. + */ +void wolfSSL_SetX448SharedSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->X448SharedSecretCtx = ctx; + } +} +/* Get the context for X448 shared secret callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for X448 shared secret callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetX448SharedSecretCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->X448SharedSecretCtx; + } + + return ret; +} +#endif /* HAVE_CURVE448 */ + +#ifndef NO_RSA +/* Set the RSA sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA sign callback. + */ +void wolfSSL_CTX_SetRsaSignCb(WOLFSSL_CTX* ctx, CallbackRsaSign cb) +{ + if (ctx != NULL) { + ctx->RsaSignCb = cb; + } +} +/* Set the RSA sign check callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA sign check callback. + */ +void wolfSSL_CTX_SetRsaSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) +{ + if (ctx != NULL) { + ctx->RsaSignCheckCb = cb; + } +} +/* Set the context for RSA sign callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA sign callback. + */ +void wolfSSL_SetRsaSignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaSignCtx = ctx; + } +} +/* Get the context for RSA sign callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA sign callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaSignCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaSignCtx; + } + + return ret; +} + +/* Set the RSA verify callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA verify callback. + */ +void wolfSSL_CTX_SetRsaVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) +{ + if (ctx != NULL) { + ctx->RsaVerifyCb = cb; + } +} +/* Set the context for RSA verify callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA verify callback. + */ +void wolfSSL_SetRsaVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaVerifyCtx = ctx; + } +} +/* Get the context for RSA verify callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA verify callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaVerifyCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaVerifyCtx; + } + + return ret; +} + +#ifdef WC_RSA_PSS +/* Set the RSA PSS sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA PSS sign callback. + */ +void wolfSSL_CTX_SetRsaPssSignCb(WOLFSSL_CTX* ctx, CallbackRsaPssSign cb) +{ + if (ctx != NULL) { + ctx->RsaPssSignCb = cb; + } +} +/* Set the RSA PSS sign check callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA PSS sign check callback. + */ +void wolfSSL_CTX_SetRsaPssSignCheckCb(WOLFSSL_CTX* ctx, + CallbackRsaPssVerify cb) +{ + if (ctx != NULL) { + ctx->RsaPssSignCheckCb = cb; + } +} +/* Set the context for RSA PSS sign callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA PSS sign callback. + */ +void wolfSSL_SetRsaPssSignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaPssSignCtx = ctx; + } +} +/* Get the context for RSA PSS sign callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA PSS sign callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaPssSignCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaPssSignCtx; + } + + return ret; +} + +/* Set the RSA PSS verify callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA PSS verify callback. + */ +void wolfSSL_CTX_SetRsaPssVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb) +{ + if (ctx != NULL) { + ctx->RsaPssVerifyCb = cb; + } +} +/* Set the context for RSA PSS verify callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA PSS verify callback. + */ +void wolfSSL_SetRsaPssVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaPssVerifyCtx = ctx; + } +} +/* Get the context for RSA PSS verify callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA PSS verify callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaPssVerifyCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaPssVerifyCtx; + } + + return ret; +} +#endif /* WC_RSA_PSS */ + +/* Set the RSA encrypt callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA encrypt callback. + */ +void wolfSSL_CTX_SetRsaEncCb(WOLFSSL_CTX* ctx, CallbackRsaEnc cb) +{ + if (ctx != NULL) { + ctx->RsaEncCb = cb; + } +} +/* Set the context for RSA encrypt callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA encrypt callback. + */ +void wolfSSL_SetRsaEncCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaEncCtx = ctx; + } +} +/* Get the context for RSA encrypt callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA encrypt callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaEncCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaEncCtx; + } + + return ret; +} + +/* Set the RSA decrypt callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA decrypt callback. + */ +void wolfSSL_CTX_SetRsaDecCb(WOLFSSL_CTX* ctx, CallbackRsaDec cb) +{ + if (ctx != NULL) { + ctx->RsaDecCb = cb; + } +} +/* Set the context for RSA decrypt callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA decrypt callback. + */ +void wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaDecCtx = ctx; + } +} +/* Get the context for RSA decrypt callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA decrypt callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaDecCtx; + } + + return ret; +} +#endif /* NO_RSA */ + +#endif /* HAVE_PK_CALLBACKS */ + +#endif /* !NO_CERTS */ + +#if defined(HAVE_PK_CALLBACKS) && !defined(NO_DH) +/* Set the DH key pair generation callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb DH key pair generation callback. + */ +void wolfSSL_CTX_SetDhGenerateKeyPair(WOLFSSL_CTX* ctx, + CallbackDhGenerateKeyPair cb) +{ + if (ctx != NULL) { + ctx->DhGenerateKeyPairCb = cb; + } +} +/* Set the DH key agree callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb DH key agree callback. + */ +void wolfSSL_CTX_SetDhAgreeCb(WOLFSSL_CTX* ctx, CallbackDhAgree cb) +{ + if (ctx != NULL) { + ctx->DhAgreeCb = cb; + } +} +/* Set the context for DH key agree callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for DH key agree callback. + */ +void wolfSSL_SetDhAgreeCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->DhAgreeCtx = ctx; + } +} +/* Get the context for DH key ageww callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for DH key agree callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->DhAgreeCtx; + } + + return ret; +} +#endif /* HAVE_PK_CALLBACKS && !NO_DH */ + +#endif /* !WOLFSSL_SSL_API_PK_INCLUDED */ diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index 2fe3cab470..e9c43ca53e 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -3334,7 +3334,8 @@ const char* wolfSSL_ASN1_tag2str(int tag) const char* str = "(unknown)"; /* Clear negative flag. */ - if ((tag == WOLFSSL_V_ASN1_NEG_INTEGER) || (tag == WOLFSSL_V_ASN1_NEG_ENUMERATED)) { + if ((tag == WOLFSSL_V_ASN1_NEG_INTEGER) || + (tag == WOLFSSL_V_ASN1_NEG_ENUMERATED)) { tag &= ~WOLFSSL_V_ASN1_NEG; } /* Check for known basic types. */ @@ -4194,7 +4195,8 @@ char* wolfSSL_ASN1_TIME_to_string(WOLFSSL_ASN1_TIME* t, char* buf, int len) } /* Get time as human readable string. */ - if ((buf != NULL) && !GetTimeString(t->data, t->type, buf, len, t->length)) { + if ((buf != NULL) && !GetTimeString(t->data, t->type, buf, len, + t->length)) { buf = NULL; } @@ -4717,9 +4719,11 @@ void wolfSSL_ASN1_TYPE_set(WOLFSSL_ASN1_TYPE *a, int type, void *value) int wolfSSL_ASN1_TYPE_get(const WOLFSSL_ASN1_TYPE *a) { - if (a != NULL && (a->type == WOLFSSL_V_ASN1_BOOLEAN || a->type == WOLFSSL_V_ASN1_NULL - || a->value.ptr != NULL)) + if (a != NULL && (a->type == WOLFSSL_V_ASN1_BOOLEAN || + a->type == WOLFSSL_V_ASN1_NULL || + a->value.ptr != NULL)) { return a->type; + } return 0; } diff --git a/src/ssl_certman.c b/src/ssl_certman.c index 2fbab23fc4..5073ba044c 100644 --- a/src/ssl_certman.c +++ b/src/ssl_certman.c @@ -25,7 +25,7 @@ #if !defined(WOLFSSL_SSL_CERTMAN_INCLUDED) #ifndef WOLFSSL_IGNORE_FILE_WARN - #warning ssl_certman.c does not need to be compiled separately from ssl.c + #warning ssl_certman.c not to be compiled separately from ssl.c #endif #else @@ -2142,8 +2142,8 @@ int wolfSSL_CertManagerEnableOCSP(WOLFSSL_CERT_MANAGER* cm, int options) /* Initialize the OCSP object. */ if (InitOCSP(cm->ocsp, cm) != 0) { WOLFSSL_MSG("Init OCSP failed"); - /* Dispose of OCSP object - indicating dynamically allocated. - */ + /* Dispose of OCSP object - indicating dynamically + * allocated. */ FreeOCSP(cm->ocsp, 1); cm->ocsp = NULL; ret = 0; @@ -2533,6 +2533,821 @@ int wolfSSL_CertManagerSetOCSP_Cb(WOLFSSL_CERT_MANAGER* cm, CbOCSPIO ioCb, #endif /* HAVE_OCSP */ +/****************************************************************************** + * Internal APIs that use WOLFSSL_CERT_MANAGER + ******************************************************************************/ + +/* hash is the SHA digest of name, just use first 32 bits as hash */ +static WC_INLINE word32 HashSigner(const byte* hash) +{ + return MakeWordFromHash(hash) % CA_TABLE_SIZE; +} + + +/* does CA already exist on signer list */ +int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash) +{ + Signer* signers; + int ret = 0; + word32 row; + + if (cm == NULL || hash == NULL) { + return ret; + } + + row = HashSigner(hash); + + if (wc_LockMutex(&cm->caLock) != 0) { + return ret; + } + signers = cm->caTable[row]; + while (signers) { + byte* subjectHash; + + #ifndef NO_SKID + subjectHash = signers->subjectKeyIdHash; + #else + subjectHash = signers->subjectNameHash; + #endif + + if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { + ret = 1; /* success */ + break; + } + signers = signers->next; + } + wc_UnLockMutex(&cm->caLock); + + return ret; +} + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* hash is the SHA digest of name, just use first 32 bits as hash */ +static WC_INLINE word32 TrustedPeerHashSigner(const byte* hash) +{ + return MakeWordFromHash(hash) % TP_TABLE_SIZE; +} + +/* does trusted peer already exist on signer list */ +int AlreadyTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DecodedCert* cert) +{ + TrustedPeerCert* tp; + int ret = 0; + word32 row = TrustedPeerHashSigner(cert->subjectHash); + + if (wc_LockMutex(&cm->tpLock) != 0) + return ret; + tp = cm->tpTable[row]; + while (tp) { + if ((XMEMCMP(cert->subjectHash, tp->subjectNameHash, + SIGNER_DIGEST_SIZE) == 0) + #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER + && (XMEMCMP(cert->issuerHash, tp->issuerHash, + SIGNER_DIGEST_SIZE) == 0) + #endif + ) + ret = 1; + #ifndef NO_SKID + if (cert->extSubjKeyIdSet) { + /* Compare SKID as well if available */ + if (ret == 1 && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash, + SIGNER_DIGEST_SIZE) != 0) + ret = 0; + } + #endif + if (ret == 1) + break; + tp = tp->next; + } + wc_UnLockMutex(&cm->tpLock); + + return ret; +} + +/* return Trusted Peer if found, otherwise NULL + type is what to match on + */ +TrustedPeerCert* GetTrustedPeer(void* vp, DecodedCert* cert) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + TrustedPeerCert* ret = NULL; + TrustedPeerCert* tp = NULL; + word32 row; + + if (cm == NULL || cert == NULL) + return NULL; + + row = TrustedPeerHashSigner(cert->subjectHash); + + if (wc_LockMutex(&cm->tpLock) != 0) + return ret; + + tp = cm->tpTable[row]; + while (tp) { + if ((XMEMCMP(cert->subjectHash, tp->subjectNameHash, + SIGNER_DIGEST_SIZE) == 0) + #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER + && (XMEMCMP(cert->issuerHash, tp->issuerHash, + SIGNER_DIGEST_SIZE) == 0) + #endif + ) + ret = tp; + #ifndef NO_SKID + if (cert->extSubjKeyIdSet) { + /* Compare SKID as well if available */ + if (ret != NULL && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash, + SIGNER_DIGEST_SIZE) != 0) + ret = NULL; + } + #endif + if (ret != NULL) + break; + tp = tp->next; + } + wc_UnLockMutex(&cm->tpLock); + + return ret; +} + + +int MatchTrustedPeer(TrustedPeerCert* tp, DecodedCert* cert) +{ + if (tp == NULL || cert == NULL) + return BAD_FUNC_ARG; + + /* subject key id or subject hash has been compared when searching + tpTable for the cert from function GetTrustedPeer */ + + /* compare signatures */ + if (tp->sigLen == cert->sigLength) { + if (XMEMCMP(tp->sig, cert->signature, cert->sigLength)) { + return WOLFSSL_FAILURE; + } + } + else { + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_TRUST_PEER_CERT */ + +/* return CA if found, otherwise NULL */ +Signer* GetCA(void* vp, byte* hash) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; + word32 row = 0; + + if (cm == NULL || hash == NULL) + return NULL; + + row = HashSigner(hash); + + if (wc_LockMutex(&cm->caLock) != 0) + return ret; + + signers = cm->caTable[row]; + while (signers) { + byte* subjectHash; + #ifndef NO_SKID + subjectHash = signers->subjectKeyIdHash; + #else + subjectHash = signers->subjectNameHash; + #endif + if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { + ret = signers; + break; + } + signers = signers->next; + } + wc_UnLockMutex(&cm->caLock); + + return ret; +} + +#if defined(HAVE_OCSP) +Signer* GetCAByKeyHash(void* vp, const byte* keyHash) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; + int row; + + if (cm == NULL || keyHash == NULL) + return NULL; + + /* try lookup using keyHash as subjKeyID first */ + ret = GetCA(vp, (byte*)keyHash); + if (ret != NULL && XMEMCMP(ret->subjectKeyHash, keyHash, KEYID_SIZE) == 0) { + return ret; + } + + /* if we can't find the cert, we have to scan the full table */ + if (wc_LockMutex(&cm->caLock) != 0) + return NULL; + + /* Unfortunately we need to look through the entire table */ + for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { + for (signers = cm->caTable[row]; signers != NULL; + signers = signers->next) { + if (XMEMCMP(signers->subjectKeyHash, keyHash, KEYID_SIZE) == 0) { + ret = signers; + break; + } + } + } + + wc_UnLockMutex(&cm->caLock); + return ret; +} +#endif +#ifdef WOLFSSL_AKID_NAME +Signer* GetCAByAKID(void* vp, const byte* issuer, word32 issuerSz, + const byte* serial, word32 serialSz) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; + byte nameHash[SIGNER_DIGEST_SIZE]; + byte serialHash[SIGNER_DIGEST_SIZE]; + word32 row; + + if (cm == NULL || issuer == NULL || issuerSz == 0 || + serial == NULL || serialSz == 0) + return NULL; + + if (CalcHashId(issuer, issuerSz, nameHash) != 0 || + CalcHashId(serial, serialSz, serialHash) != 0) + return NULL; + + if (wc_LockMutex(&cm->caLock) != 0) + return ret; + + /* Unfortunately we need to look through the entire table */ + for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { + for (signers = cm->caTable[row]; signers != NULL; + signers = signers->next) { + if (XMEMCMP(signers->issuerNameHash, nameHash, SIGNER_DIGEST_SIZE) + == 0 && XMEMCMP(signers->serialHash, serialHash, + SIGNER_DIGEST_SIZE) == 0) { + ret = signers; + break; + } + } + } + + wc_UnLockMutex(&cm->caLock); + + return ret; +} +#endif + +#ifndef NO_SKID +/* return CA if found, otherwise NULL. Walk through hash table. */ +Signer* GetCAByName(void* vp, byte* hash) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; + word32 row; + + if (cm == NULL) + return NULL; + + if (wc_LockMutex(&cm->caLock) != 0) + return ret; + + for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { + signers = cm->caTable[row]; + while (signers && ret == NULL) { + if (XMEMCMP(hash, signers->subjectNameHash, + SIGNER_DIGEST_SIZE) == 0) { + ret = signers; + } + signers = signers->next; + } + } + wc_UnLockMutex(&cm->caLock); + + return ret; +} +#endif + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* add a trusted peer cert to linked list */ +int AddTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int verify) +{ + int ret = 0; + int row = 0; + TrustedPeerCert* peerCert; + DecodedCert* cert; + DerBuffer* der = *pDer; + + WOLFSSL_MSG("Adding a Trusted Peer Cert"); + + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) { + FreeDer(&der); + return MEMORY_E; + } + + InitDecodedCert(cert, der->buffer, der->length, cm->heap); + if ((ret = ParseCert(cert, TRUSTED_PEER_TYPE, verify, cm)) != 0) { + FreeDecodedCert(cert); + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); + FreeDer(&der); + return ret; + } + WOLFSSL_MSG("\tParsed new trusted peer cert"); + + peerCert = (TrustedPeerCert*)XMALLOC(sizeof(TrustedPeerCert), cm->heap, + DYNAMIC_TYPE_CERT); + if (peerCert == NULL) { + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + FreeDer(&der); + return MEMORY_E; + } + XMEMSET(peerCert, 0, sizeof(TrustedPeerCert)); + + #ifndef IGNORE_NAME_CONSTRAINTS + if (peerCert->permittedNames) + FreeNameSubtrees(peerCert->permittedNames, cm->heap); + if (peerCert->excludedNames) + FreeNameSubtrees(peerCert->excludedNames, cm->heap); + #endif + + if (AlreadyTrustedPeer(cm, cert)) { + WOLFSSL_MSG("\tAlready have this CA, not adding again"); + FreeTrustedPeer(peerCert, cm->heap); + (void)ret; + } + else { + /* add trusted peer signature */ + peerCert->sigLen = cert->sigLength; + peerCert->sig = (byte *)XMALLOC(cert->sigLength, cm->heap, + DYNAMIC_TYPE_SIGNATURE); + if (peerCert->sig == NULL) { + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + FreeTrustedPeer(peerCert, cm->heap); + FreeDer(&der); + return MEMORY_E; + } + XMEMCPY(peerCert->sig, cert->signature, cert->sigLength); + + /* add trusted peer name */ + peerCert->nameLen = cert->subjectCNLen; + peerCert->name = cert->subjectCN; + #ifndef IGNORE_NAME_CONSTRAINTS + peerCert->permittedNames = cert->permittedNames; + peerCert->excludedNames = cert->excludedNames; + #endif + + /* add SKID when available and hash of name */ + #ifndef NO_SKID + XMEMCPY(peerCert->subjectKeyIdHash, cert->extSubjKeyId, + SIGNER_DIGEST_SIZE); + #endif + XMEMCPY(peerCert->subjectNameHash, cert->subjectHash, + SIGNER_DIGEST_SIZE); + #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER + XMEMCPY(peerCert->issuerHash, cert->issuerHash, + SIGNER_DIGEST_SIZE); + #endif + /* If Key Usage not set, all uses valid. */ + peerCert->next = NULL; + cert->subjectCN = 0; + #ifndef IGNORE_NAME_CONSTRAINTS + cert->permittedNames = NULL; + cert->excludedNames = NULL; + #endif + + row = (int)TrustedPeerHashSigner(peerCert->subjectNameHash); + + if (wc_LockMutex(&cm->tpLock) == 0) { + peerCert->next = cm->tpTable[row]; + cm->tpTable[row] = peerCert; /* takes ownership */ + wc_UnLockMutex(&cm->tpLock); + } + else { + WOLFSSL_MSG("\tTrusted Peer Cert Mutex Lock failed"); + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + FreeTrustedPeer(peerCert, cm->heap); + FreeDer(&der); + return BAD_MUTEX_E; + } + } + + WOLFSSL_MSG("\tFreeing parsed trusted peer cert"); + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + WOLFSSL_MSG("\tFreeing der trusted peer cert"); + FreeDer(&der); + WOLFSSL_MSG("\t\tOK Freeing der trusted peer cert"); + WOLFSSL_LEAVE("AddTrustedPeer", ret); + + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_TRUST_PEER_CERT */ + +int AddSigner(WOLFSSL_CERT_MANAGER* cm, Signer *s) +{ + byte* subjectHash; + Signer* signers; + word32 row; + + if (cm == NULL || s == NULL) + return BAD_FUNC_ARG; + +#ifndef NO_SKID + subjectHash = s->subjectKeyIdHash; +#else + subjectHash = s->subjectNameHash; +#endif + + if (AlreadySigner(cm, subjectHash)) { + FreeSigner(s, cm->heap); + return 0; + } + + row = HashSigner(subjectHash); + + if (wc_LockMutex(&cm->caLock) != 0) + return BAD_MUTEX_E; + + signers = cm->caTable[row]; + s->next = signers; + cm->caTable[row] = s; + + wc_UnLockMutex(&cm->caLock); + return 0; +} + +/* owns der, internal now uses too */ +/* type flag ids from user or from chain received during verify + don't allow chain ones to be added w/o isCA extension */ +int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) +{ + int ret; + Signer* signer = NULL; + word32 row; + byte* subjectHash; + WC_DECLARE_VAR(cert, DecodedCert, 1, 0); + DerBuffer* der = *pDer; + + WOLFSSL_MSG_CERT_LOG("Adding a CA"); + + if (cm == NULL) { + FreeDer(pDer); + return BAD_FUNC_ARG; + } + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); + if (cert == NULL) { + FreeDer(pDer); + return MEMORY_E; + } + #endif + + InitDecodedCert(cert, der->buffer, der->length, cm->heap); + +#ifdef WC_ASN_UNKNOWN_EXT_CB + if (cm->unknownExtCallback != NULL) { + wc_SetUnknownExtCallback(cert, cm->unknownExtCallback); + } +#endif + + WOLFSSL_MSG_CERT("\tParsing new CA"); + ret = ParseCert(cert, CA_TYPE, verify, cm); + + WOLFSSL_MSG("\tParsed new CA"); +#ifdef WOLFSSL_DEBUG_CERTS + { + const char* err_msg; + if (ret == 0) { + WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "issuer: '%s'", + cert->issuer); + WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "subject: '%s'", + cert->subject); + } + else { + WOLFSSL_MSG_CERT( + WOLFSSL_MSG_CERT_INDENT "Failed during parse of new CA"); + err_msg = wc_GetErrorString(ret); + WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "error ret: %d; %s", + ret, err_msg); + } + } +#endif /* WOLFSSL_DEBUG_CERTS */ + +#ifndef NO_SKID + subjectHash = cert->extSubjKeyId; +#else + subjectHash = cert->subjectHash; +#endif + + /* check CA key size */ + if (verify && (ret == 0 )) { + switch (cert->keyOID) { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + case RSAk: + if (cm->minRsaKeySz < 0 || + cert->pubKeySize < (word16)cm->minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG_CERT_LOG("\tCA RSA key size error"); + WOLFSSL_MSG_CERT_EX("\tCA RSA pubKeySize = %d; " + "minRsaKeySz = %d", + cert->pubKeySize, cm->minRsaKeySz); + } + break; + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + if (cm->minEccKeySz < 0 || + cert->pubKeySize < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG_CERT_LOG("\tCA ECC key size error"); + WOLFSSL_MSG_CERT_EX("\tCA ECC pubKeySize = %d; " + "minEccKeySz = %d", + cert->pubKeySize, cm->minEccKeySz); + } + break; + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + if (cm->minEccKeySz < 0 || + ED25519_KEY_SIZE < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("\tCA ECC key size error"); + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + if (cm->minEccKeySz < 0 || + ED448_KEY_SIZE < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("\tCA ECC key size error"); + } + break; + #endif /* HAVE_ED448 */ + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + if (cm->minFalconKeySz < 0 || + FALCON_LEVEL1_KEY_SIZE < (word16)cm->minFalconKeySz) { + ret = FALCON_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Falcon level 1 key size error"); + } + break; + case FALCON_LEVEL5k: + if (cm->minFalconKeySz < 0 || + FALCON_LEVEL5_KEY_SIZE < (word16)cm->minFalconKeySz) { + ret = FALCON_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Falcon level 5 key size error"); + } + break; + #endif /* HAVE_FALCON */ + #if defined(HAVE_DILITHIUM) + #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT + case DILITHIUM_LEVEL2k: + if (cm->minDilithiumKeySz < 0 || + DILITHIUM_LEVEL2_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 2 key size error"); + } + break; + case DILITHIUM_LEVEL3k: + if (cm->minDilithiumKeySz < 0 || + DILITHIUM_LEVEL3_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 3 key size error"); + } + break; + case DILITHIUM_LEVEL5k: + if (cm->minDilithiumKeySz < 0 || + DILITHIUM_LEVEL5_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 5 key size error"); + } + break; + #endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */ + case ML_DSA_LEVEL2k: + if (cm->minDilithiumKeySz < 0 || + ML_DSA_LEVEL2_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 2 key size error"); + } + break; + case ML_DSA_LEVEL3k: + if (cm->minDilithiumKeySz < 0 || + ML_DSA_LEVEL3_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 3 key size error"); + } + break; + case ML_DSA_LEVEL5k: + if (cm->minDilithiumKeySz < 0 || + ML_DSA_LEVEL5_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 5 key size error"); + } + break; + #endif /* HAVE_DILITHIUM */ + + default: + WOLFSSL_MSG("\tNo key size check done on CA"); + break; /* no size check if key type is not in switch */ + } + } + + if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA && + type != WOLFSSL_TEMP_CA) { + WOLFSSL_MSG("\tCan't add as CA if not actually one"); + ret = NOT_CA_ERROR; + } +#ifndef ALLOW_INVALID_CERTSIGN + else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA && + type != WOLFSSL_TEMP_CA && !cert->selfSigned && + (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { + /* Intermediate CA certs are required to have the keyCertSign + * extension set. User loaded root certs are not. */ + WOLFSSL_MSG("\tDoesn't have key usage certificate signing"); + ret = NOT_CA_ERROR; + } +#endif + else if (ret == 0 && AlreadySigner(cm, subjectHash)) { + WOLFSSL_MSG("\tAlready have this CA, not adding again"); + (void)ret; + } + else if (ret == 0) { + /* take over signer parts */ + signer = MakeSigner(cm->heap); + if (!signer) + ret = MEMORY_ERROR; + } + if (ret == 0 && signer != NULL) { + ret = FillSigner(signer, cert, type, der); + + if (ret == 0){ + #ifndef NO_SKID + row = HashSigner(signer->subjectKeyIdHash); + #else + row = HashSigner(signer->subjectNameHash); + #endif + } + + #if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_FSPSM_TLS) + /* Verify CA by TSIP so that generated tsip key is going to */ + /* be able to be used for peer's cert verification */ + /* TSIP is only able to handle USER CA, and only one CA. */ + /* Therefore, it doesn't need to call TSIP again if there is already */ + /* verified CA. */ + if ( ret == 0 && signer != NULL ) { + signer->cm_idx = row; + if (type == WOLFSSL_USER_CA) { + if ((ret = wc_Renesas_cmn_RootCertVerify(cert->source, + cert->maxIdx, + cert->sigCtx.CertAtt.pubkey_n_start, + cert->sigCtx.CertAtt.pubkey_n_len - 1, + cert->sigCtx.CertAtt.pubkey_e_start, + cert->sigCtx.CertAtt.pubkey_e_len - 1, + row/* cm index */)) + < 0) + WOLFSSL_MSG("Renesas_RootCertVerify() failed"); + else + WOLFSSL_MSG("Renesas_RootCertVerify() succeed or skipped"); + } + } + #endif /* TSIP or SCE */ + + if (ret == 0 && wc_LockMutex(&cm->caLock) == 0) { + signer->next = cm->caTable[row]; + cm->caTable[row] = signer; /* takes ownership */ + wc_UnLockMutex(&cm->caLock); + if (cm->caCacheCallback) + cm->caCacheCallback(der->buffer, (int)der->length, type); + } + else { + WOLFSSL_MSG("\tCA Mutex Lock failed"); + ret = BAD_MUTEX_E; + } + } + + WOLFSSL_MSG("\tFreeing Parsed CA"); + FreeDecodedCert(cert); + if (ret != 0 && signer != NULL) + FreeSigner(signer, cm->heap); + WC_FREE_VAR_EX(cert, NULL, DYNAMIC_TYPE_DCERT); + WOLFSSL_MSG("\tFreeing der CA"); + FreeDer(pDer); + WOLFSSL_MSG("\t\tOK Freeing der CA"); + + WOLFSSL_LEAVE("AddCA", ret); + + return ret == 0 ? WOLFSSL_SUCCESS : ret; +} + +/* Removes the CA with the passed in subject hash from the + cert manager's CA cert store. */ +int RemoveCA(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type) +{ + Signer* current; + Signer** prev; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + word32 row; + + WOLFSSL_MSG("Removing a CA"); + + if (cm == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + + row = HashSigner(hash); + + if (wc_LockMutex(&cm->caLock) != 0) { + return BAD_MUTEX_E; + } + current = cm->caTable[row]; + prev = &cm->caTable[row]; + while (current) { + byte* subjectHash; + + #ifndef NO_SKID + subjectHash = current->subjectKeyIdHash; + #else + subjectHash = current->subjectNameHash; + #endif + + if ((current->type == type) && + (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0)) { + *prev = current->next; + FreeSigner(current, cm->heap); + ret = WOLFSSL_SUCCESS; + break; + } + prev = ¤t->next; + current = current->next; + } + wc_UnLockMutex(&cm->caLock); + + WOLFSSL_LEAVE("RemoveCA", ret); + + return ret; +} + +/* Sets the CA with the passed in subject hash + to the provided type. */ +int SetCAType(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type) +{ + Signer* current; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + word32 row; + + WOLFSSL_MSG_EX("Setting CA to type %d", type); + + if (cm == NULL || hash == NULL || + type < WOLFSSL_USER_CA || type > WOLFSSL_USER_INTER) { + return ret; + } + + row = HashSigner(hash); + + if (wc_LockMutex(&cm->caLock) != 0) { + return ret; + } + current = cm->caTable[row]; + while (current) { + byte* subjectHash; + + #ifndef NO_SKID + subjectHash = current->subjectKeyIdHash; + #else + subjectHash = current->subjectNameHash; + #endif + + if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { + current->type = (byte)type; + ret = WOLFSSL_SUCCESS; + break; + } + current = current->next; + } + wc_UnLockMutex(&cm->caLock); + + WOLFSSL_LEAVE("SetCAType", ret); + + return ret; +} + #endif /* NO_CERTS */ #endif /* !WOLFSSL_SSL_CERTMAN_INCLUDED */ diff --git a/src/ssl_crypto.c b/src/ssl_crypto.c index 167f71cc88..477c9a9971 100644 --- a/src/ssl_crypto.c +++ b/src/ssl_crypto.c @@ -3071,8 +3071,8 @@ void wolfSSL_AES_decrypt(const unsigned char* input, unsigned char* output, WOLFSSL_MSG("Null argument passed in"); } else -#if !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION3_GE(5,3,0))) +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ + (defined(FIPS_VERSION_GE) && FIPS_VERSION3_GE(5,3,0))) /* Decrypt a block with wolfCrypt AES. */ if (wc_AesDecryptDirect((Aes*)key, output, input) != 0) { WOLFSSL_MSG("wc_AesDecryptDirect failed"); @@ -3203,7 +3203,8 @@ void wolfSSL_AES_cbc_encrypt(const unsigned char *in, unsigned char* out, * AES_ENCRPT for encryption, AES_DECRYPTION for decryption. */ void wolfSSL_AES_cfb128_encrypt(const unsigned char *in, unsigned char* out, - size_t len, WOLFSSL_AES_KEY *key, unsigned char* iv, int* num, const int enc) + size_t len, WOLFSSL_AES_KEY *key, unsigned char* iv, int* num, + const int enc) { #ifndef WOLFSSL_AES_CFB WOLFSSL_MSG("CFB mode not enabled please use macro WOLFSSL_AES_CFB"); @@ -3435,13 +3436,15 @@ size_t wolfSSL_CRYPTO_cts128_decrypt(const unsigned char *in, * Use 0 buffer as IV to do straight decryption. * This places the Cn-1 block at lastBlk */ XMEMSET(lastBlk, 0, WOLFSSL_CTS128_BLOCK_SZ); - (*cbc)(in, prevBlk, WOLFSSL_CTS128_BLOCK_SZ, key, lastBlk, AES_DECRYPTION); + (*cbc)(in, prevBlk, WOLFSSL_CTS128_BLOCK_SZ, key, lastBlk, + AES_DECRYPTION); /* RFC2040: Append the tail (BB minus Ln) bytes of Xn to Cn * to create En. */ XMEMCPY(prevBlk, in + WOLFSSL_CTS128_BLOCK_SZ, lastBlkLen); /* Cn and Cn-1 can now be decrypted */ (*cbc)(prevBlk, out, WOLFSSL_CTS128_BLOCK_SZ, key, iv, AES_DECRYPTION); - (*cbc)(lastBlk, lastBlk, WOLFSSL_CTS128_BLOCK_SZ, key, iv, AES_DECRYPTION); + (*cbc)(lastBlk, lastBlk, WOLFSSL_CTS128_BLOCK_SZ, key, iv, + AES_DECRYPTION); XMEMCPY(out + WOLFSSL_CTS128_BLOCK_SZ, lastBlk, lastBlkLen); } diff --git a/src/ssl_ech.c b/src/ssl_ech.c new file mode 100644 index 0000000000..d27522c862 --- /dev/null +++ b/src/ssl_ech.c @@ -0,0 +1,738 @@ +/* ssl_ech.c + * + * Copyright (C) 2006-2025 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 3 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 + */ + +#include + +#if !defined(WOLFSSL_SSL_ECH_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_ech.c does not need to be compiled separately from ssl.c + #endif +#else + +#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) + +/* create the hpke key and ech config to send to clients */ +int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName, + word16 kemId, word16 kdfId, word16 aeadId) +{ + int ret = 0; + word16 encLen = DHKEM_X25519_ENC_LEN; + WOLFSSL_EchConfig* newConfig; + WOLFSSL_EchConfig* parentConfig; +#ifdef WOLFSSL_SMALL_STACK + Hpke* hpke = NULL; + WC_RNG* rng; +#else + Hpke hpke[1]; + WC_RNG rng[1]; +#endif + + if (ctx == NULL || publicName == NULL) + return BAD_FUNC_ARG; + + WC_ALLOC_VAR_EX(rng, WC_RNG, 1, ctx->heap, DYNAMIC_TYPE_RNG, + return MEMORY_E); + ret = wc_InitRng(rng); + if (ret != 0) { + WC_FREE_VAR_EX(rng, ctx->heap, DYNAMIC_TYPE_RNG); + return ret; + } + + newConfig = (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), + ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (newConfig == NULL) + ret = MEMORY_E; + else + XMEMSET(newConfig, 0, sizeof(WOLFSSL_EchConfig)); + + /* set random config id */ + if (ret == 0) + ret = wc_RNG_GenerateByte(rng, &newConfig->configId); + + /* if 0 is selected for algorithms use default, may change with draft */ + if (kemId == 0) + kemId = DHKEM_X25519_HKDF_SHA256; + + if (kdfId == 0) + kdfId = HKDF_SHA256; + + if (aeadId == 0) + aeadId = HPKE_AES_128_GCM; + + if (ret == 0) { + /* set the kem id */ + newConfig->kemId = kemId; + + /* set the cipher suite, only 1 for now */ + newConfig->numCipherSuites = 1; + newConfig->cipherSuites = + (EchCipherSuite*)XMALLOC(sizeof(EchCipherSuite), ctx->heap, + DYNAMIC_TYPE_TMP_BUFFER); + + if (newConfig->cipherSuites == NULL) { + ret = MEMORY_E; + } + else { + newConfig->cipherSuites[0].kdfId = kdfId; + newConfig->cipherSuites[0].aeadId = aeadId; + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 0) { + hpke = (Hpke*)XMALLOC(sizeof(Hpke), ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (hpke == NULL) + ret = MEMORY_E; + } +#endif + + if (ret == 0) + ret = wc_HpkeInit(hpke, kemId, kdfId, aeadId, ctx->heap); + + /* generate the receiver private key */ + if (ret == 0) + ret = wc_HpkeGenerateKeyPair(hpke, &newConfig->receiverPrivkey, rng); + + /* done with RNG */ + wc_FreeRng(rng); + + /* serialize the receiver key */ + if (ret == 0) + ret = wc_HpkeSerializePublicKey(hpke, newConfig->receiverPrivkey, + newConfig->receiverPubkey, &encLen); + + if (ret == 0) { + newConfig->publicName = (char*)XMALLOC(XSTRLEN(publicName) + 1, + ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (newConfig->publicName == NULL) { + ret = MEMORY_E; + } + else { + XMEMCPY(newConfig->publicName, publicName, + XSTRLEN(publicName) + 1); + } + } + + if (ret != 0) { + if (newConfig) { + XFREE(newConfig->cipherSuites, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(newConfig->publicName, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(newConfig, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + } + else { + parentConfig = ctx->echConfigs; + + if (parentConfig == NULL) { + ctx->echConfigs = newConfig; + } + else { + while (parentConfig->next != NULL) { + parentConfig = parentConfig->next; + } + + parentConfig->next = newConfig; + } + } + + if (ret == 0) + ret = WOLFSSL_SUCCESS; + + WC_FREE_VAR_EX(hpke, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(rng, ctx->heap, DYNAMIC_TYPE_RNG); + + return ret; +} + +int wolfSSL_CTX_SetEchConfigsBase64(WOLFSSL_CTX* ctx, const char* echConfigs64, + word32 echConfigs64Len) +{ + int ret = 0; + word32 decodedLen = echConfigs64Len * 3 / 4 + 1; + byte* decodedConfigs; + + if (ctx == NULL || echConfigs64 == NULL || echConfigs64Len == 0) + return BAD_FUNC_ARG; + + decodedConfigs = (byte*)XMALLOC(decodedLen, ctx->heap, + DYNAMIC_TYPE_TMP_BUFFER); + + if (decodedConfigs == NULL) + return MEMORY_E; + + decodedConfigs[decodedLen - 1] = 0; + + /* decode the echConfigs */ + ret = Base64_Decode((const byte*)echConfigs64, echConfigs64Len, + decodedConfigs, &decodedLen); + + if (ret != 0) { + XFREE(decodedConfigs, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + ret = wolfSSL_CTX_SetEchConfigs(ctx, decodedConfigs, decodedLen); + + XFREE(decodedConfigs, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +int wolfSSL_CTX_SetEchConfigs(WOLFSSL_CTX* ctx, const byte* echConfigs, + word32 echConfigsLen) +{ + int ret; + + if (ctx == NULL || echConfigs == NULL || echConfigsLen == 0) + return BAD_FUNC_ARG; + + FreeEchConfigs(ctx->echConfigs, ctx->heap); + ctx->echConfigs = NULL; + ret = SetEchConfigsEx(&ctx->echConfigs, ctx->heap, echConfigs, + echConfigsLen); + + if (ret == 0) + return WOLFSSL_SUCCESS; + + return ret; +} + +/* get the ech configs that the server context is using */ +int wolfSSL_CTX_GetEchConfigs(WOLFSSL_CTX* ctx, byte* output, + word32* outputLen) { + if (ctx == NULL || outputLen == NULL) + return BAD_FUNC_ARG; + + /* if we don't have ech configs */ + if (ctx->echConfigs == NULL) + return WOLFSSL_FATAL_ERROR; + + return GetEchConfigsEx(ctx->echConfigs, output, outputLen); +} + +void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable) +{ + if (ctx != NULL) { + ctx->disableECH = !enable; + if (ctx->disableECH) { + TLSX_Remove(&ctx->extensions, TLSX_ECH, ctx->heap); + FreeEchConfigs(ctx->echConfigs, ctx->heap); + ctx->echConfigs = NULL; + } + } +} + +/* set the ech config from base64 for our client ssl object, base64 is the + * format ech configs are sent using dns records */ +int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64, + word32 echConfigs64Len) +{ + int ret = 0; + word32 decodedLen = echConfigs64Len * 3 / 4 + 1; + byte* decodedConfigs; + + if (ssl == NULL || echConfigs64 == NULL || echConfigs64Len == 0) + return BAD_FUNC_ARG; + + /* already have ech configs */ + if (ssl->options.useEch == 1) { + return WOLFSSL_FATAL_ERROR; + } + + decodedConfigs = (byte*)XMALLOC(decodedLen, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + + if (decodedConfigs == NULL) + return MEMORY_E; + + decodedConfigs[decodedLen - 1] = 0; + + /* decode the echConfigs */ + ret = Base64_Decode((byte*)echConfigs64, echConfigs64Len, + decodedConfigs, &decodedLen); + + if (ret != 0) { + XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + ret = wolfSSL_SetEchConfigs(ssl, decodedConfigs, decodedLen); + + XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/* set the ech config from a raw buffer, this is the format ech configs are + * sent using retry_configs from the ech server */ +int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs, + word32 echConfigsLen) +{ + int ret; + + if (ssl == NULL || echConfigs == NULL || echConfigsLen == 0) + return BAD_FUNC_ARG; + + /* already have ech configs */ + if (ssl->options.useEch == 1) { + return WOLFSSL_FATAL_ERROR; + } + + ret = SetEchConfigsEx(&ssl->echConfigs, ssl->heap, echConfigs, + echConfigsLen); + + /* if we found valid configs */ + if (ret == 0) { + ssl->options.useEch = 1; + return WOLFSSL_SUCCESS; + } + + return ret; +} + +/* get the raw ech config from our struct */ +int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) +{ + int i; + word16 totalLen = 0; + + if (config == NULL || (output == NULL && outputLen == NULL)) + return BAD_FUNC_ARG; + + /* 2 for version */ + totalLen += 2; + /* 2 for length */ + totalLen += 2; + /* 1 for configId */ + totalLen += 1; + /* 2 for kemId */ + totalLen += 2; + /* 2 for hpke_len */ + totalLen += 2; + + /* hpke_pub_key */ + switch (config->kemId) { + case DHKEM_P256_HKDF_SHA256: + totalLen += DHKEM_P256_ENC_LEN; + break; + case DHKEM_P384_HKDF_SHA384: + totalLen += DHKEM_P384_ENC_LEN; + break; + case DHKEM_P521_HKDF_SHA512: + totalLen += DHKEM_P521_ENC_LEN; + break; + case DHKEM_X25519_HKDF_SHA256: + totalLen += DHKEM_X25519_ENC_LEN; + break; + case DHKEM_X448_HKDF_SHA512: + totalLen += DHKEM_X448_ENC_LEN; + break; + } + + /* cipherSuitesLen */ + totalLen += 2; + /* cipherSuites */ + totalLen += config->numCipherSuites * 4; + /* public name len */ + totalLen += 2; + + /* public name */ + totalLen += XSTRLEN(config->publicName); + /* trailing zeros */ + totalLen += 2; + + if (output == NULL) { + *outputLen = totalLen; + return WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + + if (totalLen > *outputLen) { + *outputLen = totalLen; + return INPUT_SIZE_E; + } + + /* version */ + c16toa(TLSX_ECH, output); + output += 2; + + /* length - 4 for version and length itself */ + c16toa(totalLen - 4, output); + output += 2; + + /* configId */ + *output = config->configId; + output++; + /* kemId */ + c16toa(config->kemId, output); + output += 2; + + /* length and key itself */ + switch (config->kemId) { + case DHKEM_P256_HKDF_SHA256: + c16toa(DHKEM_P256_ENC_LEN, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, DHKEM_P256_ENC_LEN); + output += DHKEM_P256_ENC_LEN; + break; + case DHKEM_P384_HKDF_SHA384: + c16toa(DHKEM_P384_ENC_LEN, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, DHKEM_P384_ENC_LEN); + output += DHKEM_P384_ENC_LEN; + break; + case DHKEM_P521_HKDF_SHA512: + c16toa(DHKEM_P521_ENC_LEN, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, DHKEM_P521_ENC_LEN); + output += DHKEM_P521_ENC_LEN; + break; + case DHKEM_X25519_HKDF_SHA256: + c16toa(DHKEM_X25519_ENC_LEN, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, DHKEM_X25519_ENC_LEN); + output += DHKEM_X25519_ENC_LEN; + break; + case DHKEM_X448_HKDF_SHA512: + c16toa(DHKEM_X448_ENC_LEN, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, DHKEM_X448_ENC_LEN); + output += DHKEM_X448_ENC_LEN; + break; + } + + /* cipherSuites len */ + c16toa(config->numCipherSuites * 4, output); + output += 2; + + /* cipherSuites */ + for (i = 0; i < config->numCipherSuites; i++) { + c16toa(config->cipherSuites[i].kdfId, output); + output += 2; + c16toa(config->cipherSuites[i].aeadId, output); + output += 2; + } + + /* set maximum name length to 0 */ + *output = 0; + output++; + + /* publicName len */ + *output = XSTRLEN(config->publicName); + output++; + + /* publicName */ + XMEMCPY(output, config->publicName, + XSTRLEN(config->publicName)); + output += XSTRLEN(config->publicName); + + /* terminating zeros */ + c16toa(0, output); + /* output += 2; */ + + *outputLen = totalLen; + + return 0; +} + +/* wrapper function to get ech configs from application code */ +int wolfSSL_GetEchConfigs(WOLFSSL* ssl, byte* output, word32* outputLen) +{ + if (ssl == NULL || outputLen == NULL) + return BAD_FUNC_ARG; + + /* if we don't have ech configs */ + if (ssl->options.useEch != 1) { + return WOLFSSL_FATAL_ERROR; + } + + return GetEchConfigsEx(ssl->echConfigs, output, outputLen); +} + +void wolfSSL_SetEchEnable(WOLFSSL* ssl, byte enable) +{ + if (ssl != NULL) { + ssl->options.disableECH = !enable; + if (ssl->options.disableECH) { + TLSX_Remove(&ssl->extensions, TLSX_ECH, ssl->heap); + FreeEchConfigs(ssl->echConfigs, ssl->heap); + ssl->echConfigs = NULL; + } + } +} + +int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap, + const byte* echConfigs, word32 echConfigsLen) +{ + int ret = 0; + int i; + int j; + word16 totalLength; + word16 version; + word16 length; + word16 hpkePubkeyLen; + word16 cipherSuitesLen; + word16 publicNameLen; + WOLFSSL_EchConfig* configList = NULL; + WOLFSSL_EchConfig* workingConfig = NULL; + WOLFSSL_EchConfig* lastConfig = NULL; + byte* echConfig = NULL; + + if (outputConfigs == NULL || echConfigs == NULL || echConfigsLen == 0) + return BAD_FUNC_ARG; + + /* check that the total length is well formed */ + ato16(echConfigs, &totalLength); + + if (totalLength != echConfigsLen - 2) { + return WOLFSSL_FATAL_ERROR; + } + + /* skip the total length uint16_t */ + i = 2; + + do { + echConfig = (byte*)echConfigs + i; + ato16(echConfig, &version); + ato16(echConfig + 2, &length); + + /* if the version does not match */ + if (version != TLSX_ECH) { + /* we hit the end of the configs */ + if ( (word32)i + 2 >= echConfigsLen ) { + break; + } + + /* skip this config, +4 for version and length */ + i += length + 4; + continue; + } + + /* check if the length will overrun the buffer */ + if ((word32)i + length + 4 > echConfigsLen) { + break; + } + + if (workingConfig == NULL) { + workingConfig = + (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), heap, + DYNAMIC_TYPE_TMP_BUFFER); + configList = workingConfig; + if (workingConfig != NULL) { + workingConfig->next = NULL; + } + } + else { + lastConfig = workingConfig; + workingConfig->next = + (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), + heap, DYNAMIC_TYPE_TMP_BUFFER); + workingConfig = workingConfig->next; + } + + if (workingConfig == NULL) { + ret = MEMORY_E; + break; + } + + XMEMSET(workingConfig, 0, sizeof(WOLFSSL_EchConfig)); + + /* rawLen */ + workingConfig->rawLen = length + 4; + + /* raw body */ + workingConfig->raw = (byte*)XMALLOC(workingConfig->rawLen, + heap, DYNAMIC_TYPE_TMP_BUFFER); + if (workingConfig->raw == NULL) { + ret = MEMORY_E; + break; + } + + XMEMCPY(workingConfig->raw, echConfig, workingConfig->rawLen); + + /* skip over version and length */ + echConfig += 4; + + /* configId, 1 byte */ + workingConfig->configId = *(echConfig); + echConfig++; + /* kemId, 2 bytes */ + ato16(echConfig, &workingConfig->kemId); + echConfig += 2; + /* hpke public_key length, 2 bytes */ + ato16(echConfig, &hpkePubkeyLen); + echConfig += 2; + /* hpke public_key */ + XMEMCPY(workingConfig->receiverPubkey, echConfig, hpkePubkeyLen); + echConfig += hpkePubkeyLen; + /* cipherSuitesLen */ + ato16(echConfig, &cipherSuitesLen); + + workingConfig->cipherSuites = (EchCipherSuite*)XMALLOC(cipherSuitesLen, + heap, DYNAMIC_TYPE_TMP_BUFFER); + if (workingConfig->cipherSuites == NULL) { + ret = MEMORY_E; + break; + } + + echConfig += 2; + workingConfig->numCipherSuites = cipherSuitesLen / 4; + /* cipherSuites */ + for (j = 0; j < workingConfig->numCipherSuites; j++) { + ato16(echConfig + j * 4, &workingConfig->cipherSuites[j].kdfId); + ato16(echConfig + j * 4 + 2, + &workingConfig->cipherSuites[j].aeadId); + } + echConfig += cipherSuitesLen; + /* ignore the maximum name length */ + echConfig++; + /* publicNameLen */ + publicNameLen = *(echConfig); + workingConfig->publicName = (char*)XMALLOC(publicNameLen + 1, + heap, DYNAMIC_TYPE_TMP_BUFFER); + if (workingConfig->publicName == NULL) { + ret = MEMORY_E; + break; + } + echConfig++; + /* publicName */ + XMEMCPY(workingConfig->publicName, echConfig, publicNameLen); + /* null terminated */ + workingConfig->publicName[publicNameLen] = 0; + + /* add length to go to next config, +4 for version and length */ + i += length + 4; + + /* check that we support this config */ + for (j = 0; j < HPKE_SUPPORTED_KEM_LEN; j++) { + if (hpkeSupportedKem[j] == workingConfig->kemId) + break; + } + + /* if we don't support the kem or at least one cipher suite */ + if (j >= HPKE_SUPPORTED_KEM_LEN || + EchConfigGetSupportedCipherSuite(workingConfig) < 0) + { + XFREE(workingConfig->cipherSuites, heap, + DYNAMIC_TYPE_TMP_BUFFER); + XFREE(workingConfig->publicName, heap, + DYNAMIC_TYPE_TMP_BUFFER); + XFREE(workingConfig->raw, heap, DYNAMIC_TYPE_TMP_BUFFER); + workingConfig = lastConfig; + } + } while ((word32)i < echConfigsLen); + + /* if we found valid configs */ + if (ret == 0 && configList != NULL) { + *outputConfigs = configList; + + return ret; + } + + workingConfig = configList; + + while (workingConfig != NULL) { + lastConfig = workingConfig; + workingConfig = workingConfig->next; + + XFREE(lastConfig->cipherSuites, heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(lastConfig->publicName, heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(lastConfig->raw, heap, DYNAMIC_TYPE_TMP_BUFFER); + + XFREE(lastConfig, heap, DYNAMIC_TYPE_TMP_BUFFER); + } + + if (ret == 0) + return WOLFSSL_FATAL_ERROR; + + return ret; +} + +/* get the raw ech configs from our linked list of ech config structs */ +int GetEchConfigsEx(WOLFSSL_EchConfig* configs, byte* output, word32* outputLen) +{ + int ret = 0; + WOLFSSL_EchConfig* workingConfig = NULL; + byte* outputStart = output; + word32 totalLen = 2; + word32 workingOutputLen = 0; + + if (configs == NULL || outputLen == NULL || + (output != NULL && *outputLen < totalLen)) { + return BAD_FUNC_ARG; + } + + + /* skip over total length which we fill in later */ + if (output != NULL) { + workingOutputLen = *outputLen - totalLen; + output += 2; + } + else { + /* caller getting the size only, set current 2 byte length size */ + *outputLen = totalLen; + } + + workingConfig = configs; + + while (workingConfig != NULL) { + /* get this config */ + ret = GetEchConfig(workingConfig, output, &workingOutputLen); + + if (output != NULL) + output += workingOutputLen; + + /* add this config's length to the total length */ + totalLen += workingOutputLen; + + if (totalLen > *outputLen) + workingOutputLen = 0; + else + workingOutputLen = *outputLen - totalLen; + + /* only error we break on, other 2 we need to keep finding length */ + if (ret == WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return BAD_FUNC_ARG; + + workingConfig = workingConfig->next; + } + + if (output == NULL) { + *outputLen = totalLen; + return WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + + if (totalLen > *outputLen) { + *outputLen = totalLen; + return INPUT_SIZE_E; + } + + /* total size -2 for size itself */ + c16toa(totalLen - 2, outputStart); + + *outputLen = totalLen; + + return WOLFSSL_SUCCESS; +} + +#endif /* WOLFSSL_TLS13 && HAVE_ECH */ + +#endif /* !WOLFSSL_SSL_ECH_INCLUDED */ + diff --git a/src/ssl_load.c b/src/ssl_load.c index e9e6862955..240d72e268 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -928,7 +928,8 @@ static int ProcessBufferTryDecodeDilithium(WOLFSSL_CTX* ctx, WOLFSSL* ssl, if (ret == 0) { /* Decode as a Dilithium private key. */ idx = 0; - ret = wc_Dilithium_PrivateKeyDecode(der->buffer, &idx, key, der->length); + ret = wc_Dilithium_PrivateKeyDecode(der->buffer, &idx, key, + der->length); if (ret == 0) { ret = dilithium_get_oid_sum(key, &keyFormatTemp); if (ret == 0) { @@ -1079,11 +1080,9 @@ static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, } #ifdef WC_RSA_PSS if((ret == 0) && (*keyFormat == RSAPSSk)) { - /* - Require logic to verify that the der is RSAPSSk (when *keyFormat == RSAPSSK), - and to detect that the der is RSAPSSk (when *keyFormat == 0). - */ - + /* Require logic to verify that the der is RSAPSSk + * (when *keyFormat == RSAPSSK), and to detect that the der is RSAPSSk + * (when *keyFormat == 0). */ matchAnyKey = 1; } #endif /* WC_RSA_PSS */ @@ -2138,7 +2137,8 @@ static int ProcessBufferCertHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl, * certificates so we can inject them at verification time */ if (ret == 1 && ctx->doAppleNativeCertValidationFlag == 1) { WOLFSSL_MSG("ANCV Test: Appending CA to cert list"); - ret = wolfSSL_TestAppleNativeCertValidation_AppendCA(ctx, derBuf, (int)derLen); + ret = wolfSSL_TestAppleNativeCertValidation_AppendCA(ctx, derBuf, + (int)derLen); if (ret == WOLFSSL_SUCCESS) { WOLFSSL_MSG("ANCV Test: Clearing CA table"); /* Clear the CA table so we can ensure they won't be used for @@ -2949,8 +2949,8 @@ int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file, NULL, verify); #else /* Load the DER formatted CA file */ - ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CA_TYPE, NULL, 0, - NULL, verify); + ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CA_TYPE, NULL, + 0, NULL, verify); #endif #ifndef NO_WOLFSSL_DIR if (ret == 1) { @@ -3234,8 +3234,8 @@ int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file) ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL, GET_VERIFY_SETTING_CTX(ctx)); #else - ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, NULL, 1, NULL, - GET_VERIFY_SETTING_CTX(ctx)); + ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, NULL, 1, + NULL, GET_VERIFY_SETTING_CTX(ctx)); #endif /* Return 1 on success or 0 on failure. */ @@ -4157,6 +4157,8 @@ int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, { int ret = 1; + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_Id"); + /* Dispose of old private key and allocate and copy in id. */ FreeDer(&ctx->privateKey); if (AllocCopyDer(&ctx->privateKey, id, (word32)sz, PRIVATEKEY_TYPE, @@ -4182,6 +4184,7 @@ int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, #endif } + WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_Id", ret); return ret; } @@ -4198,12 +4201,17 @@ int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* 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); + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_id"); + + 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 = (int)keySz; } + WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_id", ret); return ret; } @@ -4221,6 +4229,8 @@ int wolfSSL_CTX_use_PrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, int ret = 1; word32 sz = (word32)XSTRLEN(label) + 1; + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_Label"); + /* Dispose of old private key and allocate and copy in label. */ FreeDer(&ctx->privateKey); if (AllocCopyDer(&ctx->privateKey, (const byte*)label, (word32)sz, @@ -4246,6 +4256,7 @@ int wolfSSL_CTX_use_PrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, #endif } + WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_Label", ret); return ret; } @@ -4255,6 +4266,8 @@ int wolfSSL_CTX_use_AltPrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, { int ret = 1; + WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_Id"); + if ((ctx == NULL) || (id == NULL)) { ret = 0; } @@ -4277,17 +4290,23 @@ int wolfSSL_CTX_use_AltPrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, } } + WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_Id", ret); 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); + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_id"); + + ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId); if (ret == 1) { ctx->altPrivateKeySz = (word32)keySz; } + WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_id", ret); return ret; } @@ -4297,6 +4316,8 @@ int wolfSSL_CTX_use_AltPrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, int ret = 1; word32 sz; + WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_Label"); + if ((ctx == NULL) || (label == NULL)) { ret = 0; } @@ -4320,6 +4341,7 @@ int wolfSSL_CTX_use_AltPrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, } } + WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_Label", ret); return ret; } #endif /* WOLFSSL_DUAL_ALG_CERTS */ @@ -4871,7 +4893,8 @@ static int wolfssl_ctx_add_to_chain(WOLFSSL_CTX* ctx, const byte* der, if (res == 1) { /* Add chain to DER buffer. */ - res = wolfssl_add_to_chain(&ctx->certChain, 1, der, (word32)derSz, ctx->heap); + res = wolfssl_add_to_chain(&ctx->certChain, 1, der, (word32)derSz, + ctx->heap); #ifdef WOLFSSL_TLS13 /* Update count of certificates. */ ctx->certChainCnt++; @@ -5417,7 +5440,8 @@ int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx) } #else /* OpenSSL's implementation of this API does not require loading the - system CA cert directory. Allow skipping this without erroring out. */ + * system CA cert directory. Allow skipping this without erroring out. + */ ret = 1; #endif } @@ -5538,8 +5562,10 @@ int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz, if (ret == 1) { /* Allocate buffers for p and g to be assigned into SSL. */ - pAlloc = (byte*)XMALLOC((size_t)pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - gAlloc = (byte*)XMALLOC((size_t)gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + pAlloc = (byte*)XMALLOC((size_t)pSz, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + gAlloc = (byte*)XMALLOC((size_t)gSz, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); if ((pAlloc == NULL) || (gAlloc == NULL)) { /* Memory will be freed below in the (ret != 1) block */ ret = MEMORY_E; @@ -5590,7 +5616,8 @@ static int wolfssl_check_dh_key(unsigned char* p, int pSz, unsigned char* g, /* Initialize a DH object. */ if ((ret = wc_InitDhKey(checkKey)) == 0) { /* Check DH parameters. */ - ret = wc_DhSetCheckKey(checkKey, p, (word32)pSz, g, (word32)gSz, NULL, 0, 0, &rng); + ret = wc_DhSetCheckKey(checkKey, p, (word32)pSz, g, (word32)gSz, + NULL, 0, 0, &rng); /* Dispose of DH object. */ wc_FreeDhKey(checkKey); } @@ -5686,8 +5713,10 @@ int wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX* ctx, const unsigned char* p, int pSz, if (ret == 1) { /* Allocate buffers for p and g to be assigned into SSL context. */ - pAlloc = (byte*)XMALLOC((size_t)pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - gAlloc = (byte*)XMALLOC((size_t)gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + pAlloc = (byte*)XMALLOC((size_t)pSz, ctx->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + gAlloc = (byte*)XMALLOC((size_t)gSz, ctx->heap, + DYNAMIC_TYPE_PUBLIC_KEY); if ((pAlloc == NULL) || (gAlloc == NULL)) { ret = MEMORY_E; } diff --git a/src/ssl_p7p12.c b/src/ssl_p7p12.c index 7fc44a4b97..0b43d71e6d 100644 --- a/src/ssl_p7p12.c +++ b/src/ssl_p7p12.c @@ -1029,7 +1029,8 @@ int wolfSSL_PEM_write_bio_PKCS7(WOLFSSL_BIO* bio, PKCS7* p7) XMEMSET(pem, 0, pemSz); - if (wc_DerToPemEx(output, outputSz, pem, (word32)pemSz, NULL, CERT_TYPE) < 0) { + if (wc_DerToPemEx(output, outputSz, pem, (word32)pemSz, NULL,CERT_TYPE) + < 0) { goto error; } if ((wolfSSL_BIO_write(bio, pem, pemSz) == pemSz)) { @@ -1368,8 +1369,8 @@ PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, WOLFSSL_MSG("Error base64 decoding S/MIME message."); goto error; } - pkcs7 = wolfSSL_d2i_PKCS7_only(NULL, (const unsigned char**)&out, (int)outLen, - bcontMem, (word32)bcontMemSz); + pkcs7 = wolfSSL_d2i_PKCS7_only(NULL, (const unsigned char**)&out, + (int)outLen, bcontMem, (word32)bcontMemSz); wc_MIME_free_hdrs(allHdrs); XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7); @@ -1912,7 +1913,8 @@ int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw, DYNAMIC_TYPE_X509); InitX509(x509, 1, heap); InitDecodedCert(DeCert, current->buffer, current->bufferSz, heap); - if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL, NULL) != 0) { + if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL, NULL) + != 0) { WOLFSSL_MSG("Issue with parsing certificate"); FreeDecodedCert(DeCert); wolfSSL_X509_free(x509); diff --git a/src/ssl_sess.c b/src/ssl_sess.c index ac368c9b66..cff0046289 100644 --- a/src/ssl_sess.c +++ b/src/ssl_sess.c @@ -968,7 +968,8 @@ WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len) } /* start from most recently used */ - count = (int)min((word32)ClientCache[row].totalCount, CLIENT_SESSIONS_PER_ROW); + count = (int)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 */ @@ -997,7 +998,8 @@ WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len) #else current = &sessRow->Sessions[clSess[idx].serverIdx]; #endif - if (current && XMEMCMP(current->serverID, id, (unsigned long)len) == 0) { + if (current && XMEMCMP(current->serverID, id, + (unsigned long)len) == 0) { WOLFSSL_MSG("Found a serverid match for client"); if (LowResTimer() < (current->bornOn + current->timeout)) { WOLFSSL_MSG("Session valid"); @@ -1265,8 +1267,8 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) #endif if (output->ticketLenAlloc) XFREE(output->ticket, output->heap, DYNAMIC_TYPE_SESSION_TICK); - output->ticket = tmpTicket; /* cppcheck-suppress autoVariables - */ + /* cppcheck-suppress autoVariables */ + output->ticket = tmpTicket; output->ticketLenAlloc = PREALLOC_SESSION_TICKET_LEN; output->ticketLen = 0; tmpBufSet = 1; @@ -1394,7 +1396,8 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) output->ticketLen = 0; } if (error == WOLFSSL_SUCCESS) { - XMEMCPY(output->ticket, tmpTicket, output->ticketLen); /* cppcheck-suppress uninitvar */ + /* cppcheck-suppress uninitvar */ + XMEMCPY(output->ticket, tmpTicket, output->ticketLen); } } WC_FREE_VAR_EX(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -1839,8 +1842,9 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, 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) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + #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); #endif #endif @@ -1879,8 +1883,9 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, if (cacheSession == NULL) { #ifdef HAVE_SESSION_TICKET XFREE(ticBuff, 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))) + #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); #endif #endif @@ -2028,8 +2033,8 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, #ifndef NO_CLIENT_CACHE if (ret == 0 && clientCacheEntry != NULL) { - ClientSession* clientCache = AddSessionToClientCache(side, row, (int)idx, - addSession->serverID, addSession->idLen, id, useTicket); + ClientSession* clientCache = AddSessionToClientCache(side, row, + (int)idx, addSession->serverID, addSession->idLen, id, useTicket); if (clientCache != NULL) *clientCacheEntry = clientCache; } @@ -4088,7 +4093,8 @@ void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) ForceZero(session->sessionID, ID_LEN); if (session->type == WOLFSSL_SESSION_TYPE_HEAP) { - XFREE(session, session->heap, DYNAMIC_TYPE_SESSION); /* // NOLINT(clang-analyzer-unix.Malloc) */ + /* // NOLINTNEXTLINE(clang-analyzer-unix.Malloc) */ + XFREE(session, session->heap, DYNAMIC_TYPE_SESSION); } } diff --git a/src/ssl_sk.c b/src/ssl_sk.c index 9696a820aa..aeefa5a95b 100644 --- a/src/ssl_sk.c +++ b/src/ssl_sk.c @@ -259,6 +259,50 @@ int wolfSSL_sk_push_node(WOLFSSL_STACK** stack, WOLFSSL_STACK* node) return ret; } +/* Pushes the node onto the back of the stack. + * + * If *stack is NULL, node becomes the head. + * + * @param [in, out] stack Stack of nodes. + * @param [in] node Node to append. + * + * @return WOLFSSL_SUCCESS on success + * @return WOLFSSL_FAILURE when stack or node is NULL. + */ +int wolfSSL_sk_push_back_node(WOLFSSL_STACK** stack, WOLFSSL_STACK* node) +{ + int ret = WOLFSSL_SUCCESS; + + /* Validate parameters. */ + if (stack == NULL || node == NULL) { + ret = WOLFSSL_FAILURE; + } + if (ret == WOLFSSL_SUCCESS) { + node->next = NULL; + /* Tail node has num of 1, indicating 1 node till the end */ + node->num = 1; + + if (*stack == NULL) { + /* First node. */ + *stack = node; + } + else { + /* Walk to the end and append. Each node's num field holds the + * count of nodes from that node to the tail (inclusive), so + * every existing node's num increases by one. */ + WOLFSSL_STACK* cur = *stack; + while (cur->next != NULL) { + cur->num++; + cur = cur->next; + } + cur->num++; + cur->next = node; + } + } + + return ret; +} + /* Removes the node at the index from the stack and returns data. * * This is an internal API. diff --git a/src/tls.c b/src/tls.c index 7d7dcea86c..843d16f461 100644 --- a/src/tls.c +++ b/src/tls.c @@ -9894,7 +9894,7 @@ static int TLSX_KeyShareEntry_Parse(const WOLFSSL* ssl, const byte* input, ato16(&input[offset], &keLen); offset += OPAQUE16_LEN; if (keLen == 0) - return INVALID_PARAMETER; + return BUFFER_ERROR; if (keLen > length - offset) return BUFFER_ERROR; diff --git a/src/tls13.c b/src/tls13.c index 5b0f098507..b9e06896f9 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -5497,8 +5497,8 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, suite[1] = ssl->options.cipherSuite; if (!FindSuiteSSL(ssl, suite)) { WOLFSSL_MSG("Cipher suite not supported on client"); - WOLFSSL_ERROR_VERBOSE(MATCH_SUITE_ERROR); - return MATCH_SUITE_ERROR; + WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER); + return INVALID_PARAMETER; } #if defined(HAVE_ECH) diff --git a/src/x509.c b/src/x509.c index 291cd37ba2..ef9794829b 100644 --- a/src/x509.c +++ b/src/x509.c @@ -14986,41 +14986,109 @@ int wolfSSL_X509_NAME_digest(const WOLFSSL_X509_NAME *name, void wolfSSL_X509_email_free(WOLF_STACK_OF(WOLFSSL_STRING) *sk) { - WOLFSSL_STACK *curr; + wolfSSL_sk_pop_free(sk, NULL); +} - while (sk != NULL) { - curr = sk; - sk = sk->next; +static int x509_aia_append_string(WOLFSSL_STACK** head, + const byte* uri, word32 uriSz) +{ + WOLFSSL_STACK* node; + char* url; - XFREE(curr, NULL, DYNAMIC_TYPE_OPENSSL); + url = (char*)XMALLOC(uriSz + 1, NULL, DYNAMIC_TYPE_OPENSSL); + if (url == NULL) + return WOLFSSL_FAILURE; + + XMEMCPY(url, uri, uriSz); + url[uriSz] = '\0'; + + node = wolfSSL_sk_new_node(*head != NULL ? (*head)->heap : NULL); + if (node == NULL) { + XFREE(url, NULL, DYNAMIC_TYPE_OPENSSL); + return WOLFSSL_FAILURE; } + + node->type = STACK_TYPE_STRING; + node->data.string = url; + + if (wolfSSL_sk_push_back_node(head, node) != WOLFSSL_SUCCESS) { + XFREE(url, NULL, DYNAMIC_TYPE_OPENSSL); + wolfSSL_sk_free_node(node); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +static WOLFSSL_STACK* x509_get1_aia_by_method(WOLFSSL_X509* x, word32 method, + const byte* fallback, int fallbackSz) +{ + WOLFSSL_STACK* head = NULL; + int i; + + if (x == NULL) + return NULL; + + /* Collect matching URIs from the multi-entry list into a new stack; + * fall back to the legacy single-entry field for compatibility. */ + if (x->authInfoListSz > 0) { + for (i = 0; i < x->authInfoListSz; i++) { + if (x->authInfoList[i].method != method || + x->authInfoList[i].uri == NULL || + x->authInfoList[i].uriSz == 0) { + continue; + } + + if (x509_aia_append_string(&head, x->authInfoList[i].uri, + x->authInfoList[i].uriSz) != WOLFSSL_SUCCESS) { + wolfSSL_sk_pop_free(head, NULL); + return NULL; + } + } + } + if (head == NULL && fallback != NULL && fallbackSz > 0) { + if (x509_aia_append_string(&head, fallback, (word32)fallbackSz) + != WOLFSSL_SUCCESS) { + wolfSSL_sk_pop_free(head, NULL); + return NULL; + } + } + + return head; } WOLF_STACK_OF(WOLFSSL_STRING) *wolfSSL_X509_get1_ocsp(WOLFSSL_X509 *x) { - WOLFSSL_STACK* list = NULL; - char* url; - - if (x == NULL || x->authInfoSz == 0) + if (x == NULL) return NULL; - - list = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK) + x->authInfoSz + 1, - NULL, DYNAMIC_TYPE_OPENSSL); - if (list == NULL) - return NULL; - - url = (char*)list; - url += sizeof(WOLFSSL_STACK); - XMEMCPY(url, x->authInfo, x->authInfoSz); - url[x->authInfoSz] = '\0'; - - list->data.string = url; - list->next = NULL; - list->num = 1; - - return list; + return x509_get1_aia_by_method(x, AIA_OCSP_OID, x->authInfo, x->authInfoSz); } +int wolfSSL_X509_get_aia_overflow(WOLFSSL_X509 *x) +{ + int overflow = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_aia_overflow"); + + if (x != NULL) { + overflow = x->authInfoListOverflow; + } + + WOLFSSL_LEAVE("wolfSSL_X509_get_aia_overflow", overflow); + + return overflow; +} + +#ifdef WOLFSSL_ASN_CA_ISSUER +WOLF_STACK_OF(WOLFSSL_STRING) *wolfSSL_X509_get1_ca_issuers(WOLFSSL_X509 *x) +{ + if (x == NULL) + return NULL; + return x509_get1_aia_by_method(x, AIA_CA_ISSUER_OID, x->authInfoCaIssuer, + x->authInfoCaIssuerSz); +} +#endif /* WOLFSSL_ASN_CA_ISSUER */ + int wolfSSL_X509_check_issued(WOLFSSL_X509 *issuer, WOLFSSL_X509 *subject) { WOLFSSL_X509_NAME *issuerName = wolfSSL_X509_get_issuer_name(subject); diff --git a/tests/api.c b/tests/api.c index 95b5f37713..7083040296 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19199,6 +19199,109 @@ static int test_wolfSSL_OCSP_REQ_CTX(void) return EXPECT_RESULT(); } +static int test_wolfSSL_X509_get1_ca_issuers(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \ + defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)) && \ + defined(WOLFSSL_ASN_CA_ISSUER) && !defined(NO_FILESYSTEM) && \ + !defined(NO_RSA) + X509* cert = NULL; + STACK_OF(WOLFSSL_STRING) *skStr = NULL; + WOLFSSL_STRING url = NULL; + const char* expected = "http://example.com/ca.pem"; + + ExpectNull(wolfSSL_X509_get1_ca_issuers(NULL)); + ExpectNotNull(cert = wolfSSL_X509_load_certificate_file( + "certs/aia/ca-issuers-cert.pem", WOLFSSL_FILETYPE_PEM)); + ExpectNotNull(skStr = wolfSSL_X509_get1_ca_issuers(cert)); + ExpectIntEQ(wolfSSL_sk_WOLFSSL_STRING_num(skStr), 1); + ExpectNotNull(url = wolfSSL_sk_WOLFSSL_STRING_value(skStr, 0)); + ExpectIntEQ(XSTRCMP(url, expected), 0); + + wolfSSL_X509_email_free(skStr); + wolfSSL_X509_free(cert); +#endif + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_get1_aia_multi(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \ + defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)) && \ + defined(WOLFSSL_ASN_CA_ISSUER) && !defined(NO_FILESYSTEM) && \ + !defined(NO_RSA) + X509* cert = NULL; + STACK_OF(WOLFSSL_STRING) *ocsp = NULL; + STACK_OF(WOLFSSL_STRING) *ca = NULL; + const char* ocspExp1 = "http://127.0.0.1:22221"; + const char* ocspExp2 = "http://127.0.0.1:22222"; + const char* caExp1 = "http://www.wolfssl.com/ca.pem"; + const char* caExp2 = "https://www.wolfssl.com/ca2.pem"; + int i; + int ocspFound1 = 0, ocspFound2 = 0; + int caFound1 = 0, caFound2 = 0; + + ExpectNotNull(cert = wolfSSL_X509_load_certificate_file( + "certs/aia/multi-aia-cert.pem", WOLFSSL_FILETYPE_PEM)); + ExpectIntEQ(wolfSSL_X509_get_aia_overflow(cert), 0); + + ExpectNotNull(ocsp = wolfSSL_X509_get1_ocsp(cert)); + ExpectIntEQ(wolfSSL_sk_WOLFSSL_STRING_num(ocsp), 2); + for (i = 0; i < wolfSSL_sk_WOLFSSL_STRING_num(ocsp); i++) { + WOLFSSL_STRING url = wolfSSL_sk_WOLFSSL_STRING_value(ocsp, i); + if (url == NULL) + continue; + if (XSTRCMP(url, ocspExp1) == 0) ocspFound1 = 1; + if (XSTRCMP(url, ocspExp2) == 0) ocspFound2 = 1; + } + ExpectIntEQ(ocspFound1, 1); + ExpectIntEQ(ocspFound2, 1); + + ExpectNotNull(ca = wolfSSL_X509_get1_ca_issuers(cert)); + ExpectIntEQ(wolfSSL_sk_WOLFSSL_STRING_num(ca), 2); + for (i = 0; i < wolfSSL_sk_WOLFSSL_STRING_num(ca); i++) { + WOLFSSL_STRING url = wolfSSL_sk_WOLFSSL_STRING_value(ca, i); + if (url == NULL) + continue; + if (XSTRCMP(url, caExp1) == 0) caFound1 = 1; + if (XSTRCMP(url, caExp2) == 0) caFound2 = 1; + } + ExpectIntEQ(caFound1, 1); + ExpectIntEQ(caFound2, 1); + + wolfSSL_X509_email_free(ocsp); + wolfSSL_X509_email_free(ca); + wolfSSL_X509_free(cert); +#endif + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_get1_aia_overflow(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \ + defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)) && \ + !defined(NO_FILESYSTEM) && !defined(NO_RSA) + X509* cert = NULL; + STACK_OF(WOLFSSL_STRING) *ocsp = NULL; + int count; + + ExpectNotNull(cert = wolfSSL_X509_load_certificate_file( + "certs/aia/overflow-aia-cert.pem", WOLFSSL_FILETYPE_PEM)); + + ExpectNotNull(ocsp = wolfSSL_X509_get1_ocsp(cert)); + count = wolfSSL_sk_WOLFSSL_STRING_num(ocsp); + ExpectIntEQ(count, 8); + ExpectIntEQ(wolfSSL_X509_get_aia_overflow(cert), 1); + + wolfSSL_X509_email_free(ocsp); + wolfSSL_X509_free(cert); +#endif + return EXPECT_RESULT(); +} + static int test_no_op_functions(void) { EXPECT_DECLS; @@ -31666,6 +31769,9 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_OCSP_resp_get0), TEST_DECL(test_wolfSSL_OCSP_parse_url), TEST_DECL(test_wolfSSL_OCSP_REQ_CTX), + TEST_DECL(test_wolfSSL_X509_get1_ca_issuers), + TEST_DECL(test_wolfSSL_X509_get1_aia_multi), + TEST_DECL(test_wolfSSL_X509_get1_aia_overflow), TEST_DECL(test_wolfSSL_PEM_read), diff --git a/tests/api/test_aes.c b/tests/api/test_aes.c index fd56d26585..ab921e7ce3 100644 --- a/tests/api/test_aes.c +++ b/tests/api/test_aes.c @@ -5222,3 +5222,742 @@ int test_wc_AesEaxDecryptAuth(void) * (!HAVE_FIPS || FIPS_VERSION_GE(5, 3)) && !HAVE_SELFTEST */ +/*----------------------------------------------------------------------------* + | CryptoCB AES SetKey Test + *----------------------------------------------------------------------------*/ + +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \ + !defined(NO_AES) && defined(HAVE_AESGCM) + +#include + +#define TEST_CRYPTOCB_AES_DEVID 7 + +/* Test state tracking */ +static int cryptoCbAesSetKeyCalled = 0; +static int cryptoCbAesFreeCalled = 0; + +/* Simulated SE key storage - in real SE this would be in secure hardware */ +typedef struct { + byte key[AES_256_KEY_SIZE]; + word32 keySz; + int valid; +} MockSeKeySlot; + +static MockSeKeySlot mockSeKey = {0}; + +/* Mock handle pointing to our key slot */ +static void* cryptoCbAesMockHandle = (void*)&mockSeKey; + +/* Test CryptoCB callback for AES key import operations + * This emulates a Secure Element by: + * - Storing the key on SetKey (simulating SE key import) + * - Using stored key for encrypt/decrypt (simulating SE crypto) + * - Clearing key on Free (simulating SE key deletion) + */ +static int test_CryptoCb_Aes_Cb(int devId, wc_CryptoInfo* info, void* ctx) +{ + (void)ctx; + + if (devId != TEST_CRYPTOCB_AES_DEVID) + return CRYPTOCB_UNAVAILABLE; + + /* AES SetKey operation - simulate SE key import */ + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES && + info->cipher.aessetkey.aes != NULL) { + + Aes* aes = info->cipher.aessetkey.aes; + const byte* key = info->cipher.aessetkey.key; + word32 keySz = info->cipher.aessetkey.keySz; + + /* Validate key */ + if (key == NULL || keySz == 0 || keySz > AES_256_KEY_SIZE) { + return BAD_FUNC_ARG; + } + + /* "Import" key to simulated SE storage */ + XMEMCPY(mockSeKey.key, key, keySz); + mockSeKey.keySz = keySz; + mockSeKey.valid = 1; + + /* Store handle in aes->devCtx - this is what wolfSSL will use */ + aes->devCtx = cryptoCbAesMockHandle; + + + cryptoCbAesSetKeyCalled++; + + return 0; + } + + /* AES-GCM Encrypt - simulate SE encryption using stored key */ + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES_GCM && + info->cipher.enc) { + + Aes* aes = info->cipher.aesgcm_enc.aes; + MockSeKeySlot* slot; + Aes tempAes; + int ret; + + /* Verify handle points to our key slot */ + if (aes == NULL || aes->devCtx != cryptoCbAesMockHandle) { + return BAD_FUNC_ARG; + } + + slot = (MockSeKeySlot*)aes->devCtx; + if (!slot->valid) { + return BAD_STATE_E; + } + + /* Initialize a temporary Aes for software crypto (simulating SE internal operation) */ + XMEMSET(&tempAes, 0, sizeof(tempAes)); + ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID); /* No CryptoCB for internal use */ + if (ret != 0) return ret; + + ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz); + if (ret != 0) { + wc_AesFree(&tempAes); + return ret; + } + + /* Perform the actual encryption */ + ret = wc_AesGcmEncrypt(&tempAes, + info->cipher.aesgcm_enc.out, + info->cipher.aesgcm_enc.in, + info->cipher.aesgcm_enc.sz, + info->cipher.aesgcm_enc.iv, + info->cipher.aesgcm_enc.ivSz, + info->cipher.aesgcm_enc.authTag, + info->cipher.aesgcm_enc.authTagSz, + info->cipher.aesgcm_enc.authIn, + info->cipher.aesgcm_enc.authInSz); + + wc_AesFree(&tempAes); + + return ret; + } + + /* AES-GCM Decrypt - simulate SE decryption using stored key */ + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES_GCM && + !info->cipher.enc) { + + Aes* aes = info->cipher.aesgcm_dec.aes; + MockSeKeySlot* slot; + Aes tempAes; + int ret; + + /* Verify handle points to our key slot */ + if (aes == NULL || aes->devCtx != cryptoCbAesMockHandle) { + return BAD_FUNC_ARG; + } + + slot = (MockSeKeySlot*)aes->devCtx; + if (!slot->valid) { + return BAD_STATE_E; + } + + /* Initialize a temporary Aes for software crypto (simulating SE internal operation) */ + XMEMSET(&tempAes, 0, sizeof(tempAes)); + ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID); + if (ret != 0) return ret; + + ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz); + if (ret != 0) { + wc_AesFree(&tempAes); + return ret; + } + + /* Perform the actual decryption */ + ret = wc_AesGcmDecrypt(&tempAes, + info->cipher.aesgcm_dec.out, + info->cipher.aesgcm_dec.in, + info->cipher.aesgcm_dec.sz, + info->cipher.aesgcm_dec.iv, + info->cipher.aesgcm_dec.ivSz, + info->cipher.aesgcm_dec.authTag, + info->cipher.aesgcm_dec.authTagSz, + info->cipher.aesgcm_dec.authIn, + info->cipher.aesgcm_dec.authInSz); + + wc_AesFree(&tempAes); + + return ret; + } + +#ifdef WOLF_CRYPTO_CB_FREE + /* Free operation - simulate SE key deletion */ + if (info->algo_type == WC_ALGO_TYPE_FREE && + info->free.algo == WC_ALGO_TYPE_CIPHER && + info->free.type == WC_CIPHER_AES) { + + Aes* aes = (Aes*)info->free.obj; + + if (aes != NULL && aes->devCtx == cryptoCbAesMockHandle) { + /* "Delete" key from simulated SE */ + ForceZero(&mockSeKey, sizeof(mockSeKey)); + cryptoCbAesFreeCalled++; + } + + return 0; + } +#endif + + return CRYPTOCB_UNAVAILABLE; +} + +/* + * Test: CryptoCB AES SetKey hook for key import / secure element support + */ +int test_wc_CryptoCb_AesSetKey(void) +{ + EXPECT_DECLS; +#ifdef WOLFSSL_SMALL_STACK + Aes* aes = NULL; + byte* key = NULL; + byte* iv = NULL; + byte* plain = NULL; + byte* cipher = NULL; + byte* decrypted = NULL; + byte* authTag = NULL; +#else + Aes aes[1]; + byte key[AES_128_KEY_SIZE]; + byte iv[GCM_NONCE_MID_SZ]; + byte plain[16]; + byte cipher[16]; + byte decrypted[16]; + byte authTag[AES_BLOCK_SIZE]; +#endif + int ret; + +#ifdef WOLFSSL_SMALL_STACK + aes = (Aes*)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_TMP_BUFFER); + key = (byte*)XMALLOC(AES_128_KEY_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + iv = (byte*)XMALLOC(GCM_NONCE_MID_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + plain = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER); + cipher = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER); + decrypted = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER); + authTag = (byte*)XMALLOC(AES_BLOCK_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (aes == NULL || key == NULL || iv == NULL || plain == NULL || + cipher == NULL || decrypted == NULL || authTag == NULL) { + ret = MEMORY_E; + goto out; + } +#endif + + /* Initialize key, iv, plain arrays */ + { + static const byte keyData[AES_128_KEY_SIZE] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + static const byte plainData[16] = { + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, + 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x21, 0x00 + }; + XMEMCPY(key, keyData, AES_128_KEY_SIZE); + XMEMSET(iv, 0, GCM_NONCE_MID_SZ); + XMEMCPY(plain, plainData, 16); + } + + XMEMSET(aes, 0, sizeof(Aes)); + XMEMSET(&mockSeKey, 0, sizeof(mockSeKey)); + + /* Reset test state */ + cryptoCbAesSetKeyCalled = 0; + cryptoCbAesFreeCalled = 0; + + /* Register test callback */ + ret = wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_AES_DEVID, + test_CryptoCb_Aes_Cb, NULL); + ExpectIntEQ(ret, 0); + + /* Initialize Aes with device ID */ + ret = wc_AesInit(aes, NULL, TEST_CRYPTOCB_AES_DEVID); + ExpectIntEQ(ret, 0); + ExpectIntEQ(aes->devId, TEST_CRYPTOCB_AES_DEVID); + + /* Set key - should trigger CryptoCB and "import" to mock SE */ + ret = wc_AesGcmSetKey(aes, key, sizeof(key)); + ExpectIntEQ(ret, 0); + + /* Verify callback was invoked */ + ExpectIntEQ(cryptoCbAesSetKeyCalled, 1); + + /* Verify handle stored in devCtx */ + ExpectPtrEq(aes->devCtx, cryptoCbAesMockHandle); + + /* Verify key was "imported" to mock SE */ + ExpectIntEQ(mockSeKey.valid, 1); + ExpectIntEQ(mockSeKey.keySz, (int)sizeof(key)); + + /* Verify keylen metadata stored in Aes struct */ + ExpectIntEQ(aes->keylen, (int)sizeof(key)); + + /* After SetKey succeeds via CryptoCB, verify key NOT in devKey */ + { + byte zeroKey[AES_128_KEY_SIZE] = {0}; + /* Key should NOT be copied to devKey - SE owns it */ + ExpectIntEQ(XMEMCMP(aes->devKey, zeroKey, sizeof(key)), 0); + } + + /* Test encrypt - callback performs crypto using stored key */ + ret = wc_AesGcmEncrypt(aes, cipher, plain, sizeof(plain), + iv, sizeof(iv), authTag, sizeof(authTag), + NULL, 0); + ExpectIntEQ(ret, 0); + + /* Test decrypt - callback performs crypto using stored key */ + ret = wc_AesGcmDecrypt(aes, decrypted, cipher, sizeof(cipher), + iv, sizeof(iv), authTag, sizeof(authTag), + NULL, 0); + ExpectIntEQ(ret, 0); + + /* Verify round-trip */ + ExpectIntEQ(XMEMCMP(plain, decrypted, sizeof(plain)), 0); + +#ifdef WOLF_CRYPTO_CB_FREE + /* Free should trigger callback and "delete" key from mock SE */ + cryptoCbAesFreeCalled = 0; + wc_AesFree(aes); + + /* Verify free callback invoked */ + ExpectIntEQ(cryptoCbAesFreeCalled, 1); + + /* Verify devCtx cleared */ + ExpectPtrEq(aes->devCtx, NULL); + + /* Verify key was "deleted" from mock SE */ + ExpectIntEQ(mockSeKey.valid, 0); +#else + wc_AesFree(aes); +#endif + + /* Cleanup */ + wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_AES_DEVID); + + /* Test software path (no devId) still works */ + XMEMSET(aes, 0, sizeof(Aes)); + cryptoCbAesSetKeyCalled = 0; + + ret = wc_AesInit(aes, NULL, INVALID_DEVID); + ExpectIntEQ(ret, 0); + + ret = wc_AesGcmSetKey(aes, key, sizeof(key)); + ExpectIntEQ(ret, 0); + + /* Callback should NOT have been invoked */ + ExpectIntEQ(cryptoCbAesSetKeyCalled, 0); + + /* devCtx should be NULL */ + ExpectPtrEq(aes->devCtx, NULL); + + wc_AesFree(aes); + +#ifdef WOLFSSL_SMALL_STACK +out: + XFREE(aes, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(iv, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(cipher, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decrypted, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(authTag, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return EXPECT_RESULT(); +} + +#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY && !NO_AES && HAVE_AESGCM */ + +/*----------------------------------------------------------------------------* + | CryptoCB AES-GCM End-to-End Offload Test + *----------------------------------------------------------------------------*/ + +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \ + !defined(NO_AES) && defined(HAVE_AESGCM) + +#define TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID 8 + +/* Test state tracking for end-to-end offload test */ +static int cryptoCbAesGcmSetKeyCalled = 0; +static int cryptoCbAesGcmEncryptCalled = 0; +static int cryptoCbAesGcmDecryptCalled = 0; +static int cryptoCbAesGcmFreeCalled = 0; + +/* Mock SE key storage for offload test */ +typedef struct { + byte key[AES_256_KEY_SIZE]; + word32 keySz; + int valid; +} MockSeKeySlotOffload; + +static MockSeKeySlotOffload mockSeKeyOffload = {0}; + +/* Mock handle pointing to our key slot */ +static void* cryptoCbAesGcmMockHandle = (void*)&mockSeKeyOffload; + +/* Mock CryptoCB callback for end-to-end AES-GCM offload test + * This emulates a Secure Element that: + * - Stores the key on SetKey (simulating SE key import) + * - Performs encryption/decryption using stored key (simulating SE crypto) + * - Tracks all callback invocations to verify offload is working + * - Uses software AES internally (simulating SE internal operation) + */ +static int test_CryptoCb_AesGcm_Offload_Cb(int devId, wc_CryptoInfo* info, void* ctx) +{ + (void)ctx; + + if (devId != TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID) + return CRYPTOCB_UNAVAILABLE; + + /* AES SetKey operation - simulate SE key import */ + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES && + info->cipher.aessetkey.aes != NULL) { + + Aes* aes = info->cipher.aessetkey.aes; + const byte* key = info->cipher.aessetkey.key; + word32 keySz = info->cipher.aessetkey.keySz; + + /* Validate key */ + if (key == NULL || keySz == 0 || keySz > AES_256_KEY_SIZE) { + return BAD_FUNC_ARG; + } + + /* "Import" key to simulated SE storage */ + XMEMCPY(mockSeKeyOffload.key, key, keySz); + mockSeKeyOffload.keySz = keySz; + mockSeKeyOffload.valid = 1; + + /* Store handle in aes->devCtx - this is what wolfSSL will use */ + aes->devCtx = cryptoCbAesGcmMockHandle; + + + cryptoCbAesGcmSetKeyCalled++; + + return 0; + } + + /* AES-GCM Encrypt - simulate SE encryption using stored key */ + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES_GCM && + info->cipher.enc) { + + Aes* aes = info->cipher.aesgcm_enc.aes; + MockSeKeySlotOffload* slot; + Aes tempAes; + int ret; + + /* Verify handle points to our key slot */ + if (aes == NULL || aes->devCtx != cryptoCbAesGcmMockHandle) { + return BAD_FUNC_ARG; + } + + slot = (MockSeKeySlotOffload*)aes->devCtx; + if (!slot->valid) { + return BAD_STATE_E; + } + + /* Track that encrypt callback was invoked */ + cryptoCbAesGcmEncryptCalled++; + + /* Initialize a temporary Aes for software crypto (simulating SE internal operation) */ + XMEMSET(&tempAes, 0, sizeof(tempAes)); + ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID); /* No CryptoCB for internal use */ + if (ret != 0) return ret; + + ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz); + if (ret != 0) { + wc_AesFree(&tempAes); + return ret; + } + + /* Perform the actual encryption using software AES (simulating SE internal operation) */ + ret = wc_AesGcmEncrypt(&tempAes, + info->cipher.aesgcm_enc.out, + info->cipher.aesgcm_enc.in, + info->cipher.aesgcm_enc.sz, + info->cipher.aesgcm_enc.iv, + info->cipher.aesgcm_enc.ivSz, + info->cipher.aesgcm_enc.authTag, + info->cipher.aesgcm_enc.authTagSz, + info->cipher.aesgcm_enc.authIn, + info->cipher.aesgcm_enc.authInSz); + + wc_AesFree(&tempAes); + + return ret; + } + + /* AES-GCM Decrypt - simulate SE decryption using stored key */ + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES_GCM && + !info->cipher.enc) { + + Aes* aes = info->cipher.aesgcm_dec.aes; + MockSeKeySlotOffload* slot; + Aes tempAes; + int ret; + + /* Verify handle points to our key slot */ + if (aes == NULL || aes->devCtx != cryptoCbAesGcmMockHandle) { + return BAD_FUNC_ARG; + } + + slot = (MockSeKeySlotOffload*)aes->devCtx; + if (!slot->valid) { + return BAD_STATE_E; + } + + /* Track that decrypt callback was invoked */ + cryptoCbAesGcmDecryptCalled++; + + /* Initialize a temporary Aes for software crypto (simulating SE internal operation) */ + XMEMSET(&tempAes, 0, sizeof(tempAes)); + ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID); + if (ret != 0) return ret; + + ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz); + if (ret != 0) { + wc_AesFree(&tempAes); + return ret; + } + + /* Perform the actual decryption using software AES (simulating SE internal operation) */ + ret = wc_AesGcmDecrypt(&tempAes, + info->cipher.aesgcm_dec.out, + info->cipher.aesgcm_dec.in, + info->cipher.aesgcm_dec.sz, + info->cipher.aesgcm_dec.iv, + info->cipher.aesgcm_dec.ivSz, + info->cipher.aesgcm_dec.authTag, + info->cipher.aesgcm_dec.authTagSz, + info->cipher.aesgcm_dec.authIn, + info->cipher.aesgcm_dec.authInSz); + + wc_AesFree(&tempAes); + + return ret; + } + +#ifdef WOLF_CRYPTO_CB_FREE + /* Free operation - simulate SE key deletion */ + if (info->algo_type == WC_ALGO_TYPE_FREE && + info->free.algo == WC_ALGO_TYPE_CIPHER && + info->free.type == WC_CIPHER_AES) { + + Aes* aes = (Aes*)info->free.obj; + + if (aes != NULL && aes->devCtx == cryptoCbAesGcmMockHandle) { + /* "Delete" key from simulated SE */ + ForceZero(&mockSeKeyOffload, sizeof(mockSeKeyOffload)); + cryptoCbAesGcmFreeCalled++; + } + + return 0; + } +#endif + + return CRYPTOCB_UNAVAILABLE; +} + +/* + * Test: End-to-End AES-GCM Offload via CryptoCB + * This test verifies that: + * - AES-GCM encryption/decryption operations are routed through CryptoCb + * - Software AES is bypassed when offload is enabled + * - Encrypted output and auth tag are correct + * - Decryption via CryptoCb restores the original plaintext + */ +int test_wc_CryptoCb_AesGcm_EncryptDecrypt(void) +{ + EXPECT_DECLS; +#ifdef WOLFSSL_SMALL_STACK + Aes* aes = NULL; + byte* key = NULL; + byte* iv = NULL; + byte* aad = NULL; + byte* plaintext = NULL; + byte* ciphertext = NULL; + byte* decrypted = NULL; + byte* authTag = NULL; +#else + Aes aes[1]; + byte key[AES_128_KEY_SIZE]; + byte iv[GCM_NONCE_MID_SZ]; + byte aad[16]; + byte plaintext[32]; + byte ciphertext[32]; + byte decrypted[32]; + byte authTag[AES_BLOCK_SIZE]; +#endif + int ret; + int i; + int hasNonZero = 0; + +#ifdef WOLFSSL_SMALL_STACK + aes = (Aes*)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_TMP_BUFFER); + key = (byte*)XMALLOC(AES_128_KEY_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + iv = (byte*)XMALLOC(GCM_NONCE_MID_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + aad = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER); + plaintext = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ciphertext = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER); + decrypted = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER); + authTag = (byte*)XMALLOC(AES_BLOCK_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (aes == NULL || key == NULL || iv == NULL || aad == NULL || + plaintext == NULL || ciphertext == NULL || decrypted == NULL || + authTag == NULL) { + ret = MEMORY_E; + goto out; + } +#endif + + /* Initialize key, iv, aad, plaintext arrays */ + { + static const byte keyData[AES_128_KEY_SIZE] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + static const byte ivData[GCM_NONCE_MID_SZ] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b + }; + static const byte aadData[16] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + static const byte plaintextData[32] = { + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, + 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x21, 0x00, + 0x54, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x20, 0x32, 0x21, 0x00 + }; + XMEMCPY(key, keyData, AES_128_KEY_SIZE); + XMEMCPY(iv, ivData, GCM_NONCE_MID_SZ); + XMEMCPY(aad, aadData, 16); + XMEMCPY(plaintext, plaintextData, 32); + } + + XMEMSET(aes, 0, sizeof(Aes)); + XMEMSET(&mockSeKeyOffload, 0, sizeof(mockSeKeyOffload)); + XMEMSET(ciphertext, 0, 32); + XMEMSET(decrypted, 0, 32); + XMEMSET(authTag, 0, AES_BLOCK_SIZE); + + /* Reset test state */ + cryptoCbAesGcmSetKeyCalled = 0; + cryptoCbAesGcmEncryptCalled = 0; + cryptoCbAesGcmDecryptCalled = 0; + cryptoCbAesGcmFreeCalled = 0; + + /* Register test callback */ + ret = wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID, + test_CryptoCb_AesGcm_Offload_Cb, NULL); + ExpectIntEQ(ret, 0); + + /* Initialize Aes with device ID */ + ret = wc_AesInit(aes, NULL, TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID); + ExpectIntEQ(ret, 0); + ExpectIntEQ(aes->devId, TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID); + + /* Set key - should trigger CryptoCB and "import" to mock SE */ + ret = wc_AesGcmSetKey(aes, key, sizeof(key)); + ExpectIntEQ(ret, 0); + + /* Verify SetKey callback was invoked */ + ExpectIntEQ(cryptoCbAesGcmSetKeyCalled, 1); + + /* Verify handle stored in devCtx */ + ExpectPtrEq(aes->devCtx, cryptoCbAesGcmMockHandle); + + /* Verify key was "imported" to mock SE */ + ExpectIntEQ(mockSeKeyOffload.valid, 1); + ExpectIntEQ(mockSeKeyOffload.keySz, (int)sizeof(key)); + + /* Verify keylen metadata stored in Aes struct */ + ExpectIntEQ(aes->keylen, (int)sizeof(key)); + + /* Encrypt via wolfCrypt API - should route through CryptoCb */ + ret = wc_AesGcmEncrypt(aes, ciphertext, plaintext, 32, + iv, sizeof(iv), authTag, sizeof(authTag), + aad, 16); + ExpectIntEQ(ret, 0); + + /* Assert: Encrypt callback was invoked */ + ExpectIntEQ(cryptoCbAesGcmEncryptCalled, 1); + + /* Assert: Ciphertext is different from plaintext */ + ExpectIntNE(XMEMCMP(plaintext, ciphertext, 32), 0); + + /* Assert: Auth tag is non-zero */ + hasNonZero = 0; + for (i = 0; i < (int)sizeof(authTag); i++) { + if (authTag[i] != 0) { + hasNonZero = 1; + break; + } + } + ExpectIntEQ(hasNonZero, 1); + + /* Decrypt via wolfCrypt API - should route through CryptoCb */ + ret = wc_AesGcmDecrypt(aes, decrypted, ciphertext, 32, + iv, sizeof(iv), authTag, sizeof(authTag), + aad, 16); + ExpectIntEQ(ret, 0); + + /* Assert: Decrypt callback was invoked */ + ExpectIntEQ(cryptoCbAesGcmDecryptCalled, 1); + + /* Assert: Decrypted plaintext matches original */ + ExpectIntEQ(XMEMCMP(plaintext, decrypted, 32), 0); + +#ifdef WOLF_CRYPTO_CB_FREE + /* Free should trigger callback and "delete" key from mock SE */ + cryptoCbAesGcmFreeCalled = 0; + wc_AesFree(aes); + + /* Verify free callback invoked */ + ExpectIntEQ(cryptoCbAesGcmFreeCalled, 1); + + /* Verify devCtx cleared */ + ExpectPtrEq(aes->devCtx, NULL); + + /* Verify key was "deleted" from mock SE */ + ExpectIntEQ(mockSeKeyOffload.valid, 0); +#else + wc_AesFree(aes); +#endif + + /* Cleanup */ + wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID); + + /* Verify lifecycle: SetKey -> Encrypt -> Decrypt -> Free */ + ExpectIntEQ(cryptoCbAesGcmSetKeyCalled, 1); + ExpectIntEQ(cryptoCbAesGcmEncryptCalled, 1); + ExpectIntEQ(cryptoCbAesGcmDecryptCalled, 1); +#ifdef WOLF_CRYPTO_CB_FREE + ExpectIntEQ(cryptoCbAesGcmFreeCalled, 1); +#endif + +#ifdef WOLFSSL_SMALL_STACK +out: + XFREE(aes, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(iv, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(aad, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plaintext, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(ciphertext, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decrypted, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(authTag, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return EXPECT_RESULT(); +} + +#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY && !NO_AES && HAVE_AESGCM */ + diff --git a/tests/api/test_aes.h b/tests/api/test_aes.h index 99265f3331..261f0484ad 100644 --- a/tests/api/test_aes.h +++ b/tests/api/test_aes.h @@ -53,6 +53,19 @@ int test_wc_AesEaxDecryptAuth(void); int test_wc_GmacSetKey(void); int test_wc_GmacUpdate(void); +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \ + !defined(NO_AES) && defined(HAVE_AESGCM) +int test_wc_CryptoCb_AesSetKey(void); +int test_wc_CryptoCb_AesGcm_EncryptDecrypt(void); +#endif + +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \ + !defined(NO_AES) && defined(HAVE_AESGCM) +#define TEST_CRYPTOCB_AES_SETKEY_DECL , TEST_DECL_GROUP("aes", test_wc_CryptoCb_AesSetKey), \ + TEST_DECL_GROUP("aes", test_wc_CryptoCb_AesGcm_EncryptDecrypt) +#else +#define TEST_CRYPTOCB_AES_SETKEY_DECL +#endif #define TEST_AES_DECLS \ TEST_DECL_GROUP("aes", test_wc_AesSetKey), \ @@ -74,7 +87,8 @@ int test_wc_GmacUpdate(void); TEST_DECL_GROUP("aes", test_wc_AesCcmEncryptDecrypt), \ TEST_DECL_GROUP("aes", test_wc_AesXtsSetKey), \ TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt_Sizes), \ - TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt) + TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt) \ + TEST_CRYPTOCB_AES_SETKEY_DECL #if defined(WOLFSSL_AES_EAX) && defined(WOLFSSL_AES_256) && \ (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST) diff --git a/tests/api/test_ossl_x509_str.c b/tests/api/test_ossl_x509_str.c index 79f1ce5581..d628e08b37 100644 --- a/tests/api/test_ossl_x509_str.c +++ b/tests/api/test_ossl_x509_str.c @@ -36,9 +36,8 @@ #include #include -#if defined(OPENSSL_ALL) && \ - !defined(NO_RSA) && !defined(NO_FILESYSTEM) - +#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \ + !defined(NO_ASN_TIME) static int last_errcodes[10]; static int last_errdepths[10]; static int err_index = 0; @@ -187,8 +186,7 @@ int test_wolfSSL_X509_STORE_check_time(void) wolfSSL_X509_free(cert); cert = NULL; -#if defined(OPENSSL_ALL) && \ - !defined(NO_RSA) && !defined(NO_FILESYSTEM) +#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) err_index = 0; diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index d60e3abb67..eeaeec1cf6 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -388,12 +388,15 @@ int test_wc_PKCS7_EncodeData(void) #if defined(HAVE_PKCS7) && defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && \ !defined(NO_RSA) && !defined(NO_SHA256) -/* RSA sign raw digest callback */ +/* RSA sign raw digest callback + * This callback demonstrates HSM/secure element use case where the private + * key is not passed through PKCS7 structure but obtained independently. + */ static int rsaSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz, byte* out, word32 outSz, byte* privateKey, word32 privateKeySz, int devid, int hashOID) { - /* specific DigestInfo ASN.1 encoding prefix for a SHA2565 digest */ + /* specific DigestInfo ASN.1 encoding prefix for a SHA256 digest */ byte digInfoEncoding[] = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, @@ -407,6 +410,11 @@ static int rsaSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz, word32 idx = 0; RsaKey rsa; + /* privateKey may be NULL in HSM/secure element use case - we load it + * independently in this callback to simulate that scenario */ + (void)privateKey; + (void)privateKeySz; + /* SHA-256 required only for this example callback due to above * digInfoEncoding[] */ if (pkcs7 == NULL || digest == NULL || out == NULL || @@ -427,7 +435,33 @@ static int rsaSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz, return ret; } - ret = wc_RsaPrivateKeyDecode(privateKey, &idx, &rsa, privateKeySz); + /* Load key from test buffer - simulates HSM/secure element access */ +#if defined(USE_CERT_BUFFERS_2048) + ret = wc_RsaPrivateKeyDecode(client_key_der_2048, &idx, &rsa, + sizeof_client_key_der_2048); +#elif defined(USE_CERT_BUFFERS_1024) + ret = wc_RsaPrivateKeyDecode(client_key_der_1024, &idx, &rsa, + sizeof_client_key_der_1024); +#else + { + XFILE fp; + byte keyBuf[ONEK_BUF]; + int keySz; + + fp = XFOPEN("./certs/client-key.der", "rb"); + if (fp == XBADFILE) { + wc_FreeRsaKey(&rsa); + return -1; + } + keySz = (int)XFREAD(keyBuf, 1, sizeof(keyBuf), fp); + XFCLOSE(fp); + if (keySz <= 0) { + wc_FreeRsaKey(&rsa); + return -1; + } + ret = wc_RsaPrivateKeyDecode(keyBuf, &idx, &rsa, (word32)keySz); + } +#endif /* sign DigestInfo */ if (ret == 0) { @@ -451,6 +485,102 @@ static int rsaSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz, } #endif +#if defined(HAVE_PKCS7) && defined(HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK) && \ + defined(HAVE_ECC) && !defined(NO_SHA256) +/* ECC sign raw digest callback + * This callback demonstrates HSM/secure element use case where the private + * key is not passed through PKCS7 structure but obtained independently. + * Note: This example callback is hash-agnostic and will work with any + * hash algorithm. The hashOID parameter can be used to validate or select + * different signing behavior if needed. + */ +static int eccSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz, + byte* out, word32 outSz, byte* privateKey, + word32 privateKeySz, int devid, int hashOID) +{ + int ret; + word32 idx = 0; + word32 sigSz = outSz; +#ifdef WOLFSSL_SMALL_STACK + ecc_key* ecc = NULL; +#else + ecc_key ecc[1]; +#endif + + /* privateKey may be NULL in HSM/secure element use case - we load it + * independently in this callback to simulate that scenario */ + (void)privateKey; + (void)privateKeySz; + (void)hashOID; + + if (pkcs7 == NULL || digest == NULL || out == NULL) { + return -1; + } + +#ifdef WOLFSSL_SMALL_STACK + ecc = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap, DYNAMIC_TYPE_ECC); + if (ecc == NULL) { + return MEMORY_E; + } +#endif + + /* set up ECC key */ + ret = wc_ecc_init_ex(ecc, pkcs7->heap, devid); + if (ret != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(ecc, pkcs7->heap, DYNAMIC_TYPE_ECC); + #endif + return ret; + } + + /* Load key from test buffer - simulates HSM/secure element access */ +#if defined(USE_CERT_BUFFERS_256) + ret = wc_EccPrivateKeyDecode(ecc_clikey_der_256, &idx, ecc, + sizeof_ecc_clikey_der_256); +#else + { + XFILE fp; + byte keyBuf[ONEK_BUF]; + int keySz; + + fp = XFOPEN("./certs/client-ecc-key.der", "rb"); + if (fp == XBADFILE) { + wc_ecc_free(ecc); + #ifdef WOLFSSL_SMALL_STACK + XFREE(ecc, pkcs7->heap, DYNAMIC_TYPE_ECC); + #endif + return -1; + } + keySz = (int)XFREAD(keyBuf, 1, sizeof(keyBuf), fp); + XFCLOSE(fp); + if (keySz <= 0) { + wc_ecc_free(ecc); + #ifdef WOLFSSL_SMALL_STACK + XFREE(ecc, pkcs7->heap, DYNAMIC_TYPE_ECC); + #endif + return -1; + } + ret = wc_EccPrivateKeyDecode(keyBuf, &idx, ecc, (word32)keySz); + } +#endif + + /* sign digest */ + if (ret == 0) { + ret = wc_ecc_sign_hash(digest, digestSz, out, &sigSz, pkcs7->rng, ecc); + if (ret == 0) { + ret = (int)sigSz; + } + } + + wc_ecc_free(ecc); +#ifdef WOLFSSL_SMALL_STACK + XFREE(ecc, pkcs7->heap, DYNAMIC_TYPE_ECC); +#endif + + return ret; +} +#endif + #if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) typedef struct encodeSignedDataStream { byte out[FOURK_BUF*3]; @@ -757,8 +887,7 @@ int test_wc_PKCS7_EncodeSignedData(void) if (pkcs7 != NULL) { pkcs7->content = data; pkcs7->contentSz = (word32)sizeof(data); - pkcs7->privateKey = key; - pkcs7->privateKeySz = (word32)sizeof(key); + /* privateKey not set - callback simulates HSM/secure element access */ pkcs7->encryptOID = RSAk; pkcs7->hashOID = SHA256h; pkcs7->rng = &rng; @@ -769,6 +898,47 @@ int test_wc_PKCS7_EncodeSignedData(void) ExpectIntGT(wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz), 0); #endif +#if defined(HAVE_PKCS7) && defined(HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK) && \ + defined(HAVE_ECC) && !defined(NO_SHA256) + /* test ECC sign raw digest callback, if using ECC and compiled in. + * Example callback assumes SHA-256, so only run test if compiled in. */ + { + #if defined(USE_CERT_BUFFERS_256) + byte eccCert[sizeof(cliecc_cert_der_256)]; + word32 eccCertSz = (word32)sizeof(eccCert); + XMEMCPY(eccCert, cliecc_cert_der_256, eccCertSz); + #else + byte eccCert[ONEK_BUF]; + int eccCertSz; + XFILE eccFp = XBADFILE; + + ExpectTrue((eccFp = XFOPEN("./certs/client-ecc-cert.der", "rb")) != + XBADFILE); + ExpectIntGT(eccCertSz = (int)XFREAD(eccCert, 1, ONEK_BUF, eccFp), 0); + if (eccFp != XBADFILE) + XFCLOSE(eccFp); + #endif + + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, eccCert, (word32)eccCertSz), 0); + + if (pkcs7 != NULL) { + pkcs7->content = data; + pkcs7->contentSz = (word32)sizeof(data); + /* privateKey not set - callback simulates HSM/secure element access */ + pkcs7->encryptOID = ECDSAk; + pkcs7->hashOID = SHA256h; + pkcs7->rng = &rng; + } + + ExpectIntEQ(wc_PKCS7_SetEccSignRawDigestCb(pkcs7, eccSignRawDigestCb), 0); + + ExpectIntGT(wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz), 0); + } +#endif + wc_PKCS7_Free(pkcs7); DoExpectIntEQ(wc_FreeRng(&rng), 0); diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 3e1dcf050f..f6e2615e99 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -2683,9 +2683,9 @@ static WC_INLINE void bench_stats_start(int* count, double* start) #endif } -#ifdef WOLFSSL_USE_SAVE_VECTOR_REGISTERS +#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) #define bench_stats_start(count, start) do { \ - SAVE_VECTOR_REGISTERS(pr_err( \ + SAVE_VECTOR_REGISTERS(WOLFSSL_DEBUG_PRINTF( \ "ERROR: SAVE_VECTOR_REGISTERS failed for benchmark run."); \ return; ); \ bench_stats_start(count, start); \ @@ -3161,7 +3161,7 @@ static void bench_stats_sym_finish(const char* desc, int useDeviceID, (void)useDeviceID; (void)ret; -#ifdef WOLFSSL_USE_SAVE_VECTOR_REGISTERS +#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) RESTORE_VECTOR_REGISTERS(); #elif defined(WOLFSSL_LINUXKM) kernel_fpu_end(); @@ -3559,7 +3559,7 @@ static void bench_stats_asym_finish_ex(const char* algo, int strength, (void)useDeviceID; (void)ret; -#ifdef WOLFSSL_USE_SAVE_VECTOR_REGISTERS +#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) RESTORE_VECTOR_REGISTERS(); #elif defined(WOLFSSL_LINUXKM) kernel_fpu_end(); @@ -16024,6 +16024,20 @@ void bench_sphincsKeySign(byte level, byte optim) return (double)ns / 1000000000.0; } +#elif defined(WOLFSSL_BSDKM) + + #include + double current_time(int reset) + { + (void)reset; + struct timespec ts; + int64_t result = 0; + + getnanouptime(&ts); + result = (int64_t) ts.tv_sec + (int64_t) ts.tv_nsec / NANOSECOND; + return (double)result; + } + #elif defined(WOLFSSL_GAISLER_BCC) #include diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 8abec2905f..7217c7f871 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -4365,6 +4365,24 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt( #ifdef WOLF_CRYPTO_CB if (aes->devId != INVALID_DEVID) { + #ifdef WOLF_CRYPTO_CB_AES_SETKEY + int ret = wc_CryptoCb_AesSetKey(aes, userKey, keylen); + if (ret == 0) { + /* Callback succeeded - SE owns the key */ + aes->keylen = (int)keylen; + if (iv != NULL) + XMEMCPY(aes->reg, iv, WC_AES_BLOCK_SIZE); + else + XMEMSET(aes->reg, 0, WC_AES_BLOCK_SIZE); + return 0; + } + else if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + aes->devCtx = NULL; + return ret; + } + /* CRYPTOCB_UNAVAILABLE: continue to software setup */ + #endif + /* Standard CryptoCB path - copy key to devKey for encrypt/decrypt offload */ if (keylen > sizeof(aes->devKey)) { return BAD_FUNC_ARG; } @@ -4791,6 +4809,33 @@ static void AesSetKey_C(Aes* aes, const byte* key, word32 keySz, int dir) return BAD_FUNC_ARG; } + #ifdef WOLF_CRYPTO_CB + if (aes->devId != INVALID_DEVID) { + #ifdef WOLF_CRYPTO_CB_AES_SETKEY + ret = wc_CryptoCb_AesSetKey(aes, userKey, keylen); + if (ret == 0) { + /* Callback succeeded - SE owns the key */ + aes->keylen = (int)keylen; + if (iv != NULL) + XMEMCPY(aes->reg, iv, WC_AES_BLOCK_SIZE); + else + XMEMSET(aes->reg, 0, WC_AES_BLOCK_SIZE); + return 0; + } + else if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + aes->devCtx = NULL; + return ret; + } + /* CRYPTOCB_UNAVAILABLE: continue to software setup */ + #endif + /* Standard CryptoCB path - copy key to devKey */ + if (keylen > sizeof(aes->devKey)) { + return BAD_FUNC_ARG; + } + XMEMCPY(aes->devKey, userKey, keylen); + } + #endif + #ifdef WOLFSSL_MAXQ10XX_CRYPTO if (wc_MAXQ10XX_AesSetKey(aes, userKey, keylen) != 0) { return WC_HW_E; @@ -7454,46 +7499,55 @@ int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len) } #else #if !defined(FREESCALE_LTC_AES_GCM) && !defined(WOLFSSL_PSOC6_CRYPTO) + + +#ifdef WOLF_CRYPTO_CB_AES_SETKEY + if ((ret == 0) && (aes->devId != INVALID_DEVID && aes->devCtx != NULL)) { + /* SE owns key - skip H and M table generation */ + } + else +#endif if (ret == 0) { VECTOR_REGISTERS_PUSH; - /* AES-NI code generates its own H value, but generate it here too, to - * assure pure-C fallback is always usable. - */ + + /* Generate H = AES_Encrypt(key, 0^128) */ ret = wc_AesEncrypt(aes, iv, aes->gcm.H); if (ret == 0) { - #if defined(GCM_TABLE) || defined(GCM_TABLE_4BIT) +#if defined(GCM_TABLE) || defined(GCM_TABLE_4BIT) #if defined(WOLFSSL_AESNI) && defined(GCM_TABLE_4BIT) if (aes->use_aesni) { #if defined(WC_C_DYNAMIC_FALLBACK) #ifdef HAVE_INTEL_AVX2 if (IS_INTEL_AVX2(intel_flags)) { - GCM_generate_m0_avx2(aes->gcm.H, (byte*)aes->gcm.M0); + GCM_generate_m0_avx2(aes->gcm.H, + (byte*)aes->gcm.M0); } else #endif #if defined(HAVE_INTEL_AVX1) if (IS_INTEL_AVX1(intel_flags)) { - GCM_generate_m0_avx1(aes->gcm.H, (byte*)aes->gcm.M0); + GCM_generate_m0_avx1(aes->gcm.H, + (byte*)aes->gcm.M0); } else #endif { - GCM_generate_m0_aesni(aes->gcm.H, (byte*)aes->gcm.M0); + GCM_generate_m0_aesni(aes->gcm.H, + (byte*)aes->gcm.M0); } - #endif + #endif /* WC_C_DYNAMIC_FALLBACK */ } else - #endif + #endif /* AESNI */ { GenerateM0(&aes->gcm); } - #endif /* GCM_TABLE || GCM_TABLE_4BIT */ +#endif /* GCM_TABLE || GCM_TABLE_4BIT */ } VECTOR_REGISTERS_POP; } - #endif /* !FREESCALE_LTC_AES_GCM && !WOLFSSL_PSOC6_CRYPTO */ #endif @@ -7503,7 +7557,15 @@ int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len) #ifdef WOLF_CRYPTO_CB if (aes->devId != INVALID_DEVID) { - XMEMCPY(aes->devKey, key, len); + #ifdef WOLF_CRYPTO_CB_AES_SETKEY + if (aes->devCtx != NULL) { + /* SE owns key - don't copy to devKey */ + } + else + #endif + { + XMEMCPY(aes->devKey, key, len); + } } #endif @@ -13302,6 +13364,7 @@ int wc_AesInit(Aes* aes, void* heap, int devId) #if defined(WOLF_CRYPTO_CB) || defined(WOLFSSL_STM32U5_DHUK) aes->devId = devId; + aes->devCtx = NULL; #else (void)devId; #endif @@ -13383,10 +13446,6 @@ int wc_AesInit_Label(Aes* aes, const char* label, void* heap, int devId) /* Free Aes resources */ void wc_AesFree(Aes* aes) { -#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) - int ret = 0; -#endif - if (aes == NULL) { return; } @@ -13396,19 +13455,17 @@ void wc_AesFree(Aes* aes) if (aes->devId != INVALID_DEVID) #endif { - ret = wc_CryptoCb_Free(aes->devId, WC_ALGO_TYPE_CIPHER, - WC_CIPHER_AES, (void*)aes); - /* If they want the standard free, they can call it themselves */ - /* via their callback setting devId to INVALID_DEVID */ - /* otherwise assume the callback handled it */ + int ret = wc_CryptoCb_Free(aes->devId, WC_ALGO_TYPE_CIPHER, + WC_CIPHER_AES, aes); + #ifdef WOLF_CRYPTO_CB_AES_SETKEY + aes->devCtx = NULL; /* Clear device context handle */ + #endif + /* If callback wants standard free, it can set devId to INVALID_DEVID. + * Otherwise assume the callback handled cleanup. */ if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) return; /* fall-through when unavailable */ } - - /* silence compiler warning */ - (void)ret; - #endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_FREE */ #ifdef WC_DEBUG_CIPHER_LIFECYCLE diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 4ea0743ce6..c2f48e98d2 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -13839,7 +13839,18 @@ static int StoreEccKey(DecodedCert* cert, const byte* source, word32* srcIdx, ret = ASN_PARSE_E; #endif } - + #if defined(WOLFSSL_RENESAS_FSPSM_TLS) || defined(WOLFSSL_RENESAS_TSIP_TLS) + cert->sigCtx.CertAtt.pubkey_n_start = + cert->sigCtx.CertAtt.pubkey_e_start = + GetASNItem_DataIdx( + dataASN[ECCCERTKEYASN_IDX_SUBJPUBKEY], source) + 1; + cert->sigCtx.CertAtt.pubkey_n_len = + ((dataASN[ECCCERTKEYASN_IDX_SUBJPUBKEY].data.ref.length - 1) >> 1); + cert->sigCtx.CertAtt.pubkey_e_start += + cert->sigCtx.CertAtt.pubkey_n_len; + cert->sigCtx.CertAtt.pubkey_e_len = + cert->sigCtx.CertAtt.pubkey_n_len; + #endif #ifdef WOLFSSL_MAXQ10XX_TLS cert->publicKeyIndex = GetASNItem_DataIdx(dataASN[ECCCERTKEYASN_IDX_SUBJPUBKEY], source) @@ -21195,6 +21206,7 @@ static int DecodeAuthInfo(const byte* input, word32 sz, DecodedCert* cert) int length = 0; byte b = 0; word32 oid; + int aiaIdx; WOLFSSL_ENTER("DecodeAuthInfo"); @@ -21219,14 +21231,29 @@ static int DecodeAuthInfo(const byte* input, word32 sz, DecodedCert* cert) if (GetLength(input, &idx, &length, sz) < 0) return ASN_PARSE_E; - /* Set ocsp entry */ + if (b == GENERALNAME_URI) { + /* Add to AIA list if space. */ + aiaIdx = cert->extAuthInfoListSz; + if (aiaIdx < WOLFSSL_MAX_AIA_ENTRIES) { + cert->extAuthInfoList[aiaIdx].method = oid; + cert->extAuthInfoList[aiaIdx].uri = input + idx; + cert->extAuthInfoList[aiaIdx].uriSz = (word32)length; + cert->extAuthInfoListSz++; + } + else { + cert->extAuthInfoListOverflow = 1; + WOLFSSL_MSG("AIA list overflow"); + } + } + + /* Set first ocsp entry */ if (b == GENERALNAME_URI && oid == AIA_OCSP_OID && cert->extAuthInfo == NULL) { cert->extAuthInfoSz = length; cert->extAuthInfo = input + idx; } #ifdef WOLFSSL_ASN_CA_ISSUER - /* Set CaIssuers entry */ + /* Set first CaIssuers entry */ else if ((b == GENERALNAME_URI) && oid == AIA_CA_ISSUER_OID && cert->extAuthInfoCaIssuer == NULL) { @@ -21242,6 +21269,7 @@ static int DecodeAuthInfo(const byte* input, word32 sz, DecodedCert* cert) word32 idx = 0; int length = 0; int ret = 0; + int aiaIdx; WOLFSSL_ENTER("DecodeAuthInfo"); @@ -21263,27 +21291,41 @@ static int DecodeAuthInfo(const byte* input, word32 sz, DecodedCert* cert) if (ret == 0) { word32 sz32; - /* Check we have OCSP and URI. */ - if ((dataASN[ACCESSDESCASN_IDX_METH].data.oid.sum == AIA_OCSP_OID) && - (dataASN[ACCESSDESCASN_IDX_LOC].tag == GENERALNAME_URI) && - (cert->extAuthInfo == NULL)) { - /* Store URI for OCSP lookup. */ - GetASN_GetConstRef(&dataASN[ACCESSDESCASN_IDX_LOC], - &cert->extAuthInfo, &sz32); - cert->extAuthInfoSz = (int)sz32; + if (dataASN[ACCESSDESCASN_IDX_LOC].tag == GENERALNAME_URI) { + const byte* uri = NULL; + + GetASN_GetConstRef(&dataASN[ACCESSDESCASN_IDX_LOC], &uri, &sz32); + + /* Add to AIA list if space. */ + aiaIdx = cert->extAuthInfoListSz; + if (aiaIdx < WOLFSSL_MAX_AIA_ENTRIES) { + cert->extAuthInfoList[aiaIdx].method = + dataASN[ACCESSDESCASN_IDX_METH].data.oid.sum; + cert->extAuthInfoList[aiaIdx].uri = uri; + cert->extAuthInfoList[aiaIdx].uriSz = sz32; + cert->extAuthInfoListSz++; + } + else { + cert->extAuthInfoListOverflow = 1; + WOLFSSL_MSG("AIA list overflow"); + } + + /* Set first OCSP entry. */ + if ((dataASN[ACCESSDESCASN_IDX_METH].data.oid.sum == + AIA_OCSP_OID) && (cert->extAuthInfo == NULL)) { + cert->extAuthInfo = uri; + cert->extAuthInfoSz = (int)sz32; + } + #ifdef WOLFSSL_ASN_CA_ISSUER + /* Set first CA Issuer entry. */ + else if ((dataASN[ACCESSDESCASN_IDX_METH].data.oid.sum == + AIA_CA_ISSUER_OID) && + (cert->extAuthInfoCaIssuer == NULL)) { + cert->extAuthInfoCaIssuer = uri; + cert->extAuthInfoCaIssuerSz = (int)sz32; + } + #endif } - #ifdef WOLFSSL_ASN_CA_ISSUER - /* Check we have CA Issuer and URI. */ - else if ((dataASN[ACCESSDESCASN_IDX_METH].data.oid.sum == - AIA_CA_ISSUER_OID) && - (dataASN[ACCESSDESCASN_IDX_LOC].tag == GENERALNAME_URI) && - (cert->extAuthInfoCaIssuer == NULL)) { - /* Set CaIssuers entry */ - GetASN_GetConstRef(&dataASN[ACCESSDESCASN_IDX_LOC], - &cert->extAuthInfoCaIssuer, &sz32); - cert->extAuthInfoCaIssuerSz = (int)sz32; - } - #endif /* Otherwise skip. */ } } diff --git a/wolfcrypt/src/cpuid.c b/wolfcrypt/src/cpuid.c index 5c3e333ffe..9d9b458e8a 100644 --- a/wolfcrypt/src/cpuid.c +++ b/wolfcrypt/src/cpuid.c @@ -113,7 +113,11 @@ static WC_INLINE void cpuid_set_flags(void) { + #ifdef WOLFSSL_BSDKM + if (WOLFSSL_ATOMIC_LOAD_UINT(cpuid_flags) == WC_CPUID_INITIALIZER) { + #else if (WOLFSSL_ATOMIC_LOAD(cpuid_flags) == WC_CPUID_INITIALIZER) { + #endif cpuid_flags_t new_cpuid_flags = 0, old_cpuid_flags = WC_CPUID_INITIALIZER; if (cpuid_flag(1, 0, ECX, 28)) { new_cpuid_flags |= CPUID_AVX1 ; } diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index 04051041bd..bb56894214 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -1537,6 +1537,36 @@ int wc_CryptoCb_AesEcbDecrypt(Aes* aes, byte* out, return wc_CryptoCb_TranslateErrorCode(ret); } #endif /* HAVE_AES_ECB */ + +#ifdef WOLF_CRYPTO_CB_AES_SETKEY +int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (aes == NULL || key == NULL) + return BAD_FUNC_ARG; + + if (aes->devId == INVALID_DEVID) + return CRYPTOCB_UNAVAILABLE; + + /* locate registered callback */ + dev = wc_CryptoCb_FindDevice(aes->devId, WC_ALGO_TYPE_CIPHER); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_CIPHER; + cryptoInfo.cipher.type = WC_CIPHER_AES; + cryptoInfo.cipher.aessetkey.aes = aes; + cryptoInfo.cipher.aessetkey.key = key; + cryptoInfo.cipher.aessetkey.keySz = keySz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} +#endif /* WOLF_CRYPTO_CB_AES_SETKEY */ #endif /* !NO_AES */ #ifndef NO_DES3 diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index da309eb2ab..c34e140d6b 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -13214,7 +13214,7 @@ int ecc_mul2add(ecc_point* A, mp_int* kA, err = add_entry(idx1, A); } } - if (err == MP_OKAY && idx1 != -1) { + if (err == MP_OKAY && idx1 != -1 && fp_cache[idx1].lru_count < (INT_MAX-1)) { /* increment LRU */ ++(fp_cache[idx1].lru_count); } @@ -13231,7 +13231,7 @@ int ecc_mul2add(ecc_point* A, mp_int* kA, } } - if (err == MP_OKAY && idx2 != -1) { + if (err == MP_OKAY && idx2 != -1 && fp_cache[idx2].lru_count < (INT_MAX-1)) { /* increment LRU */ ++(fp_cache[idx2].lru_count); } @@ -13368,7 +13368,7 @@ int wc_ecc_mulmod_ex(const mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, if (idx >= 0) err = add_entry(idx, G); } - if (err == MP_OKAY && idx >= 0) { + if (err == MP_OKAY && idx >= 0 && fp_cache[idx].lru_count < (INT_MAX-1)) { /* increment LRU */ ++(fp_cache[idx].lru_count); } @@ -13539,7 +13539,7 @@ int wc_ecc_mulmod_ex2(const mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, if (idx >= 0) err = add_entry(idx, G); } - if (err == MP_OKAY && idx >= 0) { + if (err == MP_OKAY && idx >= 0 && fp_cache[idx].lru_count < (INT_MAX-1)) { /* increment LRU */ ++(fp_cache[idx].lru_count); } diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c new file mode 100644 index 0000000000..27801f010c --- /dev/null +++ b/wolfcrypt/src/evp_pk.c @@ -0,0 +1,1909 @@ +/* evp_pk.c + * + * Copyright (C) 2006-2025 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 3 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 + */ + +#include + +#if !defined(WOLFSSL_EVP_PK_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning evp_pk.c does not need to be compiled separately from ssl.c + #endif +#elif defined(WOLFCRYPT_ONLY) +#else + +/******************************************************************************* + * START OF d2i APIs + ******************************************************************************/ + +#ifndef NO_CERTS + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/** + * Make an EVP PKEY and put data and type in. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @param [in] type The type of public/private key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2i_make_pkey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + word32 memSz, int priv, int type) +{ + WOLFSSL_EVP_PKEY* pkey; + int ret = 1; + + /* Get or create the EVP PKEY object. */ + if (*out != NULL) { + pkey = *out; + } + else { + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + WOLFSSL_MSG("wolfSSL_EVP_PKEY_new error"); + return 0; + } + } + + /* Set the size and allocate memory for key data to be copied into. */ + pkey->pkey_sz = (int)memSz; + pkey->pkey.ptr = (char*)XMALLOC((size_t)memSz, NULL, + priv ? DYNAMIC_TYPE_PRIVATE_KEY : DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + ret = 0; + } + if (ret == 1) { + /* Copy in key data, set key type passed in and return object. */ + XMEMCPY(pkey->pkey.ptr, mem, memSz); + pkey->type = type; + *out = pkey; + } + if ((ret == 0) && (*out == NULL)) { + /* Dispose of object allocated in this function. */ + wolfSSL_EVP_PKEY_free(pkey); + } + + return ret; +} + +#if !defined(NO_RSA) +/** + * Try to make an RSA EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryRsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_RSA* rsaObj = NULL; + word32 keyIdx = 0; + int isRsaKey; + int ret = 1; + WC_DECLARE_VAR(rsa, RsaKey, 1, NULL); + + WC_ALLOC_VAR_EX(rsa, RsaKey, 1, NULL, DYNAMIC_TYPE_RSA, return 0); + + XMEMSET(rsa, 0, sizeof(RsaKey)); + + if (wc_InitRsaKey(rsa, NULL) != 0) { + WC_FREE_VAR_EX(rsa, NULL, DYNAMIC_TYPE_RSA); + return 0; + } + /* Try decoding data as an RSA private/public 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); + WC_FREE_VAR_EX(rsa, NULL, DYNAMIC_TYPE_RSA); + + if (!isRsaKey) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create RSA key object from data. */ + rsaObj = wolfssl_rsa_d2i(NULL, mem, keyIdx, + priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC); + if (rsaObj == NULL) { + ret = 0; + } + if (ret == 1) { + /* Create an EVP PKEY object. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_RSA); + } + if (ret == 1) { + /* Put RSA key object into EVP PKEY object. */ + (*out)->ownRsa = 1; + (*out)->rsa = rsaObj; + } + if (ret == 0) { + wolfSSL_RSA_free(rsaObj); + } + + return ret; +} +#endif /* !NO_RSA */ + +#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) +/** + * Try to make an ECC EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryEccKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_EC_KEY* ec = NULL; + word32 keyIdx = 0; + int isEccKey; + int ret = 1; + WC_DECLARE_VAR(ecc, ecc_key, 1, NULL); + + WC_ALLOC_VAR_EX(ecc, ecc_key, 1, NULL, DYNAMIC_TYPE_ECC, return 0); + + XMEMSET(ecc, 0, sizeof(ecc_key)); + + if (wc_ecc_init(ecc) != 0) { + WC_FREE_VAR_EX(ecc, NULL, DYNAMIC_TYPE_ECC); + return 0; + } + + /* Try decoding data as an ECC private/public key. */ + 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); + WC_FREE_VAR_EX(ecc, NULL, DYNAMIC_TYPE_ECC); + + if (!isEccKey) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create EC key object from data. */ + ec = wolfSSL_EC_KEY_new(); + if (ec == NULL) { + ret = 0; + } + if ((ret == 1) && (wolfSSL_EC_KEY_LoadDer_ex(ec, mem, keyIdx, + priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { + ret = 0; + } + if (ret == 1) { + /* Create an EVP PKEY object. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_EC); + } + if (ret == 1) { + /* Put RSA key object into EVP PKEY object. */ + (*out)->ownEcc = 1; + (*out)->ecc = ec; + } + if (ret == 0) { + wolfSSL_EC_KEY_free(ec); + } + + return ret; +} +#endif /* HAVE_ECC && OPENSSL_EXTRA */ + +#if !defined(NO_DSA) +/** + * Try to make a DSA EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_DSA* dsaObj; + word32 keyIdx = 0; + int isDsaKey; + int ret = 1; + WC_DECLARE_VAR(dsa, DsaKey, 1, NULL); + + WC_ALLOC_VAR_EX(dsa, DsaKey, 1, NULL, DYNAMIC_TYPE_DSA, return 0); + + XMEMSET(dsa, 0, sizeof(DsaKey)); + + if (wc_InitDsaKey(dsa) != 0) { + WC_FREE_VAR_EX(dsa, NULL, DYNAMIC_TYPE_DSA); + return 0; + } + + /* Try decoding data as a DSA private/public key. */ + if (priv) { + isDsaKey = + (wc_DsaPrivateKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0); + } + else { + isDsaKey = + (wc_DsaPublicKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0); + } + wc_FreeDsaKey(dsa); + WC_FREE_VAR_EX(dsa, NULL, DYNAMIC_TYPE_DSA); + + /* test if DSA key */ + if (!isDsaKey) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create DSA key object from data. */ + dsaObj = wolfSSL_DSA_new(); + if (dsaObj == NULL) { + ret = 0; + } + if ((ret == 1) && (wolfSSL_DSA_LoadDer_ex(dsaObj, mem, keyIdx, + priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { + ret = 0; + } + if (ret == 1) { + /* Create an EVP PKEY object. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DSA); + } + if (ret == 1) { + /* Put RSA key object into EVP PKEY object. */ + (*out)->ownDsa = 1; + (*out)->dsa = dsaObj; + } + if (ret == 0) { + wolfSSL_DSA_free(dsaObj); + } + + 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)) +/** + * Try to make a DH EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_DH* dhObj; + int isDhKey; + word32 keyIdx = 0; + int ret = 1; + WC_DECLARE_VAR(dh, DhKey, 1, NULL); + + WC_ALLOC_VAR_EX(dh, DhKey, 1, NULL, DYNAMIC_TYPE_DH, return 0); + + XMEMSET(dh, 0, sizeof(DhKey)); + + if (wc_InitDhKey(dh) != 0) { + WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); + return 0; + } + + /* Try decoding data as a DH public key. */ + isDhKey = (wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz) == 0); + wc_FreeDhKey(dh); + WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); + + /* test if DH key */ + if (!isDhKey) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create DH key object from data. */ + dhObj = wolfSSL_DH_new(); + if (dhObj == NULL) { + ret = 0; + } + if ((ret == 1) && (wolfSSL_DH_LoadDer(dhObj, mem, keyIdx) != 1)) { + ret = 0; + } + if (ret == 1) { + /* Create an EVP PKEY object. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DH); + } + if (ret == 1) { + /* Put RSA key object into EVP PKEY object. */ + (*out)->ownDh = 1; + (*out)->dh = dhObj; + } + if (ret == 0) { + wolfSSL_DH_free(dhObj); + } + + 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)) +/** + * Try to make a DH EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_DH* dhObj; + word32 keyIdx = 0; + DhKey* key = NULL; + int elements; + int ret = 1; + + /* Create DH key object from data. */ + dhObj = wolfSSL_DH_new(); + if (dhObj == NULL) { + return 0; + } + + key = (DhKey*)dhObj->internal; + /* Try decoding data as a DH public key. */ + if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) != 0) { + ret = 0; + } + if (ret == 1) { + /* DH key has data and is external to DH object. */ + elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; + if (priv) { + elements |= ELEMENT_PRV; + } + if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS ) { + ret = 0; + } + } + if (ret == 1) { + /* Create an EVP PKEY object. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DH); + } + if (ret == 1) { + /* Put RSA key object into EVP PKEY object. */ + (*out)->ownDh = 1; + (*out)->dh = dhObj; + } + if (ret == 0) { + wolfSSL_DH_free(dhObj); + } + + return ret; +} +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ + +#ifdef HAVE_FALCON +/** + * Attempt to import a private Falcon key at a specified level. + * + * @param [in] falcon Falcon key object. + * @param [in] level Level of Falcon key. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2i_falcon_priv_key_level(falcon_key* falcon, byte level, + const unsigned char* mem, long memSz) +{ + return (wc_falcon_set_level(falcon, level) == 0) && + (wc_falcon_import_private_only(mem, (word32)memSz, falcon) == 0); +} + +/** + * Attempt to import a public Falcon key at a specified level. + * + * @param [in] falcon Falcon key object. + * @param [in] level Level of Falcon key. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2i_falcon_pub_key_level(falcon_key* falcon, byte level, + const unsigned char* mem, long memSz) +{ + return (wc_falcon_set_level(falcon, level) == 0) && + (wc_falcon_import_public(mem, (word32)memSz, falcon) == 0); +} + +/** + * Try to make a Falcon EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryFalconKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + int isFalcon = 0; + WC_DECLARE_VAR(falcon, falcon_key, 1, NULL); + + WC_ALLOC_VAR_EX(falcon, falcon_key, 1, NULL, DYNAMIC_TYPE_FALCON, + return 0); + + if (wc_falcon_init(falcon) != 0) { + WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON); + return 0; + } + + /* Try decoding data as a Falcon private/public key. */ + if (priv) { + /* Try level 1 */ + isFalcon = d2i_falcon_priv_key_level(falcon, 1, mem, memSz); + if (!isFalcon) { + /* Try level 5 */ + isFalcon = d2i_falcon_priv_key_level(falcon, 5, mem, memSz); + } + } + else { + /* Try level 1 */ + isFalcon = d2i_falcon_pub_key_level(falcon, 1, mem, memSz); + if (!isFalcon) { + /* Try level 5 */ + isFalcon = d2i_falcon_pub_key_level(falcon, 5, mem, memSz); + } + } + /* Dispose of any Falcon key created. */ + wc_falcon_free(falcon); + WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON); + + if (!isFalcon) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create an EVP PKEY object. */ + return d2i_make_pkey(out, NULL, 0, priv, WC_EVP_PKEY_FALCON); +} +#endif /* HAVE_FALCON */ + +#ifdef HAVE_DILITHIUM +/** + * Attempt to import a private Dilithium key at a specified level. + * + * @param [in] dilithium Dilithium key object. + * @param [in] level Level of Dilithium key. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2i_dilithium_priv_key_level(dilithium_key* dilithium, byte level, + const unsigned char* mem, long memSz) +{ + return (wc_dilithium_set_level(dilithium, level) == 0) && + (wc_dilithium_import_private(mem, (word32)memSz, dilithium) == 0); +} + +/** + * Attempt to import a public Dilithium key at a specified level. + * + * @param [in] dilithium Dilithium key object. + * @param [in] level Level of Dilithium key. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2i_dilithium_pub_key_level(dilithium_key* dilithium, byte level, + const unsigned char* mem, long memSz) +{ + return (wc_dilithium_set_level(dilithium, level) == 0) && + (wc_dilithium_import_public(mem, (word32)memSz, dilithium) == 0); +} + +/** + * Try to make a Dilithium EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryDilithiumKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + int isDilithium = 0; + WC_DECLARE_VAR(dilithium, dilithium_key, 1, NULL); + + WC_ALLOC_VAR_EX(dilithium, dilithium_key, 1, NULL, DYNAMIC_TYPE_DILITHIUM, + return 0); + + if (wc_dilithium_init(dilithium) != 0) { + WC_FREE_VAR_EX(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); + return 0; + } + + /* Try decoding data as a Dilithium private/public key. */ + if (priv) { + isDilithium = d2i_dilithium_priv_key_level(dilithium, WC_ML_DSA_44, + mem, memSz); + if (!isDilithium) { + isDilithium = d2i_dilithium_priv_key_level(dilithium, WC_ML_DSA_65, + mem, memSz); + } + if (!isDilithium) { + isDilithium = d2i_dilithium_priv_key_level(dilithium, WC_ML_DSA_87, + mem, memSz); + } + } + else { + isDilithium = d2i_dilithium_pub_key_level(dilithium, WC_ML_DSA_44, + mem, memSz); + if (!isDilithium) { + isDilithium = d2i_dilithium_pub_key_level(dilithium, WC_ML_DSA_65, + mem, memSz); + } + if (!isDilithium) { + isDilithium = d2i_dilithium_pub_key_level(dilithium, WC_ML_DSA_87, + mem, memSz); + } + } + /* Dispose of any Dilithium key created. */ + wc_dilithium_free(dilithium); + WC_FREE_VAR_EX(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); + + if (!isDilithium) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create an EVP PKEY object. */ + return d2i_make_pkey(out, NULL, 0, priv, WC_EVP_PKEY_DILITHIUM); +} +#endif /* HAVE_DILITHIUM */ + +/** + * Try to make a WOLFSSL_EVP_PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static WOLFSSL_EVP_PKEY* d2i_evp_pkey_try(WOLFSSL_EVP_PKEY** out, + const unsigned char** in, long inSz, int priv) +{ + WOLFSSL_EVP_PKEY* pkey = NULL; + + WOLFSSL_ENTER("d2i_evp_pkey_try"); + + if (in == NULL || *in == NULL || inSz < 0) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + + if ((out != NULL) && (*out != NULL)) { + pkey = *out; + } + +#if !defined(NO_RSA) + if (d2iTryRsaKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* NO_RSA */ +#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) + if (d2iTryEccKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + 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(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION > 2)) + if (d2iTryAltDhKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ + +#ifdef HAVE_FALCON + if (d2iTryFalconKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* HAVE_FALCON */ +#ifdef HAVE_DILITHIUM + if (d2iTryDilithiumKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* HAVE_DILITHIUM */ + { + WOLFSSL_MSG("d2i_evp_pkey_try couldn't determine key type"); + } + + if ((pkey != NULL) && (out != NULL)) { + *out = pkey; + } + return pkey; +} +#endif /* OPENSSL_EXTRA || WPA_SMALL */ + +#ifdef OPENSSL_EXTRA +/* Converts a DER encoded public key to a WOLFSSL_EVP_PKEY structure. + * + * @param [in, out] out Pointer to new WOLFSSL_EVP_PKEY structure. + * Can be NULL. + * @param [in, out] in DER buffer to convert. + * @param [in] inSz Size of in buffer. + * @return Pointer to a new WOLFSSL_EVP_PKEY structure on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** out, + const unsigned char** in, long inSz) +{ + WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY"); + return d2i_evp_pkey_try(out, in, inSz, 0); +} + +#ifndef NO_BIO +/* Converts a DER encoded public key in a BIO to a WOLFSSL_EVP_PKEY structure. + * + * @param [in] bio BIO to read DER from. + * @param [out] out New WOLFSSL_EVP_PKEY pointer when not NULL. + * @return Pointer to a new WOLFSSL_EVP_PKEY structure on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY_bio(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** out) +{ + unsigned char* mem; + long memSz; + WOLFSSL_EVP_PKEY* pkey = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY_bio"); + + /* Validate parameters. */ + if (bio == NULL) { + return NULL; + } + + /* Get length of data in BIO. */ + memSz = wolfSSL_BIO_get_len(bio); + if (memSz <= 0) { + return NULL; + } + /* Allocate memory to read all of BIO data into. */ + mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + return NULL; + } + /* Read all data into allocated buffer. */ + if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) { + /* Create a WOLFSSL_EVP_PKEY from data. */ + pkey = wolfSSL_d2i_PUBKEY(NULL, (const unsigned char**)&mem, memSz); + if (out != NULL && pkey != NULL) { + /* Return new WOLFSSL_EVP_PKEY through parameter. */ + *out = pkey; + } + } + + /* Dispose of memory holding BIO data. */ + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return pkey; +} +#endif /* !NO_BIO */ +#endif /* OPENSSL_EXTRA */ + +#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. + * + * @param [in, out] out Pointer to new WOLFSSL_EVP_PKEY structure. + * Can be NULL. + * @param [in, out] in DER buffer to convert. + * @param [in] inSz Size of in buffer. + * @return Pointer to a new WOLFSSL_EVP_PKEY structure on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_EVP(WOLFSSL_EVP_PKEY** out, + unsigned char** in, long inSz) +{ + WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_EVP"); + return d2i_evp_pkey_try(out, (const unsigned char**)in, inSz, 1); +} +#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT || + * WOLFSSL_WPAS_SMALL*/ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) + +#ifndef NO_BIO +/* Converts a DER encoded private key in a BIO to a WOLFSSL_EVP_PKEY structure. + * + * @param [in] bio BIO to read DER from. + * @param [out] out New WOLFSSL_EVP_PKEY pointer when not NULL. + * @return Pointer to a new WOLFSSL_EVP_PKEY structure on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** out) +{ + unsigned char* mem = NULL; + int memSz = 0; + WOLFSSL_EVP_PKEY* key = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_bio"); + + /* Validate parameters. */ + if (bio == NULL) { + return NULL; + } + + /* Get length of data in BIO. */ + memSz = wolfSSL_BIO_get_len(bio); + if (memSz <= 0) { + WOLFSSL_MSG("wolfSSL_BIO_get_len() failure"); + return NULL; + } + /* Allocate memory to read all of BIO data into. */ + mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + WOLFSSL_MSG("Malloc failure"); + return NULL; + } + + /* Read all of data. */ + if (wolfSSL_BIO_read(bio, (unsigned char*)mem, memSz) == memSz) { + /* Determines key type and returns the new private EVP_PKEY object */ + 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; + } + + /* Write extra data back into bio object if necessary. */ + if (memSz > key->pkey_sz) { + wolfSSL_BIO_write(bio, mem + key->pkey_sz, memSz - key->pkey_sz); + if (wolfSSL_BIO_get_len(bio) <= 0) { + WOLFSSL_MSG("Failed to write memory to bio"); + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + } + + /* Return key through parameter if required. */ + if (out != NULL) { + *out = key; + } + } + + /* Dispose of memory holding BIO data. */ + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return key; +} +#endif /* !NO_BIO */ + +#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_NGINX || + * WOLFSSL_QT */ + +#ifdef OPENSSL_EXTRA +/* Reads in a DER format key. If PKCS8 headers are found they are stripped off. + * + * @param [in] type Type of key. + * @param [in, out] out Newly created WOLFSSL_EVP_PKEY structure. + * @param [in, out] in Pointer to input key DER. + * Pointer is advanced the same number of bytes read on + * success. + * @param [in] inSz Size of in buffer. + * @return A non null pointer on success. + * @return NULL on failure. + */ +static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, + const unsigned char **in, long inSz, int priv) +{ + int ret = 0; + word32 idx = 0, algId; + word16 pkcs8HeaderSz = 0; + WOLFSSL_EVP_PKEY* local; + const unsigned char* p; + int opt; + + (void)opt; + + /* Validate parameters. */ + if (in == NULL || inSz < 0) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + + if (priv == 1) { + /* Check if input buffer has PKCS8 header. In the case that it does not + * have a PKCS8 header then do not error out. */ + if ((ret = ToTraditionalInline_ex((const byte*)(*in), &idx, + (word32)inSz, &algId)) > 0) { + WOLFSSL_MSG("Found PKCS8 header"); + pkcs8HeaderSz = (word16)idx; + + /* Check header algorithm id matches algorithm type passed in. */ + if ((type == WC_EVP_PKEY_RSA && algId != RSAk + #ifdef WC_RSA_PSS + && algId != RSAPSSk + #endif + ) || + (type == WC_EVP_PKEY_EC && algId != ECDSAk) || + (type == WC_EVP_PKEY_DSA && algId != DSAk) || + (type == WC_EVP_PKEY_DH && algId != DHk)) { + WOLFSSL_MSG("PKCS8 does not match EVP key type"); + return NULL; + } + + (void)idx; /* not used */ + } + /* Ensure no error occurred try to remove any PKCS#8 header. */ + else if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) { + WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header"); + return NULL; + } + } + + /* Dispose of any WOLFSSL_EVP_PKEY passed in. */ + if (out != NULL && *out != NULL) { + wolfSSL_EVP_PKEY_free(*out); + *out = NULL; + } + /* Create a new WOLFSSL_EVP_PKEY and populate. */ + local = wolfSSL_EVP_PKEY_new(); + if (local == NULL) { + return NULL; + } + local->type = type; + local->pkey_sz = (int)inSz; + local->pkcs8HeaderSz = pkcs8HeaderSz; + local->pkey.ptr = (char*)XMALLOC((size_t)inSz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (local->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + XMEMCPY(local->pkey.ptr, *in, (size_t)inSz); + p = (const unsigned char*)local->pkey.ptr; + + /* Create an algorithm specific object into WOLFSSL_EVP_PKEY. */ + switch (type) { +#ifndef NO_RSA + case WC_EVP_PKEY_RSA: + /* Create a WOLFSSL_RSA object. */ + local->ownRsa = 1; + opt = priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC; + local->rsa = wolfssl_rsa_d2i(NULL, p, local->pkey_sz, opt); + if (local->rsa == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* NO_RSA */ +#ifdef HAVE_ECC + case WC_EVP_PKEY_EC: + /* Create a WOLFSSL_EC object. */ + local->ownEcc = 1; + local->ecc = wolfSSL_EC_KEY_new(); + if (local->ecc == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + opt = priv ? WOLFSSL_EC_KEY_LOAD_PRIVATE : + WOLFSSL_EC_KEY_LOAD_PUBLIC; + if (wolfSSL_EC_KEY_LoadDer_ex(local->ecc, p, local->pkey_sz, opt) != + WOLFSSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* HAVE_ECC */ +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) +#ifndef NO_DSA + case WC_EVP_PKEY_DSA: + /* Create a WOLFSSL_DSA object. */ + local->ownDsa = 1; + local->dsa = wolfSSL_DSA_new(); + if (local->dsa == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + opt = priv ? WOLFSSL_DSA_LOAD_PRIVATE : WOLFSSL_DSA_LOAD_PUBLIC; + if (wolfSSL_DSA_LoadDer_ex(local->dsa, p, local->pkey_sz, opt) != + WOLFSSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* NO_DSA */ +#ifndef NO_DH +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + case WC_EVP_PKEY_DH: + /* Create a WOLFSSL_DH object. */ + local->ownDh = 1; + local->dh = wolfSSL_DH_new(); + if (local->dh == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (wolfSSL_DH_LoadDer(local->dh, p, local->pkey_sz) != + WOLFSSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* HAVE_DH */ +#endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */ + default: + WOLFSSL_MSG("Unsupported key type"); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + + /* Advance pointer and return through parameter when required on success. */ + if (local != NULL) { + if (local->pkey_sz <= (int)inSz) { + *in += local->pkey_sz; + } + if (out != NULL) { + *out = local; + } + } + + /* Return newly allocated WOLFSSL_EVP_PKEY structure. */ + return local; +} + +/* Reads in a DER format key. + * + * @param [in] type Type of key. + * @param [in, out] out Newly created WOLFSSL_EVP_PKEY structure. + * @param [in, out] in Pointer to input key DER. + * Pointer is advanced the same number of bytes read on + * success. + * @param [in] inSz Size of in buffer. + * @return A non null pointer on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PublicKey(int type, WOLFSSL_EVP_PKEY** out, + const unsigned char **in, long inSz) +{ + WOLFSSL_ENTER("wolfSSL_d2i_PublicKey"); + + return d2i_evp_pkey(type, out, in, inSz, 0); +} + +/* Reads in a DER format key. If PKCS8 headers are found they are stripped off. + * + * @param [in] type Type of key. + * @param [in, out] out Newly created WOLFSSL_EVP_PKEY structure. + * @param [in, out] in Pointer to input key DER. + * Pointer is advanced the same number of bytes read on + * success. + * @param [in] inSz Size of in buffer. + * @return A non null pointer on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type, WOLFSSL_EVP_PKEY** out, + const unsigned char **in, long inSz) +{ + WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey"); + + return d2i_evp_pkey(type, out, in, inSz, 1); +} +#endif /* OPENSSL_EXTRA */ + +#ifdef OPENSSL_ALL +/* Detect RSA or EC key and decode private key DER. + * + * @param [in, out] pkey Newly created WOLFSSL_EVP_PKEY structure. + * @param [in, out] pp Pointer to private key DER data. + * @param [in] length Length in bytes of DER data. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey(WOLFSSL_EVP_PKEY** pkey, + const unsigned char** pp, long length) +{ + int ret; + WOLFSSL_EVP_PKEY* key = NULL; + const byte* der = *pp; + word32 idx = 0; + int len = 0; + int cnt = 0; + word32 algId; + word32 keyLen = (word32)length; + + /* Take off PKCS#8 wrapper if found. */ + if ((len = ToTraditionalInline_ex(der, &idx, keyLen, &algId)) >= 0) { + der += idx; + keyLen = (word32)len; + } + + idx = 0; + len = 0; + /* Use the number of elements in the outer sequence to determine key type. + */ + ret = GetSequence(der, &idx, &len, keyLen); + if (ret >= 0) { + word32 end = idx + (word32)len; + while (ret >= 0 && idx < end) { + /* Skip type */ + idx++; + /* Get length and skip over - keeping count */ + len = 0; + ret = GetLength(der, &idx, &len, keyLen); + if (ret >= 0) { + if (idx + (word32)len > end) { + ret = ASN_PARSE_E; + } + else { + idx += (word32)len; + cnt++; + } + } + } + } + + if (ret >= 0) { + int type; + /* ECC includes version, private[, curve][, public key] */ + if (cnt >= 2 && cnt <= 4) { + type = WC_EVP_PKEY_EC; + } + else { + type = WC_EVP_PKEY_RSA; + } + + /* Decode the detected type of private key. */ + key = wolfSSL_d2i_PrivateKey(type, pkey, &der, keyLen); + /* Update the pointer to after the DER data. */ + *pp = der; + } + + return key; +} + +#if !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) +/* Read all of the BIO data into a newly allocated buffer. + * + * @param [in] bio BIO to read from. + * @param [out] data Allocated buffer holding all BIO data. + * @return Number of bytes allocated and read. + * @return MEMORY_E on dynamic memory allocation failure. + * @return Other negative on error. + */ +static int bio_get_data(WOLFSSL_BIO* bio, byte** data) +{ + int ret = 0; + byte* mem = NULL; + + /* Get length of data in BIO. */ + ret = wolfSSL_BIO_get_len(bio); + if (ret > 0) { + /* Allocate memory big enough to hold data in BIO. */ + mem = (byte*)XMALLOC((size_t)ret, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (mem == NULL) { + WOLFSSL_MSG("Memory error"); + ret = MEMORY_E; + } + if (ret >= 0) { + /* Read data from BIO. */ + if ((ret = wolfSSL_BIO_read(bio, mem, ret)) <= 0) { + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + ret = MEMORY_E; + mem = NULL; + } + } + } + + /* Return allocated buffer with data from BIO. */ + *data = mem; + return ret; +} + +/* Convert the algorithm id to a key type. + * + * @param [in] algId Algorithm Id. + * @return Key type on success. + * @return WC_EVP_PKEY_NONE when algorithm id not supported. + */ +static int wolfssl_i_alg_id_to_key_type(word32 algId) +{ + int type; + + /* Convert algorithm id into EVP PKEY id. */ + switch (algId) { +#ifndef NO_RSA + case RSAk: + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + type = WC_EVP_PKEY_RSA; + break; +#endif + #ifdef HAVE_ECC + case ECDSAk: + type = WC_EVP_PKEY_EC; + break; + #endif + #ifndef NO_DSA + case DSAk: + type = WC_EVP_PKEY_DSA; + break; + #endif + #ifndef NO_DH + case DHk: + type = WC_EVP_PKEY_DH; + break; + #endif + default: + WOLFSSL_MSG("PKEY algorithm, from PKCS#8 header, not supported"); + type = WC_EVP_PKEY_NONE; + break; + } + + return type; +} + +/* Creates an WOLFSSL_EVP_PKEY from PKCS#8 encrypted private DER in a BIO. + * + * Uses the PEM default password callback when cb is NULL. + * + * @param [in] bio BIO to read DER from. + * @param [in, out] pkey Newly created WOLFSSL_EVP_PKEY structure. + * @param [in] cb Password callback. May be NULL. + * @param [in] ctx Password callback context. May be NULL. + * @return A non null pointer on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PKCS8PrivateKey_bio(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** pkey, wc_pem_password_cb* cb, void* ctx) +{ + int ret; + const byte* p; + byte* der = NULL; + int len; + word32 algId; + WOLFSSL_EVP_PKEY* key; + int type; + char password[NAME_SZ]; + int passwordSz; + + /* Get the data from the BIO into a newly allocated buffer. */ + if ((len = bio_get_data(bio, &der)) < 0) + return NULL; + + /* Use the PEM default callback if none supplied. */ + if (cb == NULL) { + cb = wolfSSL_PEM_def_callback; + } + /* Get the password. */ + passwordSz = cb(password, sizeof(password), PEM_PASS_READ, ctx); + if (passwordSz < 0) { + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wolfSSL_d2i_PKCS8PrivateKey_bio password", password, + passwordSz); +#endif + + /* Decrypt the PKCS#8 encrypted private key and get algorithm. */ + ret = ToTraditionalEnc(der, (word32)len, password, passwordSz, &algId); + ForceZero(password, (word32)passwordSz); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(password, passwordSz); +#endif + if (ret < 0) { + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + /* Get the key type from the algorithm id of the PKCS#8 header. */ + if ((type = wolfssl_i_alg_id_to_key_type(algId)) == WC_EVP_PKEY_NONE) { + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + /* Decode private key with the known type. */ + p = der; + key = d2i_evp_pkey(type, pkey, &p, len, 1); + + /* Dispose of memory holding BIO data. */ + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return key; +} +#endif /* !NO_BIO && !NO_PWDBASED && HAVE_PKCS8 */ +#endif /* OPENSSL_ALL */ + +#ifdef OPENSSL_EXTRA +/* Reads in a PKCS#8 DER format key. + * + * @param [in, out] pkey Newly created WOLFSSL_PKCS8_PRIV_KEY_INFO structure. + * @param [in, out] keyBuf Pointer to input key DER. + * Pointer is advanced the same number of bytes read on + * success. + * @param [in] keyLen Number of bytes in keyBuf. + * @return A non null pointer on success. + * @return NULL on failure. + */ +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* pkcs8 = NULL; +#ifdef WOLFSSL_PEM_TO_DER + int ret; + DerBuffer* pkcs8Der = NULL; + DerBuffer rawDer; + EncryptedInfo info; + int advanceLen = 0; + + /* Clear the encryption information and DER buffer. */ + XMEMSET(&info, 0, sizeof(info)); + XMEMSET(&rawDer, 0, sizeof(rawDer)); + + /* Validate parameters. */ + if ((keyBuf == NULL) || (*keyBuf == NULL) || (keyLen <= 0)) { + WOLFSSL_MSG("Bad key PEM/DER args"); + return NULL; + } + + /* Try to decode the PEM into DER. */ + ret = PemToDer(*keyBuf, keyLen, PRIVATEKEY_TYPE, &pkcs8Der, NULL, &info, + NULL); + if (ret >= 0) { + /* Cache the amount of data in PEM formatted private key. */ + advanceLen = (int)info.consumed; + } + else { + /* Not PEM - create a DerBuffer with the PKCS#8 DER data. */ + WOLFSSL_MSG("Not PEM format"); + ret = AllocDer(&pkcs8Der, (word32)keyLen, PRIVATEKEY_TYPE, NULL); + if (ret == 0) { + XMEMCPY(pkcs8Der->buffer, *keyBuf, keyLen); + } + } + + if (ret == 0) { + /* Verify this is PKCS8 Key */ + word32 inOutIdx = 0; + word32 algId; + + ret = ToTraditionalInline_ex(pkcs8Der->buffer, &inOutIdx, + pkcs8Der->length, &algId); + if (ret >= 0) { + if (advanceLen == 0) { + /* Set only if not PEM */ + advanceLen = (int)inOutIdx + ret; + } + if (algId == DHk) { + /* Special case for DH as we expect the DER buffer to be always + * be in PKCS8 format */ + rawDer.buffer = pkcs8Der->buffer; + rawDer.length = inOutIdx + (word32)ret; + } + else { + rawDer.buffer = pkcs8Der->buffer + inOutIdx; + rawDer.length = (word32)ret; + } + ret = 0; /* good DER */ + } + } + + if (ret == 0) { + /* Create a WOLFSSL_EVP_PKEY for a WOLFSSL_PKCS8_PRIV_KEY_INFO. */ + pkcs8 = wolfSSL_EVP_PKEY_new(); + if (pkcs8 == NULL) { + ret = MEMORY_E; + } + } + if (ret == 0) { + /* Allocate memory to hold DER. */ + pkcs8->pkey.ptr = (char*)XMALLOC(rawDer.length, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkcs8->pkey.ptr == NULL) { + ret = MEMORY_E; + } + } + if (ret == 0) { + /* Copy in DER data and size. */ + XMEMCPY(pkcs8->pkey.ptr, rawDer.buffer, rawDer.length); + pkcs8->pkey_sz = (int)rawDer.length; + } + + /* Dispose of PKCS#8 DER data - raw DER reference data in pkcs8Der. */ + FreeDer(&pkcs8Der); + if (ret != 0) { + /* Dispose of WOLFSSL_PKCS8_PRIV_KEY_INFO object on error. */ + wolfSSL_EVP_PKEY_free(pkcs8); + pkcs8 = NULL; + } + else { + /* Advance the buffer past the key on success. */ + *keyBuf += advanceLen; + } + if (pkey != NULL) { + /* Return the WOLFSSL_PKCS8_PRIV_KEY_INFO object through parameter. */ + *pkey = pkcs8; + } +#else + (void)pkey; + (void)keyBuf; + (void)keyLen; +#endif /* WOLFSSL_PEM_TO_DER */ + + /* Return new WOLFSSL_PKCS8_PRIV_KEY_INFO object. */ + return pkcs8; +} + +#ifndef NO_BIO +/* Converts a DER format key read from BIO to a PKCS#8 structure. + * + * @param [in] bio Input BIO to read DER from. + * @param [out] pkey If not NULL then this pointer will be overwritten with a + * new PKCS8 structure. + * @return A WOLFSSL_PKCS8_PRIV_KEY_INFO pointer on success + * @return NULL on failure. + */ +WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY_bio(WOLFSSL_BIO* bio, + WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey) +{ + WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL; +#ifdef WOLFSSL_PEM_TO_DER + unsigned char* mem = NULL; + int memSz; + + WOLFSSL_ENTER("wolfSSL_d2i_PKCS8_PKEY_bio"); + + /* Validate parameters. */ + if (bio == NULL) { + return NULL; + } + + /* Get the memory buffer from the BIO. */ + if ((memSz = wolfSSL_BIO_get_mem_data(bio, &mem)) < 0) { + return NULL; + } + + /* Decode the PKCS#8 key into a WOLFSSL_PKCS8_PRIV_KEY_INFO object. */ + pkcs8 = wolfSSL_d2i_PKCS8_PKEY(pkey, (const unsigned char**)&mem, memSz); +#else + (void)bio; + (void)pkey; +#endif /* WOLFSSL_PEM_TO_DER */ + + /* Return new WOLFSSL_PKCS8_PRIV_KEY_INFO object. */ + return pkcs8; +} +#endif /* !NO_BIO */ + +#ifdef WOLF_PRIVATE_KEY_ID +/* Create an EVP structure for use with crypto callbacks. + * + * @param [in] type Type of private key. + * @param [out] out WOLFSSL_EVP_PKEY object created. + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] devId Device id. + * @return A new WOLFSSL_EVP_PKEY object on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_id(int type, WOLFSSL_EVP_PKEY** out, + void* heap, int devId) +{ + WOLFSSL_EVP_PKEY* local; + + /* Dispose of any object passed in through out. */ + if (out != NULL && *out != NULL) { + wolfSSL_EVP_PKEY_free(*out); + *out = NULL; + } + + /* Create a local WOLFSSL_EVP_PKEY to be decoded into. */ + local = wolfSSL_EVP_PKEY_new_ex(heap); + if (local == NULL) { + return NULL; + } + local->type = type; + local->pkey_sz = 0; + local->pkcs8HeaderSz = 0; + + switch (type) { +#ifndef NO_RSA + case WC_EVP_PKEY_RSA: + { + /* Create a WOLFSSL_RSA object into WOLFSSL_EVP_PKEY. */ + local->rsa = wolfSSL_RSA_new_ex(heap, devId); + if (local->rsa == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + local->ownRsa = 1; + /* Algorithm specific object set into WOLFSL_EVP_PKEY. */ + local->rsa->inSet = 1; + #ifdef WOLF_CRYPTO_CB + ((RsaKey*)local->rsa->internal)->devId = devId; + #endif + break; + } +#endif /* !NO_RSA */ +#ifdef HAVE_ECC + case WC_EVP_PKEY_EC: + { + ecc_key* key; + + /* Create a WOLFSSL_EC object into WOLFSSL_EVP_PKEY. */ + local->ecc = wolfSSL_EC_KEY_new_ex(heap, devId); + if (local->ecc == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + local->ownEcc = 1; + /* Algorithm specific object set into WOLFSL_EVP_PKEY. */ + local->ecc->inSet = 1; + + /* Get wolfSSL EC key and set fields. */ + key = (ecc_key*)local->ecc->internal; + #ifdef WOLF_CRYPTO_CB + key->devId = devId; + #endif + key->type = ECC_PRIVATEKEY; + /* key is required to have a key size / curve set, although + * actual one used is determined by devId callback function. */ + wc_ecc_set_curve(key, ECDHE_SIZE, ECC_CURVE_DEF); + break; + } +#endif /* HAVE_ECC */ + default: + WOLFSSL_MSG("Unsupported private key id type"); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + + /* Return new WOLFSSL_EVP_PKEY through parameter if required. */ + if (local != NULL && out != NULL) { + *out = local; + } + /* Return new WOLFSSL_EVP_PKEY. */ + return local; +} +#endif /* WOLF_PRIVATE_KEY_ID */ +#endif /* OPENSSL_EXTRA */ + +/******************************************************************************* + * END OF d2i APIs + ******************************************************************************/ + +/******************************************************************************* + * START OF i2d APIs + ******************************************************************************/ + +#ifdef OPENSSL_ALL +/* Encode PKCS#8 key as DER data. + * + * @param [in] key PKCS#8 private key to encode. + * @param [out] pp Pointer to buffer of encoded data. + * @return Length of DER encoded data on success. + * @return Less than zero on failure. + */ +int wolfSSL_i2d_PKCS8_PKEY(WOLFSSL_PKCS8_PRIV_KEY_INFO* key, unsigned char** pp) +{ + word32 keySz = 0; + unsigned char* out; + int len; + + WOLFSSL_ENTER("wolfSSL_i2d_PKCS8_PKEY"); + + /* Validate parameters. */ + if (key == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + /* Get the length of DER encoding. */ + if (pkcs8_encode(key, NULL, &keySz) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { + return WOLFSSL_FATAL_ERROR; + } + len = (int)keySz; + + /* Return the length when output parameter is NULL. */ + if ((pp == NULL) || (len == 0)) { + return len; + } + + /* Allocate memory for DER encoding if NULL passed in for output buffer. */ + if (*pp == NULL) { + out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1); + if (out == NULL) { + return WOLFSSL_FATAL_ERROR; + } + } + else { + /* Use buffer passed in - assume it is big enough. */ + out = *pp; + } + + /* Encode the PKCS#8 key into the output buffer. */ + if (pkcs8_encode(key, out, &keySz) != len) { + if (*pp == NULL) { + XFREE(out, NULL, DYNAMIC_TYPE_ASN1); + } + return WOLFSSL_FATAL_ERROR; + } + + /* Return new output buffer or move pointer passed encoded data. */ + if (*pp == NULL) { + *pp = out; + } + else { + *pp += len; + } + + return len; +} +#endif + +#ifdef OPENSSL_EXTRA + +#if !defined(NO_ASN) && !defined(NO_PWDBASED) +/* Get raw pointer to DER buffer from WOLFSSL_EVP_PKEY. + * + * Assumes der is large enough if passed in. + * + * @param [in] key WOLFSSL_EVP_PKEY to get DER buffer for. + * @param [out] der Buffer holding DER encoding. May be NULL. + * @return Size of DER encoding on success. + * @return Less than 0 on failure. + */ +static int wolfssl_i_evp_pkey_get_der(const WOLFSSL_EVP_PKEY* key, + unsigned char** der) +{ + int sz; + word16 pkcs8HeaderSz; + + /* Validate parameters. */ + if ((key == NULL) || (key->pkey_sz == 0)) { + return WOLFSSL_FATAL_ERROR; + } + + /* If pkcs8HeaderSz is invalid, return all of the DER encoding. */ + pkcs8HeaderSz = 0; + if (key->pkey_sz > key->pkcs8HeaderSz) { + pkcs8HeaderSz = key->pkcs8HeaderSz; + } + /* Calculate the size of the DER encoding to return. */ + sz = key->pkey_sz - pkcs8HeaderSz; + /* Returning encoding when DER is not NULL. */ + if (der != NULL) { + unsigned char* pt = (unsigned char*)key->pkey.ptr; + int bufferPassedIn = ((*der) != NULL); + + if (!bufferPassedIn) { + /* Allocate buffer to hold DER encoding. */ + *der = (unsigned char*)XMALLOC((size_t)sz, NULL, + DYNAMIC_TYPE_OPENSSL); + if (*der == NULL) { + return WOLFSSL_FATAL_ERROR; + } + } + /* Copy in non-PKCS#8 DER encoding. */ + XMEMCPY(*der, pt + pkcs8HeaderSz, (size_t)sz); + /* Step past encoded key when buffer provided. */ + if (bufferPassedIn) { + *der += sz; + } + } + + /* Return size of DER encoded data. */ + return sz; +} + +/* Encode key as unencrypted DER data. + * + * @param [in] key PKCS#8 private key to encode. + * @param [out] der Pointer to buffer of encoded data. + * @return Length of DER encoded data on success. + * @return Less than zero on failure. + */ +int wolfSSL_i2d_PrivateKey(const WOLFSSL_EVP_PKEY* key, unsigned char** der) +{ + return wolfssl_i_evp_pkey_get_der(key, der); +} + +#ifndef NO_BIO +/* Encode key as unencrypted DER data and write to BIO. + * + * @param [in] bio BIO to write data to. + * @param [in] key PKCS#8 private key to encode. + * @return Length of DER encoded data on success. + * @return Less than zero on failure. + */ +int wolfSSL_i2d_PrivateKey_bio(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + int derSz = 0; + byte* der = NULL; + + if (bio == NULL || key == NULL) { + return WOLFSSL_FAILURE; + } + + derSz = wolfSSL_i2d_PrivateKey(key, &der); + if (derSz <= 0) { + WOLFSSL_MSG("wolfSSL_i2d_PrivateKey (for getting size) failed"); + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_write(bio, der, derSz) != derSz) { + goto cleanup; + } + + ret = WOLFSSL_SUCCESS; + +cleanup: + XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL); + return ret; +} +#endif + +#ifdef HAVE_ECC +/* Encode EC key as public key DER. + * + * @param [in] key WOLFSSL_EVP_KEY object to encode. + * @param [in] ec WOLFSSL_EC_KEY object to encode. + * @param [out] der Buffer with DER encoding of EC public key. + * @return Public key DER encoding size on success. + * @return WOLFSSL_FATAL_ERROR when dynamic memory allocation fails. + * @return WOLFSSL_FATAL_ERROR when encoding fails. + */ +static int wolfssl_i_i2d_ecpublickey(const WOLFSSL_EVP_PKEY* key, + const WOLFSSL_EC_KEY *ec, unsigned char **der) +{ + word32 pub_derSz = 0; + int ret; + unsigned char *local_der = NULL; + word32 local_derSz = 0; + unsigned char *pub_der = NULL; + ecc_key *eccKey = NULL; + word32 inOutIdx = 0; + + /* We need to get the DER, then convert it to a public key. But what we get + * might be a buffered private key so we need to decode it and then encode + * the public part. */ + ret = wolfssl_i_evp_pkey_get_der(key, &local_der); + if (ret <= 0) { + /* In this case, there was no buffered DER at all. This could be the + * case where the key that was passed in was generated. So now we + * have to create the local DER. */ + local_derSz = (word32)wolfSSL_i2d_ECPrivateKey(ec, &local_der); + if (local_derSz == 0) { + ret = WOLFSSL_FATAL_ERROR; + } + } else { + local_derSz = (word32)ret; + ret = 0; + } + + if (ret == 0) { + eccKey = (ecc_key *)XMALLOC(sizeof(*eccKey), NULL, DYNAMIC_TYPE_ECC); + if (eccKey == NULL) { + WOLFSSL_MSG("Failed to allocate key buffer."); + ret = WOLFSSL_FATAL_ERROR; + } + } + + /* Initialize a wolfCrypt ECC key. */ + if (ret == 0) { + ret = wc_ecc_init(eccKey); + } + if (ret == 0) { + /* Decode the DER data with wolfCrypt ECC key. */ + ret = wc_EccPublicKeyDecode(local_der, &inOutIdx, eccKey, local_derSz); + if (ret < 0) { + /* We now try again as x.963 [point type][x][opt y]. */ + ret = wc_ecc_import_x963(local_der, local_derSz, eccKey); + } + } + + if (ret == 0) { + /* Get the size of the encoding of the public key DER. */ + pub_derSz = (word32)wc_EccPublicKeyDerSize(eccKey, 1); + if ((int)pub_derSz <= 0) { + ret = WOLFSSL_FAILURE; + } + } + + if (ret == 0) { + /* Allocate memory for public key DER encoding. */ + pub_der = (unsigned char*)XMALLOC(pub_derSz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (pub_der == NULL) { + WOLFSSL_MSG("Failed to allocate output buffer."); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Encode public key as DER. */ + pub_derSz = (word32)wc_EccPublicKeyToDer(eccKey, pub_der, pub_derSz, 1); + if ((int)pub_derSz <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } + } + + /* This block is for actually returning the DER of the public key */ + if ((ret == 0) && (der != NULL)) { + int bufferPassedIn = ((*der) != NULL); + if (!bufferPassedIn) { + *der = (unsigned char*)XMALLOC(pub_derSz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (*der == NULL) { + WOLFSSL_MSG("Failed to allocate output buffer."); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 0) { + XMEMCPY(*der, pub_der, pub_derSz); + if (bufferPassedIn) { + *der += pub_derSz; + } + } + } + + /* Dispose of allocated objects. */ + XFREE(pub_der, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(local_der, NULL, DYNAMIC_TYPE_OPENSSL); + wc_ecc_free(eccKey); + XFREE(eccKey, NULL, DYNAMIC_TYPE_ECC); + + /* Return error or the size of the DER encoded public key. */ + if (ret == 0) { + ret = (int)pub_derSz; + } + return ret; +} +#endif + +/* Encode the WOLFSSL_EVP_PKEY object as public key DER. + * + * @param [in] key WOLFSLS_EVP_PKEY object to encode. + * @param [out] der Buffer with DER encoding of public key. + * @return Public key DER encoding size on success. + * @return WOLFSSL_FATAL_ERROR when key is NULL. + * @return WOLFSSL_FATAL_ERROR when key type not supported. + * @return WOLFSSL_FATAL_ERROR when dynamic memory allocation fails. + */ +int wolfSSL_i2d_PublicKey(const WOLFSSL_EVP_PKEY *key, unsigned char **der) +{ + int ret; + + /* Validate parameters. */ + if (key == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + /* Encode based on key type. */ + switch (key->type) { + #ifndef NO_RSA + case WC_EVP_PKEY_RSA: + return wolfSSL_i2d_RSAPublicKey(key->rsa, der); + #endif + #ifdef HAVE_ECC + case WC_EVP_PKEY_EC: + return wolfssl_i_i2d_ecpublickey(key, key->ecc, der); + #endif + default: + ret = WOLFSSL_FATAL_ERROR; + break; + } + + return ret; +} + +/* Encode the WOLFSSL_EVP_PKEY object as public key DER. + * + * @param [in] key WOLFSLS_EVP_PKEY object to encode. + * @param [out] der Buffer with DER encoding of public key. + * @return Public key DER encoding size on success. + * @return WOLFSSL_FATAL_ERROR when key is NULL. + * @return WOLFSSL_FATAL_ERROR when key type not supported. + * @return WOLFSSL_FATAL_ERROR when dynamic memory allocation fails. + */ +int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der) +{ + return wolfSSL_i2d_PublicKey(key, der); +} +#endif /* !NO_ASN && !NO_PWDBASED */ + +#endif /* OPENSSL_EXTRA */ + +#endif /* !NO_CERTS */ + +/******************************************************************************* + * END OF i2d APIs + ******************************************************************************/ + +#endif /* !WOLFSSL_EVP_PK_INCLUDED */ + diff --git a/wolfcrypt/src/include.am b/wolfcrypt/src/include.am index a14ae1884c..bb8eea3f42 100644 --- a/wolfcrypt/src/include.am +++ b/wolfcrypt/src/include.am @@ -12,6 +12,7 @@ MAINTAINERCLEANFILES+= $(ASYNC_FILES) EXTRA_DIST += wolfcrypt/src/misc.c EXTRA_DIST += wolfcrypt/src/evp.c +EXTRA_DIST += wolfcrypt/src/evp_pk.c EXTRA_DIST += wolfcrypt/src/asm.c EXTRA_DIST += wolfcrypt/src/aes_asm.asm EXTRA_DIST += wolfcrypt/src/aes_gcm_asm.asm diff --git a/wolfcrypt/src/kdf.c b/wolfcrypt/src/kdf.c index beb9e79124..0f6bdd736e 100644 --- a/wolfcrypt/src/kdf.c +++ b/wolfcrypt/src/kdf.c @@ -896,8 +896,7 @@ static void wc_srtp_kdf_first_block(const byte* salt, word32 saltSz, int kdrIdx, block[i] = 0; } XMEMCPY(block + WC_SRTP_MAX_SALT - saltSz, salt, saltSz); - block[WC_SRTP_MAX_SALT] = 0; - /* block[15] is counter. */ + /* block[14-15] are counter. */ /* When kdrIdx is -1, don't XOR in index. */ if (kdrIdx >= 0) { @@ -947,6 +946,7 @@ static int wc_srtp_kdf_derive_key(byte* block, int idxSz, byte label, block[WC_SRTP_MAX_SALT - idxSz - 1] ^= label; for (i = 0; (ret == 0) && (i < blocks); i++) { /* Set counter. */ + block[14] = (byte)(i >> 8); block[15] = (byte)i; /* Encrypt block into key buffer. */ ret = wc_AesEcbEncrypt(aes, key, block, WC_AES_BLOCK_SIZE); @@ -959,6 +959,7 @@ static int wc_srtp_kdf_derive_key(byte* block, int idxSz, byte label, if ((ret == 0) && (keySz > 0)) { byte enc[WC_AES_BLOCK_SIZE]; /* Set counter. */ + block[14] = (byte)(i >> 8); block[15] = (byte)i; /* Encrypt block into temporary. */ ret = wc_AesEcbEncrypt(aes, enc, block, WC_AES_BLOCK_SIZE); diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 677441e426..97d15a3937 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -1794,6 +1794,16 @@ static int wc_PKCS7_ImportRSA(wc_PKCS7* pkcs7, RsaKey* privKey) } #endif } + #ifdef HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK + else if (pkcs7->rsaSignRawDigestCb != NULL && pkcs7->publicKeySz > 0) { + /* When using raw sign callback (e.g., HSM/secure element), private + * key may not be available. Use public key from signer certificate + * for signature size calculation. */ + idx = 0; + ret = wc_RsaPublicKeyDecode(pkcs7->publicKey, &idx, privKey, + pkcs7->publicKeySz); + } + #endif else if (pkcs7->devId == INVALID_DEVID) { ret = BAD_FUNC_ARG; } @@ -1874,6 +1884,16 @@ static int wc_PKCS7_ImportECC(wc_PKCS7* pkcs7, ecc_key* privKey) } #endif } + #ifdef HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK + else if (pkcs7->eccSignRawDigestCb != NULL && pkcs7->publicKeySz > 0) { + /* When using raw sign callback (e.g., HSM/secure element), private + * key may not be available. Use public key from signer certificate + * for signature size calculation. */ + idx = 0; + ret = wc_EccPublicKeyDecode(pkcs7->publicKey, &idx, privKey, + pkcs7->publicKeySz); + } + #endif else if (pkcs7->devId == INVALID_DEVID) { ret = BAD_FUNC_ARG; } @@ -2398,6 +2418,28 @@ static int wc_PKCS7_SignedDataBuildSignature(wc_PKCS7* pkcs7, #ifdef HAVE_ECC case ECDSAk: + #ifdef HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK + if (pkcs7->eccSignRawDigestCb != NULL) { + /* get hash OID */ + int eccHashOID = wc_HashGetOID(esd->hashType); + if (eccHashOID < 0) { + ret = eccHashOID; + break; + } + + /* user signing plain digest */ + ret = pkcs7->eccSignRawDigestCb(pkcs7, + esd->contentAttribsDigest, hashSz, + esd->encContentDigest, sizeof(esd->encContentDigest), + pkcs7->privateKey, pkcs7->privateKeySz, pkcs7->devId, + eccHashOID); + /* validate return value doesn't exceed buffer size */ + if (ret > 0 && (word32)ret > sizeof(esd->encContentDigest)) { + ret = BUFFER_E; + } + break; + } + #endif /* CMS with ECDSA does not sign DigestInfo structure * like PKCS#7 with RSA does */ ret = wc_PKCS7_EcdsaSign(pkcs7, esd->contentAttribsDigest, @@ -3986,6 +4028,30 @@ int wc_PKCS7_SetRsaSignRawDigestCb(wc_PKCS7* pkcs7, CallbackRsaSignRawDigest cb) } #endif +#endif /* NO_RSA */ + + +#ifdef HAVE_ECC + +#ifdef HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK +/* register raw ECC sign digest callback */ +int wc_PKCS7_SetEccSignRawDigestCb(wc_PKCS7* pkcs7, CallbackEccSignRawDigest cb) +{ + if (pkcs7 == NULL || cb == NULL) { + return BAD_FUNC_ARG; + } + + pkcs7->eccSignRawDigestCb = cb; + + return 0; +} +#endif + +#endif /* HAVE_ECC */ + + +#ifndef NO_RSA + /* returns size of signature put into out, negative on error */ static int wc_PKCS7_RsaVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz, byte* hash, word32 hashSz) diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 4e4f4e2388..37c410b543 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1147,7 +1147,7 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, rng->drbg_scratch = NULL; #endif } - /* else swc_RNG_HealthTestLocal was successful */ + /* else wc_RNG_HealthTestLocal was successful */ if (ret == DRBG_SUCCESS) { #ifdef WOLFSSL_CHECK_MEM_ZERO diff --git a/wolfcrypt/src/wc_pkcs11.c b/wolfcrypt/src/wc_pkcs11.c index 3ac4911f25..8ad4049804 100644 --- a/wolfcrypt/src/wc_pkcs11.c +++ b/wolfcrypt/src/wc_pkcs11.c @@ -68,10 +68,6 @@ #endif -/* Maximum length of the EC parameter string. */ -#define MAX_EC_PARAM_LEN 16 - - #if defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH) /* Pointer to false required for templates. */ static CK_BBOOL ckFalse = CK_FALSE; @@ -110,7 +106,9 @@ typedef struct CK_AES_CTR_PARAMS { } CK_AES_CTR_PARAMS; #endif +#if !defined(NO_CERTS) static CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; +#endif #ifdef WOLFSSL_DEBUG_PKCS11 /* Enable logging of PKCS#11 calls and return value. */ @@ -120,6 +118,9 @@ static CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; /* Enable logging of PKCS#11 template. */ #define PKCS11_DUMP_TEMPLATE(name, templ, cnt) \ pkcs11_dump_template(name, templ, cnt) +/* Enable logging of PKCS#11 mechanism info. */ +#define PKCS11_DUMP_MECHANSIM(name, mechanism) \ + pkcs11_dump_mechanism(name, mechanism) /* Formats of template items - used to instruct how to log information. */ enum PKCS11_TYPE_FORMATS { @@ -141,7 +142,7 @@ static struct PKCS11_TYPE_STR { int format; } typeStr[] = { { CKA_CLASS, "CKA_CLASS", PKCS11_FMT_CLASS }, - { CKA_TOKEN, "CKA_TOKEN", PKCS11_FMT_POINTER }, + { CKA_TOKEN, "CKA_TOKEN", PKCS11_FMT_BOOLEAN }, { CKA_PRIVATE, "CKA_PRIVATE", PKCS11_FMT_BOOLEAN }, { CKA_LABEL, "CKA_LABEL", PKCS11_FMT_STRING }, { CKA_VALUE, "CKA_VALUE", PKCS11_FMT_DATA }, @@ -327,6 +328,11 @@ static void pkcs11_dump_template(const char* name, CK_ATTRIBUTE* templ, WOLFSSL_MSG(line); break; case PKCS11_FMT_DATA: + if (templ[i].ulValueLen == CK_UNAVAILABLE_INFORMATION) { + XSNPRINTF(line, sizeof(line), "%25s: unavailable", type); + WOLFSSL_MSG(line); + break; + } XSNPRINTF(line, sizeof(line), "%25s: %ld", type, templ[i].ulValueLen); WOLFSSL_MSG(line); @@ -340,7 +346,7 @@ static void pkcs11_dump_template(const char* name, CK_ATTRIBUTE* templ, char hex[6]; XSNPRINTF(hex, sizeof(hex), "0x%02x,", ((byte*)templ[i].pValue)[j]); - XSTRNCAT(line, hex, 5); + XSTRNCAT(line, hex, sizeof(line) - XSTRLEN(line) - 1); if ((j % 8) == 7) { WOLFSSL_MSG(line); XSNPRINTF(line, sizeof(line), "%27s", ""); @@ -365,6 +371,64 @@ static void pkcs11_dump_template(const char* name, CK_ATTRIBUTE* templ, } } +/* Information for logging a mechanism */ +static struct PKCS11_MECHANISM_STR { + /** Mechanism. */ + CK_MECHANISM_TYPE mech; + /** String to log corresponding mechanism. */ + const char* str; +} mechStr[] = { + { CKM_RSA_PKCS_KEY_PAIR_GEN, "CKM_RSA_PKCS_KEY_PAIR_GEN" }, + { CKM_RSA_X_509, "CKM_RSA_X_509" }, + { CKM_DH_PKCS_KEY_PAIR_GEN, "CKM_DH_PKCS_KEY_PAIR_GEN" }, + { CKM_DH_PKCS_DERIVE, "CKM_DH_PKCS_DERIVE" }, + { CKM_MD5_HMAC, "CKM_MD5_HMAC" }, + { CKM_SHA_1_HMAC, "CKM_SHA_1_HMAC" }, + { CKM_SHA256_HMAC, "CKM_SHA256_HMAC" }, + { CKM_SHA224_HMAC, "CKM_SHA224_HMAC" }, + { CKM_SHA384_HMAC, "CKM_SHA384_HMAC" }, + { CKM_SHA512_HMAC, "CKM_SHA512_HMAC" }, + { CKM_GENERIC_SECRET_KEY_GEN, "CKM_GENERIC_SECRET_KEY_GEN" }, + { CKM_EC_KEY_PAIR_GEN, "CKM_EC_KEY_PAIR_GEN" }, + { CKM_ECDSA, "CKM_ECDSA" }, + { CKM_ECDH1_DERIVE, "CKM_ECDH1_DERIVE" }, + { CKM_ECDH1_COFACTOR_DERIVE, "CKM_ECDH1_COFACTOR_DERIVE" }, + { CKM_AES_KEY_GEN, "CKM_AES_KEY_GEN" }, + { CKM_AES_CBC, "CKM_AES_CBC" }, + { CKM_AES_GCM, "CKM_AES_GCM" }, +}; +/* Count of known mechanism for logging. */ +#define PKCS11_MECH_STR_CNT ((int)(sizeof(mechStr) / sizeof(*mechStr))) + +/* + * Dump/log the PKCS #11 mechanism. + * + * This is only for debugging purposes. Only the values needed are recognised. + * + * @param [in] op PKCS #11 operation that was attempted. + * @param [in] mech PKCS #11 mechanism to dump. + */ +static void pkcs11_dump_mechanism(const char* op, CK_MECHANISM_TYPE mech) +{ + char line[80]; + const char *mechName = NULL; + int i; + + for (i = 0; i < PKCS11_MECH_STR_CNT; i++) { + if (mech == mechStr[i].mech) { + mechName = mechStr[i].str; + break; + } + } + if (i == PKCS11_TYPE_STR_CNT) { + mechName = "UNKNOWN"; + } + + XSNPRINTF(line, 80, "%s: %s", op, mechName); + + WOLFSSL_MSG(line); +} + /* * Log a PKCS #11 return value with the name of function called. * @@ -416,6 +480,8 @@ static void pkcs11_val(const char* op, CK_ULONG val) #define PKCS11_VAL(op, val) WC_DO_NOTHING /* Disable logging of PKCS#11 template. */ #define PKCS11_DUMP_TEMPLATE(name, templ, cnt) WC_DO_NOTHING +/* Disable logging of PKCS#11 mechanism info. */ +#define PKCS11_DUMP_MECHANSIM(name, mechanism) WC_DO_NOTHING #endif /** @@ -432,7 +498,7 @@ static void pkcs11_val(const char* op, CK_ULONG val) */ int wc_Pkcs11_Initialize(Pkcs11Dev* dev, const char* library, void* heap) { - return wc_Pkcs11_Initialize_ex(dev, library, heap, NULL); + return wc_Pkcs11_Initialize_v3(dev, library, heap, NULL, NULL, NULL); } /** @@ -451,52 +517,270 @@ int wc_Pkcs11_Initialize(Pkcs11Dev* dev, const char* library, void* heap) */ int wc_Pkcs11_Initialize_ex(Pkcs11Dev* dev, const char* library, void* heap, CK_RV* rvp) +{ + return wc_Pkcs11_Initialize_v3(dev, library, heap, NULL, NULL, rvp); +} + +/** + * Load library, get function list and initialize PKCS#11. + * + * @param [in] dev Device object. + * @param [in] library Library name including path. + * @param [in] heap Heap hint. + * @param [in,out] version On in, desired version of interface. + * On out, actual obtained version of interface. + * @param [in] interfaceName Name of the interface to use. + * @param [out] rvp PKCS#11 return value. Last return value seen. + * May be NULL. + * @return BAD_FUNC_ARG when dev or library are NULL pointers. + * @return BAD_PATH_ERROR when dynamic library cannot be opened. + * @return WC_INIT_E when the initialization PKCS#11 fails. + * @return WC_HW_E when unable to get PKCS#11 function list. + * @return 0 on success. + */ +int wc_Pkcs11_Initialize_v3(Pkcs11Dev* dev, const char* library, + void* heap, int* version, const char* interfaceName, CK_RV* rvp) { int ret = 0; CK_RV rv = CKR_OK; -#ifndef HAVE_PKCS11_STATIC +#if !defined(HAVE_PKCS11_STATIC) && !defined(HAVE_PKCS11_V3_STATIC) void* func; #endif CK_C_INITIALIZE_ARGS args; + CK_VERSION_PTR version_ptr = NULL; - if (dev == NULL || library == NULL) + if (dev == NULL) ret = BAD_FUNC_ARG; +#if !defined(HAVE_PKCS11_STATIC) && !defined(HAVE_PKCS11_V3_STATIC) + if (library == NULL) + ret = BAD_FUNC_ARG; +#endif + if (ret == 0) { dev->heap = heap; -#ifndef HAVE_PKCS11_STATIC +#if defined(HAVE_PKCS11_V3_STATIC) + CK_INTERFACE_PTR interface = NULL; + CK_VERSION pkcs11_version = {0, 0}; + + if (version != NULL) { + if (*version == WC_PCKS11VERSION_2_20) { + pkcs11_version.major = 2; + pkcs11_version.minor = 20; + } + else if (*version == WC_PCKS11VERSION_2_20) { + pkcs11_version.major = 2; + pkcs11_version.minor = 40; + } + else if (*version == WC_PCKS11VERSION_3_0) { + pkcs11_version.major = 3; + pkcs11_version.minor = 0; + } + else if (*version == WC_PCKS11VERSION_3_1) { + pkcs11_version.major = 3; + pkcs11_version.minor = 1; + } + else if (*version == WC_PCKS11VERSION_3_2) { + pkcs11_version.major = 3; + pkcs11_version.minor = 2; + } + version_ptr = &pkcs11_version; + } + else { + version_ptr = NULL; + } + + rv = C_GetInterface((CK_UTF8CHAR_PTR) interfaceName, version_ptr, + &interface, 0); + + if (rv == CKR_OK) { + dev->func = interface->pFunctionList; + version_ptr = (CK_VERSION_PTR) interface->pFunctionList; + if (version_ptr->major == 2 && version_ptr->minor == 20) { + dev->version = WC_PCKS11VERSION_2_20; + } + else if (version_ptr->major == 2 && + version_ptr->minor == 40) { + dev->version = WC_PCKS11VERSION_2_40; + } + else if (version_ptr->major == 3 && + version_ptr->minor == 0) { + dev->version = WC_PCKS11VERSION_3_0; + } + else if (version_ptr->major == 3 && + version_ptr->minor == 1) { + dev->version = WC_PCKS11VERSION_3_1; + } + else if (version_ptr->major == 3 && + version_ptr->minor == 2) { + dev->version = WC_PCKS11VERSION_3_2; + } + else { + WOLFSSL_MSG_EX("Unsupported PKCS#11 version: %d.%d", + version_ptr->major, version_ptr->minor); + ret = WC_HW_E; + } + } + else { + PKCS11_RV("CK_C_GetInterface", rv); + ret = WC_HW_E; + } +#elif defined(HAVE_PKCS11_STATIC) + rv = C_GetFunctionList(&dev->func); + if (rv == CKR_OK) { + version_ptr = (CK_VERSION_PTR) dev->func; + if (version_ptr->major == 2 && + version_ptr->minor == 20) { + dev->version = WC_PCKS11VERSION_2_20; + } + else if (version_ptr->major == 2 && + version_ptr->minor == 40) { + dev->version = WC_PCKS11VERSION_2_40; + } + else { + WOLFSSL_MSG_EX("Unsupported PKCS#11 version: %d.%d", + version_ptr->major, + version_ptr->minor); + ret = WC_HW_E; + } + } + else { + PKCS11_RV("CK_C_GetFunctionList", rv); + ret = WC_HW_E; + } +#else + /* Load dynamic library */ dev->dlHandle = dlopen(library, RTLD_NOW | RTLD_LOCAL); if (dev->dlHandle == NULL) { WOLFSSL_MSG(dlerror()); ret = BAD_PATH_ERROR; } + + if (ret == 0) { + /* Check if the library supports PKCS#11 version 3.0 (or above) by + * looking for the C_GetInterface method (only present for >= V3.0). + */ + func = dlsym(dev->dlHandle, "C_GetInterface"); + if (func != NULL) { + /* Function is present, use it */ + CK_INTERFACE_PTR interface = NULL; + CK_VERSION pkcs11_version = {0, 0}; + if (version != NULL) { + if (*version == WC_PCKS11VERSION_2_20) { + pkcs11_version.major = 2; + pkcs11_version.minor = 20; + } + else if (*version == WC_PCKS11VERSION_2_40) { + pkcs11_version.major = 2; + pkcs11_version.minor = 40; + } + else if (*version == WC_PCKS11VERSION_3_0) { + pkcs11_version.major = 3; + pkcs11_version.minor = 0; + } + else if (*version == WC_PCKS11VERSION_3_1) { + pkcs11_version.major = 3; + pkcs11_version.minor = 1; + } + else if (*version == WC_PCKS11VERSION_3_2) { + pkcs11_version.major = 3; + pkcs11_version.minor = 2; + } + version_ptr = &pkcs11_version; + } + else { + version_ptr = NULL; + } + + rv = ((CK_C_GetInterface)func)((CK_UTF8CHAR_PTR) interfaceName, + version_ptr, &interface, 0); + if (rv == CKR_OK) { + dev->func = interface->pFunctionList; + version_ptr = (CK_VERSION_PTR) interface->pFunctionList; + if (version_ptr->major == 2 && version_ptr->minor == 20) { + dev->version = WC_PCKS11VERSION_2_20; + } + else if (version_ptr->major == 2 && + version_ptr->minor == 40) { + dev->version = WC_PCKS11VERSION_2_40; + } + else if (version_ptr->major == 3 && + version_ptr->minor == 0) { + dev->version = WC_PCKS11VERSION_3_0; + } + else if (version_ptr->major == 3 && + version_ptr->minor == 1) { + dev->version = WC_PCKS11VERSION_3_1; + } + else if (version_ptr->major == 3 && + version_ptr->minor == 2) { + dev->version = WC_PCKS11VERSION_3_2; + } + else { + WOLFSSL_MSG_EX("Unsupported PKCS#11 version: %d.%d", + version_ptr->major, version_ptr->minor); + ret = WC_HW_E; + } + } + else { + PKCS11_RV("CK_C_GetInterface", rv); + ret = WC_HW_E; + } + } + else { + /* Function not present, try a 2.x library by looking for + * C_GetFunctionList. */ + func = dlsym(dev->dlHandle, "C_GetFunctionList"); + if (func == NULL) { + #if defined(_WIN32) + WOLFSSL_MSG_EX("GetProcAddress(): %d", GetLastError()); + #else + WOLFSSL_MSG(dlerror()); + #endif + ret = WC_HW_E; + } + if (ret == 0) { + rv = ((CK_C_GetFunctionList)func)(&dev->func); + if (rv == CKR_OK) { + version_ptr = (CK_VERSION_PTR) dev->func; + if (version_ptr->major == 2 && + version_ptr->minor == 20) { + dev->version = WC_PCKS11VERSION_2_20; + } + else if (version_ptr->major == 2 && + version_ptr->minor == 40) { + dev->version = WC_PCKS11VERSION_2_40; + } + else { + WOLFSSL_MSG_EX("Unsupported PKCS#11 version: %d.%d", + version_ptr->major, + version_ptr->minor); + ret = WC_HW_E; + } + } + else { + PKCS11_RV("CK_C_GetFunctionList", rv); + ret = WC_HW_E; + } + } + } + } +#endif } - if (ret == 0) { - dev->func = NULL; - func = dlsym(dev->dlHandle, "C_GetFunctionList"); - if (func == NULL) { - WOLFSSL_MSG(dlerror()); - ret = WC_HW_E; - } - } - if (ret == 0) { - rv = ((CK_C_GetFunctionList)func)(&dev->func); -#else - rv = C_GetFunctionList(&dev->func); -#endif - if (rv != CKR_OK) { - PKCS11_RV("CK_C_GetFunctionList", ret); - ret = WC_HW_E; - } - } + if (ret == 0 && version != NULL) + *version = dev->version; if (ret == 0) { XMEMSET(&args, 0x00, sizeof(args)); args.flags = CKF_OS_LOCKING_OK; rv = dev->func->C_Initialize(&args); - if (rv != CKR_OK) { - PKCS11_RV("C_Initialize", ret); + if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) { + WOLFSSL_MSG("PKCS#11 already initialized"); + rv = CKR_OK; + } + else if (rv != CKR_OK) { + PKCS11_RV("C_Initialize", rv); ret = WC_INIT_E; } } @@ -520,7 +804,7 @@ int wc_Pkcs11_Initialize_ex(Pkcs11Dev* dev, const char* library, void* heap, void wc_Pkcs11_Finalize(Pkcs11Dev* dev) { if (dev != NULL -#ifndef HAVE_PKCS11_STATIC +#if !defined(HAVE_PKCS11_STATIC) && !defined(HAVE_PKCS11_V3_STATIC) && dev->dlHandle != NULL #endif ) { @@ -528,7 +812,7 @@ void wc_Pkcs11_Finalize(Pkcs11Dev* dev) dev->func->C_Finalize(NULL); dev->func = NULL; } -#ifndef HAVE_PKCS11_STATIC +#if !defined(HAVE_PKCS11_STATIC) && !defined(HAVE_PKCS11_V3_STATIC) dlclose(dev->dlHandle); dev->dlHandle = NULL; #endif @@ -633,6 +917,7 @@ static int Pkcs11Token_Init(Pkcs11Token* token, Pkcs11Dev* dev, int slotId, token->userPin = NULL_PTR; token->userPinSz = 0; token->userPinLogin = 0; + token->version = dev->version; } XFREE(slot, dev->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -809,6 +1094,7 @@ static int Pkcs11OpenSession(Pkcs11Token* token, Pkcs11Session* session, if (ret == 0) { session->func = token->func; session->slotId = token->slotId; + session->version = token->version; } return ret; @@ -1060,13 +1346,24 @@ static int Pkcs11EccSetParams(ecc_key* key, CK_ATTRIBUTE* tmpl, int idx) { int ret = 0; - if (key->dp != NULL && key->dp->oid != NULL) { + if (key != NULL && key->dp != NULL && key->dp->oid != NULL) { unsigned char* derParams = tmpl[idx].pValue; + #if defined(HAVE_OID_ENCODING) + word32 oidSz = ECC_MAX_OID_LEN - 2; + ret = wc_EncodeObjectId(key->dp->oid, key->dp->oidSz, derParams+2, &oidSz); + if (ret != 0) { + return ret; + } + tmpl[idx].ulValueLen = oidSz + 2; + derParams[0] = ASN_OBJECT_ID; + derParams[1] = oidSz; + #else /* ASN.1 encoding: OBJ + ecc parameters OID */ tmpl[idx].ulValueLen = key->dp->oidSz + 2; derParams[0] = ASN_OBJECT_ID; derParams[1] = key->dp->oidSz; XMEMCPY(derParams + 2, key->dp->oid, key->dp->oidSz); + #endif } else ret = NOT_COMPILED_IN; @@ -1096,7 +1393,7 @@ static int Pkcs11CreateEccPublicKey(CK_OBJECT_HANDLE* publicKey, unsigned char* ecPoint = NULL; word32 len; CK_RV rv; - CK_UTF8CHAR params[MAX_EC_PARAM_LEN]; + CK_UTF8CHAR params[ECC_MAX_OID_LEN]; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, @@ -1180,7 +1477,7 @@ static int Pkcs11CreateEccPrivateKey(CK_OBJECT_HANDLE* privateKey, { int ret = 0; CK_RV rv; - CK_UTF8CHAR params[MAX_EC_PARAM_LEN]; + CK_UTF8CHAR params[ECC_MAX_OID_LEN]; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, @@ -1209,16 +1506,30 @@ static int Pkcs11CreateEccPrivateKey(CK_OBJECT_HANDLE* privateKey, ret = Pkcs11EccSetParams(private_key, keyTemplate, 3); if (ret == 0) { - keyTemplate[4].pValue = wc_ecc_key_get_priv(private_key)->raw.buf; - keyTemplate[4].ulValueLen = wc_ecc_key_get_priv(private_key)->raw.len; - - PKCS11_DUMP_TEMPLATE("Ec Private Key", keyTemplate, keyTmplCnt); - rv = session->func->C_CreateObject(session->handle, keyTemplate, - keyTmplCnt, privateKey); - PKCS11_RV("C_CreateObject", rv); - if (rv != CKR_OK) { - ret = WC_HW_E; + word32 privLen = private_key->dp->size; + byte* priv = (byte*)XMALLOC(privLen, private_key->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (priv == NULL) { + ret = MEMORY_E; } + if (ret == 0) { + PRIVATE_KEY_LOCK(); + ret = wc_ecc_export_private_only(private_key, priv, &privLen); + PRIVATE_KEY_UNLOCK(); + } + if (ret == 0) { + keyTemplate[4].pValue = priv; + keyTemplate[4].ulValueLen = privLen; + + PKCS11_DUMP_TEMPLATE("Ec Private Key", keyTemplate, keyTmplCnt); + rv = session->func->C_CreateObject(session->handle, keyTemplate, + keyTmplCnt, privateKey); + PKCS11_RV("C_CreateObject", rv); + if (rv != CKR_OK) { + ret = WC_HW_E; + } + } + XFREE(priv, private_key->heap, DYNAMIC_TYPE_TMP_BUFFER); } return ret; @@ -1230,22 +1541,28 @@ static int Pkcs11CreateEccPrivateKey(CK_OBJECT_HANDLE* privateKey, /** * Check if mechanism is available in session on token. * - * @param [in] session Session object. - * @param [in] mech Mechanism to look for. + * @param [in] session Session object. + * @param [in] mech Mechanism to look for. + * @param [out] mechInfoPtr Mechanism info return data (optional). * @return NOT_COMPILED_IN when mechanism not available. * @return 0 when mechanism is available. */ -static int Pkcs11MechAvail(Pkcs11Session* session, CK_MECHANISM_TYPE mech) +static int Pkcs11MechAvail(Pkcs11Session* session, CK_MECHANISM_TYPE mech, + CK_MECHANISM_INFO_PTR mechInfoPtr) { int ret = 0; CK_RV rv; CK_MECHANISM_INFO mechInfo; + PKCS11_DUMP_MECHANSIM("PKCS#11: Check if mechanism is available", mech); rv = session->func->C_GetMechanismInfo(session->slotId, mech, &mechInfo); PKCS11_RV("C_GetMechanismInfo", rv); if (rv != CKR_OK) { ret = NOT_COMPILED_IN; } + if (mechInfoPtr != NULL) { + *mechInfoPtr = mechInfo; + } return ret; } @@ -1335,7 +1652,7 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) case PKCS11_KEY_TYPE_AES_GCM: { Aes* aes = (Aes*)key; - ret = Pkcs11MechAvail(&session, CKM_AES_GCM); + ret = Pkcs11MechAvail(&session, CKM_AES_GCM, NULL); if (ret == 0) { ret = Pkcs11CreateSecretKey(&privKey, &session, CKK_AES, (unsigned char*)aes->devKey, @@ -1353,7 +1670,7 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) case PKCS11_KEY_TYPE_AES_CBC: { Aes* aes = (Aes*)key; - ret = Pkcs11MechAvail(&session, CKM_AES_CBC); + ret = Pkcs11MechAvail(&session, CKM_AES_CBC, NULL); if (ret == 0) { ret = Pkcs11CreateSecretKey(&privKey, &session, CKK_AES, (unsigned char*)aes->devKey, @@ -1378,7 +1695,7 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) break; if (ret == 0) - ret = Pkcs11MechAvail(&session, mechType); + ret = Pkcs11MechAvail(&session, mechType, NULL); if (ret == 0) { ret = Pkcs11CreateSecretKey(&privKey, &session, keyType, (unsigned char*)hmac->keyRaw, @@ -1403,7 +1720,7 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) case PKCS11_KEY_TYPE_RSA: { RsaKey* rsaKey = (RsaKey*)key; - ret = Pkcs11MechAvail(&session, CKM_RSA_X_509); + ret = Pkcs11MechAvail(&session, CKM_RSA_X_509, NULL); if (ret == 0) ret = Pkcs11CreateRsaPrivateKey(&privKey, &session, rsaKey, 1); @@ -1426,7 +1743,7 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) #ifndef NO_PKCS11_ECDH if ((eccKey->flags & WC_ECC_FLAG_DEC_SIGN) == 0) { /* Try ECDH mechanism first. */ - ret = Pkcs11MechAvail(&session, CKM_ECDH1_DERIVE); + ret = Pkcs11MechAvail(&session, CKM_ECDH1_DERIVE, NULL); if (ret == 0) { ret = Pkcs11CreateEccPrivateKey(&privKey, &session, eccKey, CKA_DERIVE); @@ -1435,7 +1752,7 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) #endif if (ret == 0 || ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { /* Try ECDSA mechanism next. */ - ret2 = Pkcs11MechAvail(&session, CKM_ECDSA); + ret2 = Pkcs11MechAvail(&session, CKM_ECDSA, NULL); if (ret2 == 0) { ret2 = Pkcs11CreateEccPrivateKey(&privKey, &session, eccKey, CKA_SIGN); @@ -2188,7 +2505,6 @@ static int Pkcs11RsaSign(Pkcs11Session* session, wc_CryptoInfo* info, static int Pkcs11Rsa(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; - CK_RV rv; CK_MECHANISM_INFO mechInfo; CK_MECHANISM_TYPE mechanism = 0x0UL; int sessionKey = 0; @@ -2214,12 +2530,7 @@ static int Pkcs11Rsa(Pkcs11Session* session, wc_CryptoInfo* info) } /* Check operation is supported. */ - rv = session->func->C_GetMechanismInfo(session->slotId, mechanism, - &mechInfo); - PKCS11_RV("C_GetMechanismInfo", rv); - if (rv != CKR_OK) { - ret = NOT_COMPILED_IN; - } + ret = Pkcs11MechAvail(session, mechanism, &mechInfo); if (ret == 0) { if ((type == RSA_PUBLIC_ENCRYPT) || (type == RSA_PUBLIC_DECRYPT)) { @@ -2318,7 +2629,7 @@ static int Pkcs11RsaKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) int privTmplCnt = 2; int i; - ret = Pkcs11MechAvail(session, CKM_RSA_PKCS_KEY_PAIR_GEN); + ret = Pkcs11MechAvail(session, CKM_RSA_PKCS_KEY_PAIR_GEN, NULL); if (ret == 0) { WOLFSSL_MSG("PKCS#11: RSA Key Generation Operation"); @@ -2394,9 +2705,8 @@ static int Pkcs11FindEccKey(CK_OBJECT_HANDLE* key, CK_OBJECT_CLASS keyClass, int i; unsigned char* ecPoint = NULL; word32 len = 0; - CK_RV rv; CK_ULONG count; - CK_UTF8CHAR params[MAX_EC_PARAM_LEN]; + CK_UTF8CHAR params[ECC_MAX_OID_LEN]; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &ecKeyType, sizeof(ecKeyType) }, @@ -2433,26 +2743,7 @@ static int Pkcs11FindEccKey(CK_OBJECT_HANDLE* key, CK_OBJECT_CLASS keyClass, attrCnt++; } if (ret == 0) { - PKCS11_DUMP_TEMPLATE("Find Ec Key", keyTemplate, attrCnt); - rv = session->func->C_FindObjectsInit(session->handle, keyTemplate, - attrCnt); - PKCS11_RV("C_FindObjectsInit", rv); - if (rv != CKR_OK) { - ret = WC_HW_E; - } - } - if (ret == 0) { - rv = session->func->C_FindObjects(session->handle, key, 1, &count); - PKCS11_RV("C_FindObjects", rv); - PKCS11_VAL("C_FindObjects Count", count); - if (rv != CKR_OK) { - ret = WC_HW_E; - } - rv = session->func->C_FindObjectsFinal(session->handle); - PKCS11_RV("C_FindObjectsFinal", rv); - if (rv != CKR_OK) { - ret = WC_HW_E; - } + ret = Pkcs11FindKeyByTemplate(key, session, keyTemplate, attrCnt, &count); } XFREE(ecPoint, eccKey->heap, DYNAMIC_TYPE_ECC); @@ -2560,7 +2851,7 @@ static int Pkcs11EcKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) CK_RV rv; CK_OBJECT_HANDLE pubKey = NULL_PTR, privKey = NULL_PTR; CK_MECHANISM mech; - CK_UTF8CHAR params[MAX_EC_PARAM_LEN]; + CK_UTF8CHAR params[ECC_MAX_OID_LEN]; CK_ATTRIBUTE pubKeyTmpl[] = { { CKA_EC_PARAMS, params, 0 }, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, @@ -2584,7 +2875,7 @@ static int Pkcs11EcKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) /* Mandatory entries + 2 optional. */ int privTmplCnt = 1; - ret = Pkcs11MechAvail(session, CKM_EC_KEY_PAIR_GEN); + ret = Pkcs11MechAvail(session, CKM_EC_KEY_PAIR_GEN, NULL); if (ret == 0) { WOLFSSL_MSG("PKCS#11: EC Key Generation Operation"); @@ -2670,7 +2961,9 @@ static int Pkcs11ExtractSecret(Pkcs11Session* session, CK_OBJECT_HANDLE secret, } PKCS11_DUMP_TEMPLATE("Secret Length", tmpl, tmplCnt); if (ret == 0) { - if (tmpl[0].ulValueLen > *outLen) + if (tmpl[0].ulValueLen == CK_UNAVAILABLE_INFORMATION) + ret = WC_HW_E; + else if (tmpl[0].ulValueLen > *outLen) ret = BUFFER_E; } if (ret == 0) { @@ -2720,7 +3013,7 @@ static int Pkcs11ECDH(Pkcs11Session* session, wc_CryptoInfo* info) }; CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); - ret = Pkcs11MechAvail(session, CKM_ECDH1_DERIVE); + ret = Pkcs11MechAvail(session, CKM_ECDH1_DERIVE, NULL); if (ret == 0 && info->pk.ecdh.outlen == NULL) { ret = BAD_FUNC_ARG; } @@ -3008,12 +3301,10 @@ static int Pkcs11ECDSA_Sign(Pkcs11Session* session, wc_CryptoInfo* info) CK_OBJECT_HANDLE privateKey = NULL_PTR; /* Check operation is supported. */ - rv = session->func->C_GetMechanismInfo(session->slotId, CKM_ECDSA, - &mechInfo); - PKCS11_RV("C_GetMechanismInfo", rv); - if (rv != CKR_OK || (mechInfo.flags & CKF_SIGN) == 0) + ret = Pkcs11MechAvail(session, CKM_ECDSA, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_SIGN) == 0) { ret = NOT_COMPILED_IN; - + } if (ret == 0 && info->pk.eccsign.outlen == NULL) { ret = BAD_FUNC_ARG; } @@ -3105,20 +3396,20 @@ static int Pkcs11ECDSA_Sign(Pkcs11Session* session, wc_CryptoInfo* info) static int Pkcs11ECDSA_Verify(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; + int sessionKey = 0; CK_RV rv; CK_MECHANISM mech; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE publicKey = NULL_PTR; unsigned char* sig = NULL; - word32 sz = info->pk.eccverify.key->dp->size; + ecc_key* key = info->pk.eccverify.key; + word32 sz = key->dp->size; /* Check operation is supported. */ - rv = session->func->C_GetMechanismInfo(session->slotId, CKM_ECDSA, - &mechInfo); - PKCS11_RV("C_GetMechanismInfo", rv); - if (rv != CKR_OK || (mechInfo.flags & CKF_VERIFY) == 0) + ret = Pkcs11MechAvail(session, CKM_ECDSA, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_VERIFY) == 0) { ret = NOT_COMPILED_IN; - + } if (ret == 0 && info->pk.eccverify.res == NULL) { ret = BAD_FUNC_ARG; } @@ -3126,12 +3417,32 @@ static int Pkcs11ECDSA_Verify(Pkcs11Session* session, wc_CryptoInfo* info) if (ret == 0) { WOLFSSL_MSG("PKCS#11: EC Verification Operation"); - ret = Pkcs11CreateEccPublicKey(&publicKey, session, - info->pk.eccverify.key, CKA_VERIFY); + if (key->labelLen > 0) { + ret = Pkcs11FindKeyByLabel(&publicKey, CKO_PUBLIC_KEY, CKK_EC, + session, key->label, key->labelLen); + if (ret == 0 && key->dp == NULL) { + ret = Pkcs11GetEccParams(session, publicKey, key); + } + } + else if (key->idLen > 0) { + ret = Pkcs11FindKeyById(&publicKey, CKO_PUBLIC_KEY, CKK_EC, + session, key->id, key->idLen); + if (ret == 0 && key->dp == NULL) { + ret = Pkcs11GetEccParams(session, publicKey, key); + } + } + else if (!mp_iszero(key->pubkey.x)) { + ret = Pkcs11CreateEccPublicKey(&publicKey, session, key, + CKA_VERIFY); + sessionKey = 1; + } + else + ret = Pkcs11FindEccKey(&publicKey, CKO_PUBLIC_KEY, session, + info->pk.eccsign.key, CKA_VERIFY); } if (ret == 0) { - sig = (unsigned char *)XMALLOC(sz * 2, info->pk.eccverify.key->heap, + sig = (unsigned char *)XMALLOC(sz * 2, key->heap, DYNAMIC_TYPE_TMP_BUFFER); if (sig == NULL) ret = MEMORY_E; @@ -3168,7 +3479,7 @@ static int Pkcs11ECDSA_Verify(Pkcs11Session* session, wc_CryptoInfo* info) *info->pk.eccverify.res = 1; } - if (publicKey != NULL_PTR) + if (sessionKey && publicKey != NULL_PTR) session->func->C_DestroyObject(session->handle, publicKey); if (sig != NULL) @@ -3429,12 +3740,10 @@ static int Pkcs11AesGcmEncrypt(Pkcs11Session* session, wc_CryptoInfo* info) CK_ULONG outLen; /* Check operation is supported. */ - rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_GCM, - &mechInfo); - PKCS11_RV("C_GetMechanismInfo", rv); - if (rv != CKR_OK || (mechInfo.flags & CKF_ENCRYPT) == 0) + ret = Pkcs11MechAvail(session, CKM_AES_GCM, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_ENCRYPT) == 0) { ret = NOT_COMPILED_IN; - + } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-GCM Encryption Operation"); @@ -3524,12 +3833,10 @@ static int Pkcs11AesGcmDecrypt(Pkcs11Session* session, wc_CryptoInfo* info) word32 len; /* Check operation is supported. */ - rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_GCM, - &mechInfo); - PKCS11_RV("C_GetMechanismInfo", rv); - if (rv != CKR_OK || (mechInfo.flags & CKF_DECRYPT) == 0) + ret = Pkcs11MechAvail(session, CKM_AES_GCM, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_DECRYPT) == 0) { ret = NOT_COMPILED_IN; - + } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-GCM Decryption Operation"); @@ -3633,12 +3940,10 @@ static int Pkcs11AesCbcEncrypt(Pkcs11Session* session, wc_CryptoInfo* info) CK_ULONG outLen; /* Check operation is supported. */ - rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_CBC, - &mechInfo); - PKCS11_RV("C_GetMechanismInfo", rv); - if (rv != CKR_OK || (mechInfo.flags & CKF_ENCRYPT) == 0) + ret = Pkcs11MechAvail(session, CKM_AES_CBC, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_ENCRYPT) == 0) { ret = NOT_COMPILED_IN; - + } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-CBC Encryption Operation"); @@ -3709,12 +4014,10 @@ static int Pkcs11AesCbcDecrypt(Pkcs11Session* session, wc_CryptoInfo* info) CK_ULONG outLen; /* Check operation is supported. */ - rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_CBC, - &mechInfo); - PKCS11_RV("C_GetMechanismInfo", rv); - if (rv != CKR_OK || (mechInfo.flags & CKF_DECRYPT) == 0) + ret = Pkcs11MechAvail(session, CKM_AES_CBC, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_DECRYPT) == 0) { ret = NOT_COMPILED_IN; - + } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-CBC Decryption Operation"); @@ -3789,12 +4092,10 @@ static int Pkcs11AesCtrEncrypt(Pkcs11Session* session, wc_CryptoInfo* info) CK_ULONG outLen; /* Check operation is supported. */ - rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_CTR, - &mechInfo); - PKCS11_RV("C_GetMechanismInfo", rv); - if (rv != CKR_OK || (mechInfo.flags & CKF_ENCRYPT) == 0) + ret = Pkcs11MechAvail(session, CKM_AES_CTR, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_ENCRYPT) == 0) { ret = NOT_COMPILED_IN; - + } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-CTR Encryption Operation"); @@ -3870,12 +4171,10 @@ static int Pkcs11AesCtrDecrypt(Pkcs11Session* session, wc_CryptoInfo* info) CK_ULONG outLen; /* Check operation is supported. */ - rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_CTR, - &mechInfo); - PKCS11_RV("C_GetMechanismInfo", rv); - if (rv != CKR_OK || (mechInfo.flags & CKF_DECRYPT) == 0) + ret = Pkcs11MechAvail(session, CKM_AES_CTR, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_DECRYPT) == 0) { ret = NOT_COMPILED_IN; - + } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-CTR Decryption Operation"); @@ -3960,11 +4259,10 @@ static int Pkcs11Hmac(Pkcs11Session* session, wc_CryptoInfo* info) ret = Pkcs11HmacTypes(info->hmac.macType, &mechType, &keyType); if (ret == 0) { /* Check operation is supported. */ - rv = session->func->C_GetMechanismInfo(session->slotId, mechType, - &mechInfo); - PKCS11_RV("C_GetMechanismInfo", rv); - if (rv != CKR_OK || (mechInfo.flags & CKF_SIGN) == 0) + ret = Pkcs11MechAvail(session, mechType, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_SIGN) == 0) { ret = NOT_COMPILED_IN; + } } /* Check whether key been used to initialized. */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index a14991294d..b9a28d4b18 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -31783,6 +31783,8 @@ typedef struct Srtp_Kdf_Tv { word32 ksSz; } Srtp_Kdf_Tv; +#define SRTP_KDF_LONG_KEY 5000 + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t srtpkdf_test(void) { wc_test_ret_t ret = 0; @@ -32034,6 +32036,18 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t srtpkdf_test(void) unsigned char keyE[32]; unsigned char keyA[20]; unsigned char keyS[14]; +#ifndef BENCH_EMBEDDED + WC_DECLARE_VAR(keyELong, byte, SRTP_KDF_LONG_KEY, HEAP_HINT); + WC_DECLARE_VAR(keyALong, byte, SRTP_KDF_LONG_KEY, HEAP_HINT); + WC_DECLARE_VAR(keySLong, byte, SRTP_KDF_LONG_KEY, HEAP_HINT); +#endif + +#ifndef BENCH_EMBEDDED + WC_ALLOC_VAR(keyELong, byte, SRTP_KDF_LONG_KEY, HEAP_HINT); + WC_ALLOC_VAR(keyALong, byte, SRTP_KDF_LONG_KEY, HEAP_HINT); + WC_ALLOC_VAR(keySLong, byte, SRTP_KDF_LONG_KEY, HEAP_HINT); +#endif + WOLFSSL_ENTER("srtpkdf_test"); for (i = 0; (ret == 0) && (i < SRTP_TV_CNT); i++) { @@ -32284,6 +32298,30 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t srtpkdf_test(void) return WC_TEST_RET_ENC_NC; } +#ifndef BENCH_EMBEDDED + /* Check that long messages can be created. */ + ret = wc_SRTP_KDF(tv[0].key, tv[0].keySz, tv[0].salt, tv[0].saltSz, + tv[0].kdfIdx, tv[0].index_c, keyELong, SRTP_KDF_LONG_KEY, keyALong, + SRTP_KDF_LONG_KEY, keySLong, SRTP_KDF_LONG_KEY); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* Check that two bytes of counter are being used. */ + if (XMEMCMP(keyELong, keyELong + 4096, SRTP_KDF_LONG_KEY - 4096) == 0) { + return WC_TEST_RET_ENC_NC; + } + if (XMEMCMP(keyELong, keyALong + 4096, SRTP_KDF_LONG_KEY - 4096) == 0) { + return WC_TEST_RET_ENC_NC; + } + if (XMEMCMP(keyELong, keySLong + 4096, SRTP_KDF_LONG_KEY - 4096) == 0) { + return WC_TEST_RET_ENC_NC; + } + + WC_FREE_VAR(keyELong, HEAP_HINT); + WC_FREE_VAR(keyALong, HEAP_HINT); + WC_FREE_VAR(keySLong, HEAP_HINT); +#endif + return 0; } #endif diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 59fb268aef..5eca832149 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -5335,6 +5335,19 @@ struct WOLFSSL_X509_NAME { #endif #endif +#ifndef WOLFSSL_AIA_ENTRY_DEFINED +#ifndef WOLFSSL_MAX_AIA_ENTRIES + #define WOLFSSL_MAX_AIA_ENTRIES 8 +#endif + +#define WOLFSSL_AIA_ENTRY_DEFINED +typedef struct WOLFSSL_AIA_ENTRY { + word32 method; /* AIA method OID sum (e.g., AIA_OCSP_OID). */ + const byte* uri; /* Pointer into cert DER for the URI. */ + word32 uriSz; /* Length of URI data. */ +} WOLFSSL_AIA_ENTRY; +#endif /* WOLFSSL_AIA_ENTRY_DEFINED */ + struct WOLFSSL_X509 { int version; int serialSz; @@ -5405,6 +5418,9 @@ struct WOLFSSL_X509 { byte* authInfoCaIssuer; int authInfoCaIssuerSz; #endif + WOLFSSL_AIA_ENTRY authInfoList[WOLFSSL_MAX_AIA_ENTRIES]; + byte authInfoListSz:7; + byte authInfoListOverflow:1; word32 pathLength; word16 keyUsage; int rawCRLInfoSz; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 08989907c3..ed88c09002 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1917,6 +1917,8 @@ WOLFSSL_API WOLFSSL_STACK* wolfSSL_sk_get_node(WOLFSSL_STACK* sk, int idx); #endif #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) WOLFSSL_API int wolfSSL_sk_push_node(WOLFSSL_STACK** stack, WOLFSSL_STACK* in); +WOLFSSL_API int wolfSSL_sk_push_back_node(WOLFSSL_STACK** stack, + WOLFSSL_STACK* in); WOLFSSL_API void wolfSSL_sk_free(WOLFSSL_STACK* sk); WOLFSSL_API WOLFSSL_STACK* wolfSSL_sk_dup(WOLFSSL_STACK* sk); @@ -5796,6 +5798,11 @@ WOLFSSL_API int wolfSSL_X509_STORE_CTX_get1_issuer(WOLFSSL_X509 **issuer, WOLFSSL_API void wolfSSL_X509_email_free(WOLF_STACK_OF(WOLFSSL_STRING) *sk); WOLFSSL_API WOLF_STACK_OF(WOLFSSL_STRING) *wolfSSL_X509_get1_ocsp(WOLFSSL_X509 *x); +WOLFSSL_API int wolfSSL_X509_get_aia_overflow(WOLFSSL_X509 *x); +#ifdef WOLFSSL_ASN_CA_ISSUER +WOLFSSL_API WOLF_STACK_OF(WOLFSSL_STRING) *wolfSSL_X509_get1_ca_issuers( + WOLFSSL_X509 *x); +#endif /* WOLFSSL_ASN_CA_ISSUER */ WOLFSSL_API int wolfSSL_X509_check_issued(WOLFSSL_X509 *issuer, WOLFSSL_X509 *subject); diff --git a/wolfssl/wolfcrypt/aes.h b/wolfssl/wolfcrypt/aes.h index fa077bfe8e..85d5b71fa0 100644 --- a/wolfssl/wolfcrypt/aes.h +++ b/wolfssl/wolfcrypt/aes.h @@ -334,7 +334,7 @@ struct Aes { #endif /* __aarch64__ && WOLFSSL_ARMASM && !WOLFSSL_ARMASM_NO_HW_CRYPTO */ #if defined(WOLF_CRYPTO_CB) || defined(WOLFSSL_STM32U5_DHUK) int devId; - void* devCtx; + void* devCtx; /* Opaque handle for CryptoCB device */ #endif #ifdef WOLF_PRIVATE_KEY_ID byte id[AES_MAX_ID_LEN]; diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 992c715e7c..e1448c145a 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1702,6 +1702,19 @@ typedef struct TrustedPeerCert TrustedPeerCert; #endif /* WOLFSSL_TRUST_PEER_CERT */ typedef struct SignatureCtx SignatureCtx; +#ifndef WOLFSSL_AIA_ENTRY_DEFINED +#ifndef WOLFSSL_MAX_AIA_ENTRIES + #define WOLFSSL_MAX_AIA_ENTRIES 8 +#endif + +#define WOLFSSL_AIA_ENTRY_DEFINED +typedef struct WOLFSSL_AIA_ENTRY { + word32 method; /* AIA method OID sum (e.g., AIA_OCSP_OID). */ + const byte* uri; /* Pointer into cert DER for the URI. */ + word32 uriSz; /* Length of URI data. */ +} WOLFSSL_AIA_ENTRY; +#endif /* WOLFSSL_AIA_ENTRY_DEFINED */ + #ifdef WC_ASN_UNKNOWN_EXT_CB typedef int (*wc_UnknownExtCallback)(const word16* oid, word32 oidSz, int crit, const unsigned char* der, word32 derSz); @@ -2060,6 +2073,10 @@ struct DecodedCert { WC_BITFIELD extAltSigAlgCrit:1; WC_BITFIELD extAltSigValCrit:1; #endif /* WOLFSSL_DUAL_ALG_CERTS */ + + WOLFSSL_AIA_ENTRY extAuthInfoList[WOLFSSL_MAX_AIA_ENTRIES]; + WC_BITFIELD extAuthInfoListSz:7; + WC_BITFIELD extAuthInfoListOverflow:1; }; #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) @@ -2209,6 +2226,8 @@ typedef enum MimeStatus #define GetShortInt wc_GetShortInt #define SetShortInt wc_SetShortInt #define GetLength wc_GetLength + #define SetLength wc_SetLength + #define SetSequence wc_SetSequence #define GetASNInt wc_GetASNInt #define GetASNTag wc_GetASNTag #define SetAlgoID wc_SetAlgoID @@ -2468,11 +2487,11 @@ WOLFSSL_LOCAL word32 SetASNImplicit(byte tag,byte number, word32 len, WOLFSSL_LOCAL word32 SetASNExplicit(byte number, word32 len, byte* output); WOLFSSL_LOCAL word32 SetASNSet(word32 len, byte* output); -WOLFSSL_LOCAL word32 SetLength(word32 length, byte* output); +WOLFSSL_ASN_API word32 SetLength(word32 length, byte* output); WOLFSSL_LOCAL word32 SetLengthEx(word32 length, byte* output, byte isIndef); WOLFSSL_LOCAL word32 SetHeader(byte tag, word32 len, byte* output, byte isIndef); -WOLFSSL_LOCAL word32 SetSequence(word32 len, byte* output); +WOLFSSL_ASN_API word32 SetSequence(word32 len, byte* output); WOLFSSL_LOCAL word32 SetSequenceEx(word32 len, byte* output, byte isIndef); WOLFSSL_LOCAL word32 SetIndefEnd(byte* output); WOLFSSL_LOCAL word32 SetOctetString(word32 len, byte* output); diff --git a/wolfssl/wolfcrypt/cpuid.h b/wolfssl/wolfcrypt/cpuid.h index 176f99f292..38b64e8fa7 100644 --- a/wolfssl/wolfcrypt/cpuid.h +++ b/wolfssl/wolfcrypt/cpuid.h @@ -122,7 +122,11 @@ typedef word32 cpuid_flags_t; * accurate. */ static WC_INLINE int cpuid_get_flags_atomic(cpuid_flags_atomic_t *flags) { + #ifdef WOLFSSL_BSDKM + if (WOLFSSL_ATOMIC_LOAD_UINT(*flags) == WC_CPUID_INITIALIZER) { + #else if (WOLFSSL_ATOMIC_LOAD(*flags) == WC_CPUID_INITIALIZER) { + #endif /* WOLFSSL_BSDKM */ cpuid_flags_t old_cpuid_flags = WC_CPUID_INITIALIZER; return wolfSSL_Atomic_Uint_CompareExchange (flags, &old_cpuid_flags, cpuid_get_flags()); diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index 455da94ddd..7e4924bc78 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -376,6 +376,13 @@ typedef struct wc_CryptoInfo { const byte* in; word32 sz; } des3; + #endif + #if !defined(NO_AES) && defined(WOLF_CRYPTO_CB_AES_SETKEY) + struct { + Aes* aes; + const byte* key; + word32 keySz; + } aessetkey; #endif void* ctx; #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES @@ -678,6 +685,9 @@ WOLFSSL_LOCAL int wc_CryptoCb_AesEcbEncrypt(Aes* aes, byte* out, WOLFSSL_LOCAL int wc_CryptoCb_AesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz); #endif /* HAVE_AES_ECB */ +#ifdef WOLF_CRYPTO_CB_AES_SETKEY +WOLFSSL_API int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz); +#endif /* WOLF_CRYPTO_CB_AES_SETKEY */ #endif /* !NO_AES */ #ifndef NO_DES3 diff --git a/wolfssl/wolfcrypt/pkcs11.h b/wolfssl/wolfcrypt/pkcs11.h index 2413e724e0..4cf7ae7011 100644 --- a/wolfssl/wolfcrypt/pkcs11.h +++ b/wolfssl/wolfcrypt/pkcs11.h @@ -34,6 +34,7 @@ extern "C" { #define CK_INVALID_HANDLE 0UL +#define CK_UNAVAILABLE_INFORMATION (~0UL) #define CKN_SURRENDER 0UL @@ -184,6 +185,7 @@ extern "C" { #define CKR_OK 0x00000000UL #define CKR_MECHANISM_INVALID 0x00000070UL #define CKR_SIGNATURE_INVALID 0x000000C0UL +#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191UL #define CKD_NULL 0x00000001UL #define CKZ_DATA_SPECIFIED 0x00000001UL @@ -384,15 +386,47 @@ typedef struct CK_RSA_PKCS_OAEP_PARAMS { } CK_RSA_PKCS_OAEP_PARAMS; typedef CK_RSA_PKCS_OAEP_PARAMS *CK_RSA_PKCS_OAEP_PARAMS_PTR; +typedef struct CK_ASYNC_DATA { + CK_ULONG ulVersion; + CK_BYTE_PTR pValue; + CK_ULONG ulValueLen; + CK_OBJECT_HANDLE hObject; + CK_OBJECT_HANDLE hAdditionalObject; +} CK_ASYNC_DATA; +typedef CK_ASYNC_DATA* CK_ASYNC_DATA_PTR; + /* Function list types. */ typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST; +typedef struct CK_FUNCTION_LIST_3_0 CK_FUNCTION_LIST_3_0; +typedef struct CK_FUNCTION_LIST_3_2 CK_FUNCTION_LIST_3_2; + typedef CK_FUNCTION_LIST* CK_FUNCTION_LIST_PTR; +typedef CK_FUNCTION_LIST_3_0* CK_FUNCTION_LIST_3_0_PTR; +typedef CK_FUNCTION_LIST_3_2* CK_FUNCTION_LIST_3_2_PTR; + typedef CK_FUNCTION_LIST_PTR* CK_FUNCTION_LIST_PTR_PTR; +typedef CK_FUNCTION_LIST_3_0_PTR* CK_FUNCTION_LIST_3_0_PTR_PTR; +typedef CK_FUNCTION_LIST_3_2_PTR* CK_FUNCTION_LIST_3_2_PTR_PTR; typedef CK_RV (*CK_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); -#ifdef HAVE_PKCS11_STATIC +typedef struct CK_INTERFACE { + CK_UTF8CHAR_PTR pInterfaceName; + CK_VOID_PTR pFunctionList; + CK_FLAGS flags; +} CK_INTERFACE; + +typedef CK_INTERFACE* CK_INTERFACE_PTR; +typedef CK_INTERFACE_PTR* CK_INTERFACE_PTR_PTR; + +typedef CK_RV (*CK_C_GetInterface)(CK_UTF8CHAR_PTR pInterfaceName, + CK_VERSION_PTR pVersion, CK_INTERFACE_PTR_PTR ppInterface, CK_FLAGS flags); + +#if defined(HAVE_PKCS11_STATIC) CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); +#elif defined(HAVE_PKCS11_V3_STATIC) +CK_RV C_GetInterface(CK_UTF8CHAR_PTR pInterfaceName, CK_VERSION_PTR pVersion, + CK_INTERFACE_PTR_PTR ppInterface, CK_FLAGS flags); #endif struct CK_FUNCTION_LIST { @@ -578,6 +612,533 @@ struct CK_FUNCTION_LIST { }; +struct CK_FUNCTION_LIST_3_0 { + CK_VERSION version; + + CK_RV (*C_Initialize)(CK_VOID_PTR pInitArgs); + CK_RV (*C_Finalize)(CK_VOID_PTR pReserved); + CK_RV (*C_GetInfo)(CK_INFO_PTR pInfo); + CK_RV (*C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); + CK_RV (*C_GetSlotList)(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, + CK_ULONG_PTR pulCount); + CK_RV (*C_GetSlotInfo)(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo); + CK_RV (*C_GetTokenInfo)(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo); + CK_RV (*C_GetMechanismList)(CK_SLOT_ID slotID, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount); + CK_RV (*C_GetMechanismInfo)(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo); + CK_RV (*C_InitToken)(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, + CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel); + CK_RV (*C_InitPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, + CK_ULONG ulPinLen); + CK_RV (*C_SetPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, + CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, + CK_ULONG ulNewLen); + CK_RV (*C_OpenSession)(CK_SLOT_ID slotID, CK_FLAGS flags, + CK_VOID_PTR pApplication, CK_NOTIFY Notify, + CK_SESSION_HANDLE_PTR phSession); + CK_RV (*C_CloseSession)(CK_SESSION_HANDLE hSession); + CK_RV (*C_CloseAllSessions)(CK_SLOT_ID slotID); + CK_RV (*C_GetSessionInfo)(CK_SESSION_HANDLE hSession, + CK_SESSION_INFO_PTR pInfo); + CK_RV (*C_GetOperationState)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG_PTR pulOperationStateLen); + CK_RV (*C_SetOperationState)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG ulOperationStateLen, + CK_OBJECT_HANDLE hEncryptionKey, + CK_OBJECT_HANDLE hAuthenticationKey); + CK_RV (*C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, + CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen); + CK_RV (*C_Logout)(CK_SESSION_HANDLE hSession); + CK_RV (*C_CreateObject)(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phObject); + CK_RV (*C_CopyObject)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phNewObject); + CK_RV (*C_DestroyObject)(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject); + CK_RV (*C_GetObjectSize)(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize); + CK_RV (*C_GetAttributeValue)(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); + CK_RV (*C_SetAttributeValue)(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); + CK_RV (*C_FindObjectsInit)(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); + CK_RV (*C_FindObjects)(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE_PTR phObject, + CK_ULONG ulMaxObjectCount, + CK_ULONG_PTR pulObjectCount); + CK_RV (*C_FindObjectsFinal)(CK_SESSION_HANDLE hSession); + CK_RV (*C_EncryptInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + CK_RV (*C_Encrypt)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, + CK_ULONG_PTR pulEncryptedDataLen); + CK_RV (*C_EncryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen); + CK_RV (*C_EncryptFinal)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pLastEncryptedPart, + CK_ULONG_PTR pulLastEncryptedPartLen); + CK_RV (*C_DecryptInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + CK_RV (*C_Decrypt)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, + CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, + CK_ULONG_PTR pulDataLen); + CK_RV (*C_DecryptUpdate)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen); + CK_RV (*C_DecryptFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, + CK_ULONG_PTR pulLastPartLen); + CK_RV (*C_DigestInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism); + CK_RV (*C_Digest)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, + CK_ULONG_PTR pulDigestLen); + CK_RV (*C_DigestUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen); + CK_RV (*C_DigestKey)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey); + CK_RV (*C_DigestFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, + CK_ULONG_PTR pulDigestLen); + CK_RV (*C_SignInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_Sign)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen); + CK_RV (*C_SignUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen); + CK_RV (*C_SignFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen); + CK_RV (*C_SignRecoverInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_SignRecover)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen); + CK_RV (*C_VerifyInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + CK_RV (*C_Verify)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen); + CK_RV (*C_VerifyUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen); + CK_RV (*C_VerifyFinal)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); + CK_RV (*C_VerifyRecoverInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_VerifyRecover)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen); + CK_RV (*C_DigestEncryptUpdate)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen); + CK_RV (*C_DecryptDigestUpdate)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); + CK_RV (*C_SignEncryptUpdate)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen); + CK_RV (*C_DecryptVerifyUpdate)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); + CK_RV (*C_GenerateKey)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phKey); + CK_RV (*C_GenerateKeyPair)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPublicKey, + CK_OBJECT_HANDLE_PTR phPrivateKey); + CK_RV (*C_WrapKey)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, + CK_BYTE_PTR pWrappedKey, + CK_ULONG_PTR pulWrappedKeyLen); + CK_RV (*C_UnwrapKey)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hUnwrappingKey, + CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_OBJECT_HANDLE_PTR phKey); + CK_RV (*C_DeriveKey)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hBaseKey, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_OBJECT_HANDLE_PTR phKey); + CK_RV (*C_SeedRandom)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, + CK_ULONG ulSeedLen); + CK_RV (*C_GenerateRandom)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen); + CK_RV (*C_GetFunctionStatus)(CK_SESSION_HANDLE hSession); + CK_RV (*C_CancelFunction)(CK_SESSION_HANDLE hSession); + CK_RV (*C_WaitForSlotEvent)(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, + CK_VOID_PTR pReserved); + /* PKCS#11 V 3.0 functions */ + CK_RV (*C_GetInterfaceList)(CK_INTERFACE_PTR pInterfacesList, + CK_ULONG_PTR pulCount); + CK_RV (*C_GetInterface)(CK_UTF8CHAR_PTR pInterfaceName, + CK_VERSION_PTR pVersion, + CK_INTERFACE_PTR_PTR ppInterface, + CK_FLAGS flags); + CK_RV (*C_LoginUser)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, + CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, + CK_UTF8CHAR_PTR pUsername, CK_ULONG ulUsernameLen); + CK_RV (*C_SessionCancel)(CK_SESSION_HANDLE hSession, CK_FLAGS flags); + CK_RV (*C_MessageEncryptInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_EncryptMessage)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen, CK_BYTE_PTR pPlaintext, + CK_ULONG ulPlaintextLen, CK_BYTE_PTR pCiphertext, + CK_ULONG_PTR pulCiphertextLen); + CK_RV (*C_EncryptMessageBegin)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen); + CK_RV (*C_EncryptMessageNext)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pPlaintextPart, + CK_ULONG ulPlaintextPartLen, CK_BYTE_PTR pCiphertextPart, + CK_ULONG_PTR pulCiphertextPartLen, CK_FLAGS flags); + CK_RV (*C_MessageEncryptFinal)(CK_SESSION_HANDLE hSession); + CK_RV (*C_MessageDecryptInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_DecryptMessage)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen, CK_BYTE_PTR pCiphertext, + CK_ULONG ulCiphertextLen, CK_BYTE_PTR pPlaintext, + CK_ULONG_PTR pulPlaintextLen); + CK_RV (*C_DecryptMessageBegin)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen); + CK_RV (*C_DecryptMessageNext)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pCiphertextPart, + CK_ULONG ulCiphertextPartLen, CK_BYTE_PTR pPlaintextPart, + CK_ULONG_PTR pulPlaintextPartLen, CK_FLAGS flags); + CK_RV (*C_MessageDecryptFinal)(CK_SESSION_HANDLE hSession); + CK_RV (*C_MessageSignInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_SignMessage)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen); + CK_RV (*C_SignMessageBegin)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen); + CK_RV (*C_SignMessageNext)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen); + CK_RV (*C_MessageSignFinal)(CK_SESSION_HANDLE hSession); + CK_RV (*C_MessageVerifyInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_VerifyMessage)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen); + CK_RV (*C_VerifyMessageBegin)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen); + CK_RV (*C_VerifyMessageNext)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen); + CK_RV (*C_MessageVerifyFinal)(CK_SESSION_HANDLE hSession); +}; + +struct CK_FUNCTION_LIST_3_2 { + CK_VERSION version; + + CK_RV (*C_Initialize)(CK_VOID_PTR pInitArgs); + CK_RV (*C_Finalize)(CK_VOID_PTR pReserved); + CK_RV (*C_GetInfo)(CK_INFO_PTR pInfo); + CK_RV (*C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); + CK_RV (*C_GetSlotList)(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, + CK_ULONG_PTR pulCount); + CK_RV (*C_GetSlotInfo)(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo); + CK_RV (*C_GetTokenInfo)(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo); + CK_RV (*C_GetMechanismList)(CK_SLOT_ID slotID, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount); + CK_RV (*C_GetMechanismInfo)(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo); + CK_RV (*C_InitToken)(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, + CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel); + CK_RV (*C_InitPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, + CK_ULONG ulPinLen); + CK_RV (*C_SetPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, + CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, + CK_ULONG ulNewLen); + CK_RV (*C_OpenSession)(CK_SLOT_ID slotID, CK_FLAGS flags, + CK_VOID_PTR pApplication, CK_NOTIFY Notify, + CK_SESSION_HANDLE_PTR phSession); + CK_RV (*C_CloseSession)(CK_SESSION_HANDLE hSession); + CK_RV (*C_CloseAllSessions)(CK_SLOT_ID slotID); + CK_RV (*C_GetSessionInfo)(CK_SESSION_HANDLE hSession, + CK_SESSION_INFO_PTR pInfo); + CK_RV (*C_GetOperationState)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG_PTR pulOperationStateLen); + CK_RV (*C_SetOperationState)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG ulOperationStateLen, + CK_OBJECT_HANDLE hEncryptionKey, + CK_OBJECT_HANDLE hAuthenticationKey); + CK_RV (*C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, + CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen); + CK_RV (*C_Logout)(CK_SESSION_HANDLE hSession); + CK_RV (*C_CreateObject)(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phObject); + CK_RV (*C_CopyObject)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phNewObject); + CK_RV (*C_DestroyObject)(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject); + CK_RV (*C_GetObjectSize)(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize); + CK_RV (*C_GetAttributeValue)(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); + CK_RV (*C_SetAttributeValue)(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); + CK_RV (*C_FindObjectsInit)(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); + CK_RV (*C_FindObjects)(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE_PTR phObject, + CK_ULONG ulMaxObjectCount, + CK_ULONG_PTR pulObjectCount); + CK_RV (*C_FindObjectsFinal)(CK_SESSION_HANDLE hSession); + CK_RV (*C_EncryptInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + CK_RV (*C_Encrypt)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, + CK_ULONG_PTR pulEncryptedDataLen); + CK_RV (*C_EncryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen); + CK_RV (*C_EncryptFinal)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pLastEncryptedPart, + CK_ULONG_PTR pulLastEncryptedPartLen); + CK_RV (*C_DecryptInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + CK_RV (*C_Decrypt)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, + CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, + CK_ULONG_PTR pulDataLen); + CK_RV (*C_DecryptUpdate)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen); + CK_RV (*C_DecryptFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, + CK_ULONG_PTR pulLastPartLen); + CK_RV (*C_DigestInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism); + CK_RV (*C_Digest)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, + CK_ULONG_PTR pulDigestLen); + CK_RV (*C_DigestUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen); + CK_RV (*C_DigestKey)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey); + CK_RV (*C_DigestFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, + CK_ULONG_PTR pulDigestLen); + CK_RV (*C_SignInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_Sign)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen); + CK_RV (*C_SignUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen); + CK_RV (*C_SignFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen); + CK_RV (*C_SignRecoverInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_SignRecover)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen); + CK_RV (*C_VerifyInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + CK_RV (*C_Verify)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen); + CK_RV (*C_VerifyUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen); + CK_RV (*C_VerifyFinal)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); + CK_RV (*C_VerifyRecoverInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_VerifyRecover)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen); + CK_RV (*C_DigestEncryptUpdate)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen); + CK_RV (*C_DecryptDigestUpdate)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); + CK_RV (*C_SignEncryptUpdate)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen); + CK_RV (*C_DecryptVerifyUpdate)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); + CK_RV (*C_GenerateKey)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phKey); + CK_RV (*C_GenerateKeyPair)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPublicKey, + CK_OBJECT_HANDLE_PTR phPrivateKey); + CK_RV (*C_WrapKey)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, + CK_BYTE_PTR pWrappedKey, + CK_ULONG_PTR pulWrappedKeyLen); + CK_RV (*C_UnwrapKey)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hUnwrappingKey, + CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_OBJECT_HANDLE_PTR phKey); + CK_RV (*C_DeriveKey)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hBaseKey, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_OBJECT_HANDLE_PTR phKey); + CK_RV (*C_SeedRandom)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, + CK_ULONG ulSeedLen); + CK_RV (*C_GenerateRandom)(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen); + CK_RV (*C_GetFunctionStatus)(CK_SESSION_HANDLE hSession); + CK_RV (*C_CancelFunction)(CK_SESSION_HANDLE hSession); + CK_RV (*C_WaitForSlotEvent)(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, + CK_VOID_PTR pReserved); + + /* PKCS#11 V 3.0 functions */ + CK_RV (*C_GetInterfaceList)(CK_INTERFACE_PTR pInterfacesList, + CK_ULONG_PTR pulCount); + CK_RV (*C_GetInterface)(CK_UTF8CHAR_PTR pInterfaceName, + CK_VERSION_PTR pVersion, + CK_INTERFACE_PTR_PTR ppInterface, + CK_FLAGS flags); + CK_RV (*C_LoginUser)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, + CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, + CK_UTF8CHAR_PTR pUsername, CK_ULONG ulUsernameLen); + CK_RV (*C_SessionCancel)(CK_SESSION_HANDLE hSession, CK_FLAGS flags); + CK_RV (*C_MessageEncryptInit)(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_EncryptMessage)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen, CK_BYTE_PTR pPlaintext, + CK_ULONG ulPlaintextLen, CK_BYTE_PTR pCiphertext, + CK_ULONG_PTR pulCiphertextLen); + CK_RV (*C_EncryptMessageBegin)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen); + CK_RV (*C_EncryptMessageNext)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pPlaintextPart, + CK_ULONG ulPlaintextPartLen, CK_BYTE_PTR pCiphertextPart, + CK_ULONG_PTR pulCiphertextPartLen, CK_FLAGS flags); + CK_RV (*C_MessageEncryptFinal)(CK_SESSION_HANDLE hSession); + CK_RV (*C_MessageDecryptInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_DecryptMessage)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen, CK_BYTE_PTR pCiphertext, + CK_ULONG ulCiphertextLen, CK_BYTE_PTR pPlaintext, + CK_ULONG_PTR pulPlaintextLen); + CK_RV (*C_DecryptMessageBegin)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen); + CK_RV (*C_DecryptMessageNext)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pCiphertextPart, + CK_ULONG ulCiphertextPartLen, CK_BYTE_PTR pPlaintextPart, + CK_ULONG_PTR pulPlaintextPartLen, CK_FLAGS flags); + CK_RV (*C_MessageDecryptFinal)(CK_SESSION_HANDLE hSession); + CK_RV (*C_MessageSignInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_SignMessage)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen); + CK_RV (*C_SignMessageBegin)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen); + CK_RV (*C_SignMessageNext)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen); + CK_RV (*C_MessageSignFinal)(CK_SESSION_HANDLE hSession); + CK_RV (*C_MessageVerifyInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); + CK_RV (*C_VerifyMessage)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen); + CK_RV (*C_VerifyMessageBegin)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen); + CK_RV (*C_VerifyMessageNext)(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen); + CK_RV (*C_MessageVerifyFinal)(CK_SESSION_HANDLE hSession); + + /* PKCS#11 V 3.2 functions */ + CK_RV (*C_EncapsulateKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hPublicKey, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, + CK_BYTE_PTR pCiphertext, CK_ULONG_PTR pulCiphertextLen); + CK_RV (*C_DecapsulateKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hPrivateKey, CK_BYTE_PTR pCiphertext, + CK_ULONG ulCiphertextLen, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey); + CK_RV (*C_VerifySignatureInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen); + CK_RV (*C_VerifySignature)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, + CK_ULONG ulDataLen); + CK_RV (*C_VerifySignatureUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen); + CK_RV (*C_VerifySignatureFinal)(CK_SESSION_HANDLE hSession); + CK_RV (*C_GetSessionValidationFlags)(CK_SESSION_HANDLE hSession, CK_ULONG type, + CK_FLAGS * pFlags); + CK_RV (*C_AsyncComplete)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName, + CK_ASYNC_DATA_PTR pResult); + CK_RV (*C_AsyncGetID)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName, + CK_ULONG_PTR pulID); + CK_RV (*C_AsyncJoin)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName, + CK_ULONG ulID, CK_BYTE_PTR pData, CK_ULONG ulData); +}; + #ifdef __cplusplus } #endif diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 834d17fa5c..57bd83594d 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -229,6 +229,14 @@ typedef int (*CallbackRsaSignRawDigest)(wc_PKCS7* pkcs7, byte* digest, int devId, int hashOID); #endif +#if defined(HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK) && defined(HAVE_ECC) +/* ECC sign raw digest callback, user signs hash directly */ +typedef int (*CallbackEccSignRawDigest)(wc_PKCS7* pkcs7, byte* digest, + word32 digestSz, byte* out, word32 outSz, + byte* privateKey, word32 privateKeySz, + int devId, int hashOID); +#endif + /* Public Structure Warning: * Existing members must not be changed to maintain backwards compatibility! @@ -376,6 +384,10 @@ struct wc_PKCS7 { CallbackAESKeyWrapUnwrap aesKeyWrapUnwrapCb; +#if defined(HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK) && defined(HAVE_ECC) + CallbackEccSignRawDigest eccSignRawDigestCb; +#endif + /* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */ }; @@ -511,6 +523,11 @@ WOLFSSL_API int wc_PKCS7_SetRsaSignRawDigestCb(wc_PKCS7* pkcs7, CallbackRsaSignRawDigest cb); #endif +#if defined(HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK) && defined(HAVE_ECC) +WOLFSSL_API int wc_PKCS7_SetEccSignRawDigestCb(wc_PKCS7* pkcs7, + CallbackEccSignRawDigest cb); +#endif + /* CMS/PKCS#7 EnvelopedData */ WOLFSSL_API int wc_PKCS7_EncodeEnvelopedData(wc_PKCS7* pkcs7, byte* output, word32 outputSz); diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index a499a95278..49301a4d3a 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -4990,6 +4990,10 @@ extern void uITRON4_free(void *p) ; #error "If TLS is enabled please make sure either client or server is enabled." #endif +#if defined(WC_RNG_BANK_SUPPORT) && defined(NO_ASN_TIME) + #undef WC_RNG_BANK_SUPPORT +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/wolfcrypt/wc_pkcs11.h b/wolfssl/wolfcrypt/wc_pkcs11.h index 803a1a6c05..b4805690c7 100644 --- a/wolfssl/wolfcrypt/wc_pkcs11.h +++ b/wolfssl/wolfcrypt/wc_pkcs11.h @@ -37,13 +37,21 @@ extern "C" { #endif +enum Pkcs11InterfaceVersionType { + WC_PCKS11VERSION_2_20, + WC_PCKS11VERSION_2_40, + WC_PCKS11VERSION_3_0, + WC_PCKS11VERSION_3_1, + WC_PCKS11VERSION_3_2, +}; typedef struct Pkcs11Dev { -#ifndef HAVE_PKCS11_STATIC +#if !defined(HAVE_PKCS11_STATIC) && !defined(HAVE_PKCS11_V3_STATIC) void* dlHandle; /* Handle to library */ #endif CK_FUNCTION_LIST* func; /* Array of functions */ void* heap; + int version; /* Pkcs11InterfaceVersionType */ } Pkcs11Dev; typedef struct Pkcs11Token { @@ -53,12 +61,14 @@ typedef struct Pkcs11Token { CK_UTF8CHAR_PTR userPin; /* User's PIN to login with */ CK_ULONG userPinSz; /* Size of user's PIN in bytes */ byte userPinLogin:1; /* Login with User's PIN */ + int version; /* Pkcs11InterfaceVersionType */ } Pkcs11Token; typedef struct Pkcs11Session { CK_FUNCTION_LIST* func; /* Table of PKCS#11 function from lib */ CK_SLOT_ID slotId; /* Id of slot to use */ CK_SESSION_HANDLE handle; /* Handle to active session */ + int version; /* Pkcs11InterfaceVersionType */ } Pkcs11Session; /* Types of keys that can be stored. */ @@ -74,6 +84,8 @@ WOLFSSL_API int wc_Pkcs11_Initialize(Pkcs11Dev* dev, const char* library, void* heap); WOLFSSL_API int wc_Pkcs11_Initialize_ex(Pkcs11Dev* dev, const char* library, void* heap, CK_RV* rvp); +WOLFSSL_API int wc_Pkcs11_Initialize_v3(Pkcs11Dev* dev, const char* library, + void* heap, int* version, const char* interfaceName, CK_RV* rvp); WOLFSSL_API void wc_Pkcs11_Finalize(Pkcs11Dev* dev); WOLFSSL_API int wc_Pkcs11Token_Init(Pkcs11Token* token, Pkcs11Dev* dev, diff --git a/wrapper/rust/Makefile b/wrapper/rust/Makefile index 73bd658e5a..dec76d4b05 100644 --- a/wrapper/rust/Makefile +++ b/wrapper/rust/Makefile @@ -6,6 +6,10 @@ all: test: +$(MAKE) -C wolfssl-wolfcrypt test +.PHONY: testfips +testfips: + +$(MAKE) -C wolfssl-wolfcrypt testfips + .PHONY: clean clean: +$(MAKE) -C wolfssl-wolfcrypt clean diff --git a/wrapper/rust/wolfssl-wolfcrypt/Makefile b/wrapper/rust/wolfssl-wolfcrypt/Makefile index 3944a1971b..7cda418962 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/Makefile +++ b/wrapper/rust/wolfssl-wolfcrypt/Makefile @@ -6,7 +6,11 @@ all: .PHONY: test test: - cargo test + cargo test -- --test-threads=1 + +.PHONY: testfips +testfips: + cargo test --lib --bins --tests -- --test-threads=1 .PHONY: clean clean: diff --git a/wrapper/rust/wolfssl-wolfcrypt/build.rs b/wrapper/rust/wolfssl-wolfcrypt/build.rs index 608c100e27..9580b1608b 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/build.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/build.rs @@ -19,6 +19,7 @@ fn main() { /// Returns `Ok(())` if successful, or an error if any step fails. fn run_build() -> Result<()> { generate_bindings()?; + generate_fips_aliases()?; setup_wolfssl_link()?; scan_cfg()?; Ok(()) @@ -64,6 +65,79 @@ fn generate_bindings() -> Result<()> { }) } +/// Generate FIPS symbol aliases. +/// +/// Since Rust can't use fips.h's #defines which map the "regular" wc function +/// name to the _fips variant, and since bindgen has only seen the _fips +/// variant, we will generate aliases that allow the non-_fips variant function +/// name to be called without the _fips prefix by Rust sources in a manner +/// similar to which C sources would be able to call the non-_fips variant +/// function name. +/// +/// Returns `Ok(())` if successful, or an error if generation fails. +fn generate_fips_aliases() -> Result<()> { + let binding = read_file(bindings_path())?; + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let aliases_path = out_dir.join("fips_aliases.rs"); + + let mut aliases = String::new(); + + // Find all _fips symbol names + let fips_sym_re = Regex::new(r"pub fn (wc_\w+)_fips\s*\(").unwrap(); + + for cap in fips_sym_re.captures_iter(&binding) { + let mut base_name = &cap[1]; + let fips_name = format!("{}_fips", base_name); + + // Exception mappings: (standard_name, fips_name) + // For cases where FIPS name doesn't follow the simple _fips pattern + let exceptions: &[(&str, &str)] = &[ + // _ex suffix changed to Ex before _fips + ("wc_InitRsaKey_ex", "wc_InitRsaKeyEx_fips"), + ("wc_RsaPublicEncrypt_ex", "wc_RsaPublicEncryptEx_fips"), + ("wc_RsaPrivateDecryptInline_ex", "wc_RsaPrivateDecryptInlineEx_fips"), + ("wc_RsaPrivateDecrypt_ex", "wc_RsaPrivateDecryptEx_fips"), + ("wc_RsaPSS_Sign_ex", "wc_RsaPSS_SignEx_fips"), + ("wc_RsaPSS_VerifyInline_ex", "wc_RsaPSS_VerifyInlineEx_fips"), + ("wc_RsaPSS_Verify_ex", "wc_RsaPSS_VerifyEx_fips"), + ("wc_RsaPSS_CheckPadding_ex", "wc_RsaPSS_CheckPaddingEx_fips"), + ("wc_DhSetKey_ex", "wc_DhSetKeyEx_fips"), + ("wc_DhCheckPubKey_ex", "wc_DhCheckPubKeyEx_fips"), + ("wc_DhCheckPrivKey_ex", "wc_DhCheckPrivKeyEx_fips"), + + // Name change + ("wc_PRF_TLS", "wc_PRF_TLSv12_fips"), + ]; + + // Handle exceptions + for (exc_base_name, exc_fips_name) in exceptions { + if fips_name == *exc_fips_name { + base_name = exc_base_name; + break; + } + } + + // Check if the non-_fips version exists in bindings + let non_fips_pattern = format!(r"pub fn {}\s*\(", regex::escape(base_name)); + let non_fips_re = Regex::new(&non_fips_pattern).unwrap(); + + if non_fips_re.is_match(&binding) { + // Add any new known names defined with both a _fips suffix and not + // here. Warn if any new ones are discovered. + if base_name != "wc_AesGcmEncrypt" { + println!("cargo:warning=Skipping FIPS symbols alias for {}", base_name); + } + } else { + // Only alias if the base name doesn't already exist + aliases.push_str(&format!("pub use {} as {};\n", fips_name, base_name)); + } + } + + fs::write(&aliases_path, aliases)?; + + Ok(()) +} + /// Instruct cargo to link against wolfssl C library /// /// Returns `Ok(())` if successful, or an error if any step fails. @@ -93,7 +167,7 @@ fn read_file(path: String) -> Result { } fn check_cfg(binding: &str, function_name: &str, cfg_name: &str) { - let pattern = format!(r"\b{}\b", function_name); + let pattern = format!(r"\b{}(_fips)?\b", function_name); let re = match Regex::new(&pattern) { Ok(r) => r, Err(e) => { @@ -181,6 +255,9 @@ fn scan_cfg() -> Result<()> { check_cfg(&binding, "wc_ed448_verify_msg_ex", "ed448_verify"); check_cfg(&binding, "wc_ed448_verify_msg_init", "ed448_streaming_verify"); + /* fips */ + check_cfg(&binding, "wc_SetSeed_Cb_fips", "fips"); + /* hkdf */ check_cfg(&binding, "wc_HKDF_Extract_ex", "hkdf"); @@ -213,6 +290,8 @@ fn scan_cfg() -> Result<()> { check_cfg(&binding, "wc_InitSha256", "sha256"); check_cfg(&binding, "wc_InitSha384", "sha384"); check_cfg(&binding, "wc_InitSha512", "sha512"); + check_cfg(&binding, "wc_HashType_WC_HASH_TYPE_SHA512_224", "sha512_224"); + check_cfg(&binding, "wc_HashType_WC_HASH_TYPE_SHA512_256", "sha512_256"); check_cfg(&binding, "wc_InitSha3_224", "sha3"); check_cfg(&binding, "wc_InitShake128", "shake128"); check_cfg(&binding, "wc_InitShake256", "shake256"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs b/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs index a6c35c493a..2965cca3ae 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs @@ -711,7 +711,7 @@ impl ECC { } let mut wc_ecc_key = unsafe { wc_ecc_key.assume_init() }; let priv_size = priv_buf.len() as u32; - let pub_ptr = if pub_buf.len() == 0 {core::ptr::null()} else {pub_buf.as_ptr()}; + let pub_ptr = if pub_buf.is_empty() {core::ptr::null()} else {pub_buf.as_ptr()}; let pub_size = pub_buf.len() as u32; let rc = unsafe { sys::wc_ecc_import_private_key(priv_buf.as_ptr(), priv_size, @@ -785,7 +785,7 @@ impl ECC { } let mut wc_ecc_key = unsafe { wc_ecc_key.assume_init() }; let priv_size = priv_buf.len() as u32; - let pub_ptr = if pub_buf.len() == 0 {core::ptr::null()} else {pub_buf.as_ptr()}; + let pub_ptr = if pub_buf.is_empty() {core::ptr::null()} else {pub_buf.as_ptr()}; let pub_size = pub_buf.len() as u32; let rc = unsafe { sys::wc_ecc_import_private_key_ex(priv_buf.as_ptr(), priv_size, diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/fips.rs b/wrapper/rust/wolfssl-wolfcrypt/src/fips.rs new file mode 100644 index 0000000000..b77b93f5c3 --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/src/fips.rs @@ -0,0 +1,34 @@ +#![cfg(fips)] + +use crate::sys; + +/// Enables or disables the ability to read private key data in FIPS mode. +/// +/// In FIPS mode, private keys are protected and cannot be read by default. +/// This function allows temporarily enabling private key reads for operations +/// that require access to the raw key material, such as key export or backup. +/// +/// # Arguments +/// +/// * `enabled` - Set to `1` to enable private key reads, or `0` to disable. +/// +/// # Returns +/// +/// * `Ok(())` - The operation succeeded. +/// * `Err(i32)` - The operation failed, returning the wolfSSL error code. +/// +/// # Note +/// +/// This function applies to all key types (`WC_KEYTYPE_ALL`). Private key +/// reading should be disabled again after the required operation is complete +/// to maintain FIPS compliance. +pub fn set_private_key_read_enable(enabled: i32) -> Result<(), i32> { + let rc = unsafe { + sys::wolfCrypt_SetPrivateKeyReadEnable_fips(enabled, sys::wc_KeyType_WC_KEYTYPE_ALL) + }; + if rc != 0 { + Err(rc) + } else { + Ok(()) + } +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs b/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs index 5c93c200c2..31505aa647 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs @@ -38,7 +38,9 @@ impl HMAC { pub const TYPE_SHA: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA as i32; pub const TYPE_SHA256: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA256 as i32; pub const TYPE_SHA512: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA512 as i32; + #[cfg(sha512_224)] pub const TYPE_SHA512_224: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA512_224 as i32; + #[cfg(sha512_256)] pub const TYPE_SHA512_256: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA512_256 as i32; pub const TYPE_SHA384: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA384 as i32; pub const TYPE_SHA224: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA224 as i32; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs index dfeef39b7f..b3f35822fd 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs @@ -30,6 +30,7 @@ pub mod dh; pub mod ecc; pub mod ed25519; pub mod ed448; +pub mod fips; pub mod hkdf; pub mod hmac; pub mod kdf; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/random.rs b/wrapper/rust/wolfssl-wolfcrypt/src/random.rs index 9e12a5f376..d577cb7ffb 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/random.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/random.rs @@ -87,6 +87,15 @@ impl RNG { /// A Result which is Ok(RNG) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new_ex(heap: Option<*mut std::os::raw::c_void>, dev_id: Option) -> Result { + #[cfg(fips)] + { + let rc = unsafe { + sys::wc_SetSeed_Cb_fips(Some(sys::wc_GenerateSeed)) + }; + if rc != 0 { + return Err(rc); + } + } let mut rng: MaybeUninit = MaybeUninit::uninit(); let heap = match heap { Some(heap) => heap, @@ -137,6 +146,15 @@ impl RNG { /// A Result which is Ok(RNG) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new_with_nonce_ex(nonce: &mut [T], heap: Option<*mut std::os::raw::c_void>, dev_id: Option) -> Result { + #[cfg(fips)] + { + let rc = unsafe { + sys::wc_SetSeed_Cb_fips(Some(sys::wc_GenerateSeed)) + }; + if rc != 0 { + return Err(rc); + } + } let ptr = nonce.as_mut_ptr() as *mut u8; let size: u32 = size_of_val(nonce) as u32; let mut rng: MaybeUninit = MaybeUninit::uninit(); diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs index 8b8d44f3f6..d1a2c17d37 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs @@ -100,7 +100,9 @@ impl RSA { pub const HASH_TYPE_SHA3_512 : u32 = sys::wc_HashType_WC_HASH_TYPE_SHA3_512; pub const HASH_TYPE_BLAKE2B : u32 = sys::wc_HashType_WC_HASH_TYPE_BLAKE2B; pub const HASH_TYPE_BLAKE2S : u32 = sys::wc_HashType_WC_HASH_TYPE_BLAKE2S; + #[cfg(sha512_224)] pub const HASH_TYPE_SHA512_224 : u32 = sys::wc_HashType_WC_HASH_TYPE_SHA512_224; + #[cfg(sha512_256)] pub const HASH_TYPE_SHA512_256 : u32 = sys::wc_HashType_WC_HASH_TYPE_SHA512_256; #[cfg(shake128)] pub const HASH_TYPE_SHAKE128 : u32 = sys::wc_HashType_WC_HASH_TYPE_SHAKE128; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/sys.rs b/wrapper/rust/wolfssl-wolfcrypt/src/sys.rs index 3ab98816b7..5b90a342f9 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/sys.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/sys.rs @@ -14,3 +14,6 @@ #![allow(unnecessary_transmutes)] #![allow(unsafe_op_in_unsafe_fn)] include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + +/* Include generated FIPS symbol aliases. */ +include!(concat!(env!("OUT_DIR"), "/fips_aliases.rs")); diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/common/mod.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/common/mod.rs new file mode 100644 index 0000000000..8d191ed97b --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/common/mod.rs @@ -0,0 +1,12 @@ +#[cfg(fips)] +fn setup_fips() +{ + use wolfssl_wolfcrypt::fips; + fips::set_private_key_read_enable(1).expect("Error with set_private_key_read_enable()"); +} + +pub fn setup() +{ + #[cfg(fips)] + setup_fips(); +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs index 7cd15f3670..522a875cc2 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs @@ -780,41 +780,39 @@ fn test_xts_consecutive_sectors() { #[cfg(aes_xts_stream)] fn test_xtsstream() { let keys: [u8; 32] = [ - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x39, 0x25, 0x79, 0x05, 0xdf, 0xcc, 0x77, 0x76, + 0x6c, 0x87, 0x0a, 0x80, 0x6a, 0x60, 0xe3, 0xc0, + 0x93, 0xd1, 0x2a, 0xcf, 0xcb, 0x51, 0x42, 0xfa, + 0x09, 0x69, 0x89, 0x62, 0x5b, 0x60, 0xdb, 0x16 ]; let tweak: [u8; 16] = [ - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x5c, 0xf7, 0x9d, 0xb6, 0xc5, 0xcd, 0x99, 0x1a, + 0x1c, 0x78, 0x81, 0x42, 0x24, 0x95, 0x1e, 0x84 ]; - let plain: [u8; 40] = [ - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0xff, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 + let plain: [u8; 32] = [ + 0xbd, 0xc5, 0x46, 0x8f, 0xbc, 0x8d, 0x50, 0xa1, + 0x0d, 0x1c, 0x85, 0x7f, 0x79, 0x1c, 0x5c, 0xba, + 0xb3, 0x81, 0x0d, 0x0d, 0x73, 0xcf, 0x8f, 0x20, + 0x46, 0xb1, 0xd1, 0x9e, 0x7d, 0x5d, 0x8a, 0x56 ]; - let expected_cipher: [u8; 40] = [ - 0xA2, 0x07, 0x47, 0x76, 0x3F, 0xEC, 0x0C, 0x23, - 0x1B, 0xD0, 0xBD, 0x46, 0x9A, 0x27, 0x38, 0x12, - 0x95, 0x02, 0x3D, 0x5D, 0xC6, 0x94, 0x51, 0x36, - 0xA0, 0x85, 0xD2, 0x69, 0x6E, 0x87, 0x0A, 0xBF, - 0xB5, 0x5A, 0xDD, 0xCB, 0x80, 0xE0, 0xFC, 0xCD + let expected_cipher: [u8; 32] = [ + 0xd6, 0xbe, 0x04, 0x6d, 0x41, 0xf2, 0x3b, 0x5e, + 0xd7, 0x0b, 0x6b, 0x3d, 0x5c, 0x8e, 0x66, 0x23, + 0x2b, 0xe6, 0xb8, 0x07, 0xd4, 0xdc, 0xc6, 0x0e, + 0xff, 0x8d, 0xbc, 0x1d, 0x9f, 0x7f, 0xc8, 0x22 ]; let mut xtsstream = XTSStream::new().expect("Failed to create XTSStream"); xtsstream.init_encrypt(&keys, &tweak).expect("Error with init_encrypt()"); - let mut cipher: [u8; 40] = [0; 40]; + let mut cipher: [u8; 32] = [0; 32]; xtsstream.encrypt_update(&plain[0..16], &mut cipher[0..16]).expect("Error with encrypt_update()"); - xtsstream.encrypt_final(&plain[16..40], &mut cipher[16..40]).expect("Error with encrypt_final()"); + xtsstream.encrypt_final(&plain[16..32], &mut cipher[16..32]).expect("Error with encrypt_final()"); assert_eq!(cipher, expected_cipher); xtsstream.init_decrypt(&keys, &tweak).expect("Error with init_decrypt()"); - let mut plain_out: [u8; 40] = [0; 40]; + let mut plain_out: [u8; 32] = [0; 32]; xtsstream.decrypt_update(&cipher[0..16], &mut plain_out[0..16]).expect("Error with decrypt_update()"); - xtsstream.decrypt_final(&cipher[16..40], &mut plain_out[16..40]).expect("Error with decrypt_final()"); + xtsstream.decrypt_final(&cipher[16..32], &mut plain_out[16..32]).expect("Error with decrypt_final()"); assert_eq!(plain_out, plain); } diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_dh.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_dh.rs index 99094e658b..1135954e32 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_dh.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_dh.rs @@ -1,5 +1,7 @@ #![cfg(dh)] +mod common; + #[cfg(any(all(dh_keygen, dh_ffdhe_2048), random))] use wolfssl_wolfcrypt::dh::DH; #[cfg(random)] @@ -31,6 +33,7 @@ fn test_dh_named_parameters() { #[test] #[cfg(all(dh_keygen, random))] fn test_generate_params() { + common::setup(); let mut rng = RNG::new().expect("Error with RNG::new()"); let mut dh = DH::generate(&mut rng, 2048).expect("Error with generate()"); @@ -75,6 +78,7 @@ fn test_generate_key_pair() { #[test] #[cfg(random)] fn test_dh_checks() { + common::setup(); let p = [ 0xc5u8, 0x7c, 0xa2, 0x4f, 0x4b, 0xd6, 0x8c, 0x3c, 0xda, 0xc7, 0xba, 0xaa, 0xea, 0x2e, 0x5c, 0x1e, diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ecc.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ecc.rs index c828ab0540..82f5369fbe 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ecc.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ecc.rs @@ -1,5 +1,7 @@ #![cfg(ecc)] +mod common; + #[cfg(any(all(ecc_import, ecc_export, ecc_sign, ecc_verify, random), random))] use std::fs; use wolfssl_wolfcrypt::ecc::*; @@ -128,6 +130,8 @@ fn test_ecc_import_export_sign_verify() { #[test] #[cfg(all(ecc_dh, random))] fn test_ecc_shared_secret() { + common::setup(); + let mut rng = RNG::new().expect("Failed to create RNG"); let mut ecc0 = ECC::generate(32, &mut rng, None, None).expect("Error with generate()"); let mut ecc1 = ECC::generate(32, &mut rng, None, None).expect("Error with generate()"); @@ -152,6 +156,8 @@ fn test_ecc_shared_secret() { #[test] #[cfg(all(ecc_export, random))] fn test_ecc_export() { + common::setup(); + let mut rng = RNG::new().expect("Failed to create RNG"); let mut ecc = ECC::generate(32, &mut rng, None, None).expect("Error with generate()"); let mut qx = [0u8; 32]; @@ -166,6 +172,8 @@ fn test_ecc_export() { #[test] #[cfg(all(ecc_export, random))] fn test_ecc_export_ex() { + common::setup(); + let mut rng = RNG::new().expect("Failed to create RNG"); let mut ecc = ECC::generate(32, &mut rng, None, None).expect("Error with generate()"); let mut qx = [0u8; 32]; @@ -180,6 +188,8 @@ fn test_ecc_export_ex() { #[test] #[cfg(all(ecc_import, ecc_export, ecc_sign, ecc_verify, random))] fn test_ecc_import_export_private() { + common::setup(); + let mut rng = RNG::new().expect("Failed to create RNG"); let mut ecc = ECC::generate(32, &mut rng, None, None).expect("Error with generate()"); let hash = [0x42u8; 32]; @@ -204,6 +214,8 @@ fn test_ecc_import_export_private() { #[test] #[cfg(all(ecc_import, ecc_export, ecc_sign, ecc_verify, random))] fn test_ecc_import_export_private_ex() { + common::setup(); + let mut rng = RNG::new().expect("Failed to create RNG"); let curve_id = ECC::SECP256R1; let curve_size = ECC::get_curve_size_from_id(curve_id).expect("Error with get_curve_size_from_id()"); @@ -242,6 +254,8 @@ fn test_ecc_export_public() { #[test] #[cfg(all(ecc_import, ecc_export, ecc_sign, ecc_verify, random))] fn test_ecc_import_unsigned() { + common::setup(); + let mut rng = RNG::new().expect("Failed to create RNG"); let curve_id = ECC::SECP256R1; let curve_size = ECC::get_curve_size_from_id(curve_id).expect("Error with get_curve_size_from_id()"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed25519.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed25519.rs index a61f132e0f..8c7e225c28 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed25519.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed25519.rs @@ -1,11 +1,15 @@ #![cfg(ed25519)] +mod common; + use wolfssl_wolfcrypt::random::RNG; use wolfssl_wolfcrypt::ed25519::*; #[test] #[cfg(all(ed25519_import, ed25519_export))] fn test_make_public() { + common::setup(); + let mut rng = RNG::new().expect("Error creating RNG"); let ed = Ed25519::generate(&mut rng).expect("Error with generate()"); let mut private = [0u8; Ed25519::KEY_SIZE]; @@ -210,6 +214,8 @@ fn test_ph_sign_verify() { #[test] #[cfg(all(ed25519_import, ed25519_export))] fn test_import_export() { + common::setup(); + let mut rng = RNG::new().expect("Error creating RNG"); let ed = Ed25519::generate(&mut rng).expect("Error with generate()"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed448.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed448.rs index 2bd5582fc5..d0f7186f12 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed448.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed448.rs @@ -1,11 +1,15 @@ #![cfg(ed448)] +mod common; + use wolfssl_wolfcrypt::random::RNG; use wolfssl_wolfcrypt::ed448::*; #[test] #[cfg(all(ed448_import, ed448_export))] fn test_make_public() { + common::setup(); + let mut rng = RNG::new().expect("Error creating RNG"); let ed = Ed448::generate(&mut rng).expect("Error with generate()"); let mut private = [0u8; Ed448::KEY_SIZE]; @@ -214,6 +218,8 @@ fn test_ph_sign_verify() { #[test] #[cfg(all(ed448_import, ed448_export))] fn test_import_export() { + common::setup(); + let mut rng = RNG::new().expect("Error creating RNG"); let ed = Ed448::generate(&mut rng).expect("Error with generate()"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_hkdf.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_hkdf.rs index 44b25580d0..e2b1e340c4 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_hkdf.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_hkdf.rs @@ -1,11 +1,15 @@ #![cfg(hkdf)] +mod common; + use wolfssl_wolfcrypt::hkdf::*; use wolfssl_wolfcrypt::hmac::HMAC; use wolfssl_wolfcrypt::sha::SHA256; #[test] fn test_hkdf_extract_expand() { + common::setup(); + let ikm = b"MyPassword0"; let salt = b"12345678ABCDEFGH"; let mut extract_out = [0u8; SHA256::DIGEST_SIZE]; @@ -26,6 +30,8 @@ fn test_hkdf_extract_expand() { #[test] fn test_hkdf_one_shot() { + common::setup(); + let ikm = b"MyPassword0"; let salt = b"12345678ABCDEFGH"; let info = b"0"; diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_kdf.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_kdf.rs index e540a5244a..a91edc1eee 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_kdf.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_kdf.rs @@ -1,5 +1,7 @@ #![cfg(any(kdf_srtp, all(hmac, any(kdf_pbkdf2, kdf_ssh, kdf_tls13))))] +mod common; + #[cfg(all(hmac, any(kdf_pbkdf2, kdf_tls13)))] use wolfssl_wolfcrypt::hmac::HMAC; use wolfssl_wolfcrypt::kdf::*; @@ -9,6 +11,8 @@ use wolfssl_wolfcrypt::sha::SHA256; #[test] #[cfg(all(hmac, kdf_pbkdf2))] fn test_pbkdf2() { + common::setup(); + let password = b"passwordpassword"; let salt = [0x78u8, 0x57, 0x8E, 0x5a, 0x5d, 0x63, 0xcb, 0x06]; let iterations = 2048; @@ -50,6 +54,8 @@ fn test_pkcs12_pbkdf() { #[test] #[cfg(all(hmac, kdf_tls13))] fn test_tls13_hkdf_extract_expand() { + common::setup(); + let hash_hello1 = [ 0x63u8, 0x83, 0x58, 0xab, 0x36, 0xcd, 0x0c, 0xf3, 0x26, 0x07, 0xb5, 0x5f, 0x0b, 0x8b, 0x45, 0xd6, @@ -84,6 +90,8 @@ fn test_tls13_hkdf_extract_expand() { #[test] #[cfg(all(hmac, kdf_ssh))] fn test_ssh_kdf() { + common::setup(); + let ssh_kdf_set3_k = [ 0x6Au8, 0xC3, 0x82, 0xEA, 0xAC, 0xA0, 0x93, 0xE1, 0x25, 0xE2, 0x5C, 0x24, 0xBE, 0xBC, 0x84, 0x64, @@ -146,6 +154,8 @@ fn test_ssh_kdf() { #[test] #[cfg(kdf_srtp)] fn test_srtp_kdf() { + common::setup(); + let key = [ 0xc4u8, 0x80, 0x9f, 0x6d, 0x36, 0x98, 0x88, 0x72, 0x8e, 0x26, 0xad, 0xb5, 0x32, 0x12, 0x98, 0x90 @@ -194,6 +204,8 @@ fn test_srtp_kdf() { #[test] #[cfg(kdf_srtp)] fn test_srtcp_kdf() { + common::setup(); + let key = [ 0xc4u8, 0x80, 0x9f, 0x6d, 0x36, 0x98, 0x88, 0x72, 0x8e, 0x26, 0xad, 0xb5, 0x32, 0x12, 0x98, 0x90 diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_prf.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_prf.rs index 511a8a07ef..9bbbc78d9e 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_prf.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_prf.rs @@ -1,9 +1,13 @@ #![cfg(all(prf, sha384))] +mod common; + use wolfssl_wolfcrypt::prf::*; #[test] fn test_prf() { + common::setup(); + let secret = [0x10u8, 0xbc, 0xb4, 0xa2, 0xe8, 0xdc, 0xf1, 0x9b, 0x4c, 0x51, 0x9c, 0xed, 0x31, 0x1b, 0x51, 0x57, 0x02, 0x3f, 0xa1, 0x7d, 0xfb, 0x0e, 0xf3, 0x4e, 0x8f, 0x6f, 0x71, diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa.rs index 7ab9aaf9ab..b8d19cfaec 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa.rs @@ -1,5 +1,7 @@ #![cfg(rsa)] +mod common; + #[cfg(any(all(sha256, random, rsa_pss), random, rsa_direct))] use std::fs; #[cfg(random)] @@ -10,6 +12,8 @@ use wolfssl_wolfcrypt::rsa::*; #[test] #[cfg(rsa_keygen)] fn test_rsa_generate() { + common::setup(); + let mut rng = RNG::new().expect("Error creating RNG"); let mut rsa = RSA::generate(2048, 65537, &mut rng).expect("Error with generate()"); rsa.check().expect("Error with check()");