wolfSSL / wolfssl

The wolfSSL library is a small, fast, portable implementation of TLS/SSL for embedded devices to the cloud. wolfSSL supports up to TLS 1.3 and DTLS 1.3!
https://www.wolfssl.com
GNU General Public License v2.0
2.22k stars 798 forks source link

[Bug]: src/ssl.c:ProcessBuffer() different/broken behavior for same private key depending on PEM or ASN1 format #7668

Open gstrauss opened 2 weeks ago

gstrauss commented 2 weeks ago

Contact Details

No response

Version

v5.7.0-stable

Description

src/ssl.c:ProcessBuffer() fails if dilithium_level5_entity_key.pem is parsed by application into DER and passed to wolfSSL_CTX_use_PrivateKey_buffer() with format WOLFSSL_FILETYPE_ASN1, but works if the PEM buffer is passed to wolfSSL_CTX_use_PrivateKey_buffer() with format WOLFSSL_FILETYPE_PEM

Separate bug: wolfSSL crashes with SIGSEGV if the above private key (incorrectly) is passed as PEM buffer to wolfSSL_CTX_use_PrivateKey_buffer() with format WOLFSSL_FILETYPE_ASN1. Note the mismatched format. Still, wolfSSL should not crash, as the buffer and buffer length are parameters.

Reproduction steps

Ask @anhu for instructions for Post-Quantum Algorithms in cURL using lighttpd and wolfssl (and please give him feedback if the demo could be simpler)

Alternatively, generate dilithium_level5_entity_key.pem using oqs/generate_dilithium_chains.sh from wolfSSL osp repo. https://github.com/wolfSSL/osp

Read the file into memory and pass to wolfSSL_CTX_use_PrivateKey_buffer(). Then, parse the PEM into DER and call wolfSSL_CTX_use_PrivateKey_buffer().

Relevant log output

More details in https://wolfssl.zendesk.com/hc/requests/18173
anhu commented 1 day ago

Hi,

I built with the following configuration: $ ./configure --enable-experimental --with-liboqs CFLAGS=-DNO_FILESYSTEM

I then made the following quick and temporary changes:

diff --git examples/server/server.c examples/server/server.c
index cca853a14..b65e75434 100644
--- examples/server/server.c
+++ examples/server/server.c
@@ -2720,8 +2720,14 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
     #endif /* HAVE_PK_CALLBACKS && TEST_PK_PRIVKEY */
     ) {
     #ifdef NO_FILESYSTEM
-        if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, server_key_der_2048,
-            sizeof_server_key_der_2048, SSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS)
+
+byte dilithium_buffer[8000];
+int dilithium_sz;
+FILE * f = fopen("/path/to/wolfssl-examples/certs/mldsa87_server_key.der", "r");
+dilithium_sz = fread(dilithium_buffer, 1, 8000, f);
+fclose(f);
+        if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, dilithium_buffer,
+            dilithium_sz, SSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS)
             err_sys_ex(catastrophic, "can't load server private key buffer");
     #elif !defined(TEST_LOAD_BUFFER)
         if (SSL_CTX_use_PrivateKey_file(ctx, ourKey, WOLFSSL_FILETYPE_PEM)

I ran examples/server/server and no error occurred.

I then use this change:

diff --git examples/server/server.c examples/server/server.c
index cca853a14..ae3246c39 100644
--- examples/server/server.c
+++ examples/server/server.c
@@ -2720,8 +2720,14 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
     #endif /* HAVE_PK_CALLBACKS && TEST_PK_PRIVKEY */
     ) {
     #ifdef NO_FILESYSTEM
-        if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, server_key_der_2048,
-            sizeof_server_key_der_2048, SSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS)
+
+byte dilithium_buffer[8000];
+int dilithium_sz;
+FILE * f = fopen("/path/to/wolfssl-examples/certs/mldsa87_server_key.der", "r");
+dilithium_sz = fread(dilithium_buffer, 1, 8000, f);
+fclose(f);
+        if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, dilithium_buffer,
+            dilithium_sz, SSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
             err_sys_ex(catastrophic, "can't load server private key buffer");
     #elif !defined(TEST_LOAD_BUFFER)
         if (SSL_CTX_use_PrivateKey_file(ctx, ourKey, WOLFSSL_FILETYPE_PEM)

As expected, I got the following error message: wolfSSL error: can't load server private key buffer

I then used this change:

diff --git examples/server/server.c examples/server/server.c
index cca853a14..88f8b1b56 100644
--- examples/server/server.c
+++ examples/server/server.c
@@ -2720,8 +2720,14 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
     #endif /* HAVE_PK_CALLBACKS && TEST_PK_PRIVKEY */
     ) {
     #ifdef NO_FILESYSTEM
-        if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, server_key_der_2048,
-            sizeof_server_key_der_2048, SSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS)
+
+byte dilithium_buffer[11000];
+int dilithium_sz;
+FILE * f = fopen("/path/to/wolfssl-examples/certs/mldsa87_server_key.pem", "r");
+dilithium_sz = fread(dilithium_buffer, 1, 11000, f);
+fclose(f);
+        if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, dilithium_buffer,
+            dilithium_sz, SSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
             err_sys_ex(catastrophic, "can't load server private key buffer");
     #elif !defined(TEST_LOAD_BUFFER)
         if (SSL_CTX_use_PrivateKey_file(ctx, ourKey, WOLFSSL_FILETYPE_PEM)

I ran examples/server/server and no error occurred.

I then used this change:

diff --git examples/server/server.c examples/server/server.c
index cca853a14..ae2599a85 100644
--- examples/server/server.c
+++ examples/server/server.c
@@ -2720,8 +2720,14 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
     #endif /* HAVE_PK_CALLBACKS && TEST_PK_PRIVKEY */
     ) {
     #ifdef NO_FILESYSTEM
-        if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, server_key_der_2048,
-            sizeof_server_key_der_2048, SSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS)
+
+byte dilithium_buffer[11000];
+int dilithium_sz;
+FILE * f = fopen("/path/to/wolfssl-examples/certs/mldsa87_server_key.pem", "r");
+dilithium_sz = fread(dilithium_buffer, 1, 11000, f);
+fclose(f);
+        if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, dilithium_buffer,
+            dilithium_sz, SSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS)
             err_sys_ex(catastrophic, "can't load server private key buffer");
     #elif !defined(TEST_LOAD_BUFFER)
         if (SSL_CTX_use_PrivateKey_file(ctx, ourKey, WOLFSSL_FILETYPE_PEM)

As expected, I got the following error message: wolfSSL error: can't load server private key buffer

Note, you'll need the following wolfssl-examples PR to get the keys: https://github.com/wolfSSL/wolfssl-examples/pull/443

Warm regards, Anthony

gstrauss commented 1 day ago

lighttpd base64-decodes the key from a .pem file into a buffer which contains the DER. Passing this value to wolfSSL_CTX_use_PrivateKey_buffer() failed with dilithium keys. Using lighttpd mod_openssl instead of lighttpd mod_wolfssl works fine with the same keys, so the base64-decoding is working.

lighttpd does not use stdio because lighttpd takes steps to wipe the memory containing sensitive keys, something that you can not do portably with internal stdio buffers unless you employ setvbuf() with a custom-allocated buffer.

anhu commented 17 hours ago

We have recently be moving to newer versions of the algorithm. You might need to use mldsa when generating the certificates.