Browse Source

Implement transient certs

Add wolfSSL_CertManagerUnloadIntermediateCerts API to clear intermediate certs added to store.
Juliusz Sosinowicz 2 months ago
parent
commit
4caef93346
6 changed files with 233 additions and 18 deletions
  1. 17 0
      src/ssl.c
  2. 25 0
      src/ssl_certman.c
  3. 163 18
      tests/api.c
  4. 22 0
      wolfcrypt/src/asn.c
  5. 3 0
      wolfssl/ssl.h
  6. 3 0
      wolfssl/wolfcrypt/asn.h

+ 17 - 0
src/ssl.c

@@ -5954,6 +5954,7 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify)
         cert->permittedNames = NULL;
         cert->excludedNames = NULL;
     #endif
+        signer->type = (byte)type;
 
     #ifndef NO_SKID
         row = HashSigner(signer->subjectKeyIdHash);
@@ -16355,6 +16356,22 @@ int wolfSSL_set_compression(WOLFSSL* ssl)
         return wolfSSL_CertManagerUnloadCAs(ctx->cm);
     }
 
+    int wolfSSL_CTX_UnloadIntermediateCerts(WOLFSSL_CTX* ctx)
+    {
+        WOLFSSL_ENTER("wolfSSL_CTX_UnloadIntermediateCerts");
+
+        if (ctx == NULL)
+            return BAD_FUNC_ARG;
+
+        if (ctx->ref.count > 1) {
+            WOLFSSL_MSG("ctx object must have a ref count of 1 before "
+                        "unloading intermediate certs");
+            return BAD_STATE_E;
+        }
+
+        return wolfSSL_CertManagerUnloadIntermediateCerts(ctx->cm);
+    }
+
 
 #ifdef WOLFSSL_TRUST_PEER_CERT
     int wolfSSL_CTX_Unload_trust_peers(WOLFSSL_CTX* ctx)

+ 25 - 0
src/ssl_certman.c

@@ -457,6 +457,31 @@ int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm)
     return ret;
 }
 
+int wolfSSL_CertManagerUnloadIntermediateCerts(WOLFSSL_CERT_MANAGER* cm)
+{
+    int ret = WOLFSSL_SUCCESS;
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerUnloadIntermediateCerts");
+
+    /* Validate parameter. */
+    if (cm == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    /* Lock CA table. */
+    if ((ret == WOLFSSL_SUCCESS) && (wc_LockMutex(&cm->caLock) != 0)) {
+        ret = BAD_MUTEX_E;
+    }
+    if (ret == WOLFSSL_SUCCESS) {
+        /* Dispose of CA table. */
+        FreeSignerTableType(cm->caTable, CA_TABLE_SIZE, WOLFSSL_CHAIN_CA,
+                cm->heap);
+
+        /* Unlock CA table. */
+        wc_UnLockMutex(&cm->caLock);
+    }
+
+    return ret;
+}
 
 #ifdef WOLFSSL_TRUST_PEER_CERT
 /* Unload the trusted peers table.

+ 163 - 18
tests/api.c

@@ -441,6 +441,7 @@ typedef struct test_ssl_cbf {
     ctx_cb ctx_ready;
     ssl_cb ssl_ready;
     ssl_cb on_result;
+    ctx_cb on_ctx_cleanup;
     ssl_cb on_cleanup;
     hs_cb  on_handshake;
     WOLFSSL_CTX* ctx;
@@ -6149,8 +6150,10 @@ static WC_INLINE int test_ssl_memio_setup(test_ssl_memio_ctx *ctx)
     int c_sharedCtx = 0;
     int s_sharedCtx = 0;
 #endif
-    const char* certFile = svrCertFile;
-    const char* keyFile = svrKeyFile;
+    const char* clientCertFile = cliCertFile;
+    const char* clientKeyFile = cliKeyFile;
+    const char* serverCertFile = svrCertFile;
+    const char* serverKeyFile = svrKeyFile;
 
     /********************************
      * Create WOLFSSL_CTX for client.
@@ -6182,13 +6185,19 @@ static WC_INLINE int test_ssl_memio_setup(test_ssl_memio_ctx *ctx)
     else
         ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->c_ctx,
                 caCertFile, 0), WOLFSSL_SUCCESS);
+    if (ctx->c_cb.certPemFile != NULL) {
+        clientCertFile = ctx->c_cb.certPemFile;
+    }
+    if (ctx->c_cb.keyPemFile != NULL) {
+        clientKeyFile = ctx->c_cb.keyPemFile;
+    }
 #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
     if (!c_sharedCtx)
 #endif
     {
         ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx->c_ctx,
-            cliCertFile), WOLFSSL_SUCCESS);
-        ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx->c_ctx, cliKeyFile,
+            clientCertFile), WOLFSSL_SUCCESS);
+        ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx->c_ctx, clientKeyFile,
             WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
     }
 #ifdef HAVE_CRL
@@ -6255,23 +6264,23 @@ static WC_INLINE int test_ssl_memio_setup(test_ssl_memio_ctx *ctx)
     wolfSSL_CTX_set_default_passwd_cb(ctx->s_ctx, PasswordCallBack);
 #endif
     if (ctx->s_cb.certPemFile != NULL) {
-        certFile = ctx->s_cb.certPemFile;
+        serverCertFile = ctx->s_cb.certPemFile;
     }
 #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
     if (!s_sharedCtx)
 #endif
     {
         ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx->s_ctx,
-            certFile), WOLFSSL_SUCCESS);
+            serverCertFile), WOLFSSL_SUCCESS);
     }
     if (ctx->s_cb.keyPemFile != NULL) {
-        keyFile = ctx->s_cb.keyPemFile;
+        serverKeyFile = ctx->s_cb.keyPemFile;
     }
 #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
     if (!s_sharedCtx)
 #endif
     {
-        ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx->s_ctx, keyFile,
+        ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx->s_ctx, serverKeyFile,
             WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
     }
     if (ctx->s_ciphers != NULL) {
@@ -6295,9 +6304,9 @@ static WC_INLINE int test_ssl_memio_setup(test_ssl_memio_ctx *ctx)
 #endif
         )
     {
-        ExpectIntEQ(wolfSSL_use_certificate_chain_file(ctx->c_ssl, cliCertFile),
-            WOLFSSL_SUCCESS);
-        ExpectIntEQ(wolfSSL_use_PrivateKey_file(ctx->c_ssl, cliKeyFile,
+        ExpectIntEQ(wolfSSL_use_certificate_chain_file(ctx->c_ssl,
+                clientCertFile), WOLFSSL_SUCCESS);
+        ExpectIntEQ(wolfSSL_use_PrivateKey_file(ctx->c_ssl, clientKeyFile,
             WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
     }
     if (ctx->c_cb.ssl_ready != NULL) {
@@ -6316,9 +6325,9 @@ static WC_INLINE int test_ssl_memio_setup(test_ssl_memio_ctx *ctx)
 #endif
         )
     {
-        ExpectIntEQ(wolfSSL_use_certificate_chain_file(ctx->s_ssl, certFile),
-            WOLFSSL_SUCCESS);
-        ExpectIntEQ(wolfSSL_use_PrivateKey_file(ctx->s_ssl, keyFile,
+        ExpectIntEQ(wolfSSL_use_certificate_chain_file(ctx->s_ssl,
+                serverCertFile), WOLFSSL_SUCCESS);
+        ExpectIntEQ(wolfSSL_use_PrivateKey_file(ctx->s_ssl, serverKeyFile,
             WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
     }
 #if !defined(NO_FILESYSTEM) && !defined(NO_DH)
@@ -6400,7 +6409,7 @@ static int test_ssl_memio_do_handshake(test_ssl_memio_ctx* ctx, int max_rounds,
         }
     }
 
-    if (!handshake_complete) {
+    if (!handshake_complete || failing_c || failing_s) {
         return TEST_FAIL;
     }
 
@@ -6468,14 +6477,20 @@ static void test_ssl_memio_cleanup(test_ssl_memio_ctx* ctx)
     wolfSSL_shutdown(ctx->c_ssl);
     wolfSSL_free(ctx->s_ssl);
     wolfSSL_free(ctx->c_ssl);
-    if (!ctx->s_cb.isSharedCtx) {
-        wolfSSL_CTX_free(ctx->s_ctx);
-        ctx->s_ctx = NULL;
+    if (ctx->c_cb.on_ctx_cleanup != NULL) {
+        ctx->c_cb.on_ctx_cleanup(ctx->c_ctx);
     }
     if (!ctx->c_cb.isSharedCtx) {
         wolfSSL_CTX_free(ctx->c_ctx);
         ctx->c_ctx = NULL;
     }
+    if (ctx->s_cb.on_ctx_cleanup != NULL) {
+        ctx->s_cb.on_ctx_cleanup(ctx->s_ctx);
+    }
+    if (!ctx->s_cb.isSharedCtx) {
+        wolfSSL_CTX_free(ctx->s_ctx);
+        ctx->s_ctx = NULL;
+    }
 
     if (!ctx->s_cb.ticNoInit) {
 #if defined(HAVE_SESSION_TICKET) && \
@@ -69972,6 +69987,135 @@ static int test_get_signature_nid(void)
     return EXPECT_RESULT();
 }
 
+#if !defined(NO_CERTS) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
+static word32 test_tls_cert_store_unchanged_HashCaTable(Signer** caTable)
+{
+#ifndef NO_MD5
+    enum wc_HashType hashType = WC_HASH_TYPE_MD5;
+#elif !defined(NO_SHA)
+    enum wc_HashType hashType = WC_HASH_TYPE_SHA;
+#elif !defined(NO_SHA256)
+    enum wc_HashType hashType = WC_HASH_TYPE_SHA256;
+#else
+    #error "We need a digest to hash the Signer object"
+#endif
+    byte hashBuf[WC_MAX_DIGEST_SIZE];
+    wc_HashAlg hash;
+    size_t i;
+
+    AssertIntEQ(wc_HashInit(&hash, hashType), 0);
+    for (i = 0; i < CA_TABLE_SIZE; i++) {
+        Signer* cur;
+        for (cur = caTable[i]; cur != NULL; cur = cur->next)
+            AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)cur,
+                    sizeof(*cur)), 0);
+    }
+    AssertIntEQ(wc_HashFinal(&hash, hashType, hashBuf), 0);
+    AssertIntEQ(wc_HashFree(&hash, hashType), 0);
+
+    return MakeWordFromHash(hashBuf);
+}
+
+static word32 test_tls_cert_store_unchanged_before_hashes[2];
+static size_t test_tls_cert_store_unchanged_before_hashes_idx = 0;
+static word32 test_tls_cert_store_unchanged_after_hashes[2];
+static size_t test_tls_cert_store_unchanged_after_hashes_idx = 0;
+
+static int test_tls_cert_store_unchanged_ctx_ready(WOLFSSL_CTX* ctx)
+{
+    EXPECT_DECLS;
+
+    ExpectIntNE(test_tls_cert_store_unchanged_before_hashes
+        [test_tls_cert_store_unchanged_before_hashes_idx++] =
+            test_tls_cert_store_unchanged_HashCaTable(ctx->cm->caTable), 0);
+
+    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER |
+            WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
+
+    return EXPECT_RESULT();
+}
+
+static int test_tls_cert_store_unchanged_ctx_cleanup(WOLFSSL_CTX* ctx)
+{
+    EXPECT_DECLS;
+    ExpectIntEQ(wolfSSL_CTX_UnloadIntermediateCerts(ctx), WOLFSSL_SUCCESS);
+    ExpectIntNE(test_tls_cert_store_unchanged_after_hashes
+        [test_tls_cert_store_unchanged_after_hashes_idx++] =
+            test_tls_cert_store_unchanged_HashCaTable(ctx->cm->caTable), 0);
+
+    return EXPECT_RESULT();
+}
+
+/*
+static int test_tls_cert_store_unchanged_on_hs(WOLFSSL_CTX **ctx, WOLFSSL **ssl)
+{
+    EXPECT_DECLS;
+
+    (void)ssl;
+    ExpectIntNE(test_tls_cert_store_unchanged_after_hashes
+        [test_tls_cert_store_unchanged_after_hashes_idx++] =
+            test_tls_cert_store_unchanged_HashCaTable((*ctx)->cm->caTable), 0);
+
+    return EXPECT_RESULT();
+}
+*/
+
+static int test_tls_cert_store_unchanged_ssl_ready(WOLFSSL* ssl)
+{
+    EXPECT_DECLS;
+    WOLFSSL_CTX* ctx;
+
+    ExpectNotNull(ctx = wolfSSL_get_SSL_CTX(ssl));
+
+    return EXPECT_RESULT();
+}
+#endif
+
+static int test_tls_cert_store_unchanged(void)
+{
+    EXPECT_DECLS;
+#if !defined(NO_CERTS) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
+    test_ssl_cbf client_cbf;
+    test_ssl_cbf server_cbf;
+
+    XMEMSET(&client_cbf, 0, sizeof(client_cbf));
+    XMEMSET(&server_cbf, 0, sizeof(server_cbf));
+
+    XMEMSET(test_tls_cert_store_unchanged_before_hashes, 0,
+            sizeof(test_tls_cert_store_unchanged_before_hashes));
+    XMEMSET(test_tls_cert_store_unchanged_after_hashes, 0,
+            sizeof(test_tls_cert_store_unchanged_after_hashes));
+
+    client_cbf.ctx_ready = test_tls_cert_store_unchanged_ctx_ready;
+    server_cbf.ctx_ready = test_tls_cert_store_unchanged_ctx_ready;
+
+    client_cbf.ssl_ready = test_tls_cert_store_unchanged_ssl_ready;
+    server_cbf.ssl_ready = test_tls_cert_store_unchanged_ssl_ready;
+
+    /* TODO add API to allow clearing/not storing certs while connections are
+     * still active.
+    client_cbf.on_handshake = test_tls_cert_store_unchanged_on_hs;
+    server_cbf.on_handshake = test_tls_cert_store_unchanged_on_hs;
+    */
+
+    client_cbf.on_ctx_cleanup = test_tls_cert_store_unchanged_ctx_cleanup;
+    server_cbf.on_ctx_cleanup = test_tls_cert_store_unchanged_ctx_cleanup;
+
+    client_cbf.certPemFile = "certs/intermediate/client-chain.pem";
+    server_cbf.certPemFile = "certs/intermediate/server-chain.pem";
+
+    server_cbf.caPemFile = caCertFile;
+
+    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
+        &server_cbf, NULL), TEST_SUCCESS);
+
+    ExpectBufEQ(test_tls_cert_store_unchanged_before_hashes,
+            test_tls_cert_store_unchanged_after_hashes,
+            sizeof(test_tls_cert_store_unchanged_after_hashes));
+#endif
+    return EXPECT_RESULT();
+}
+
 /*----------------------------------------------------------------------------*
  | Main
  *----------------------------------------------------------------------------*/
@@ -71281,6 +71425,7 @@ TEST_CASE testCases[] = {
     TEST_DECL(test_write_dup),
     TEST_DECL(test_read_write_hs),
     TEST_DECL(test_get_signature_nid),
+    TEST_DECL(test_tls_cert_store_unchanged),
     /* This test needs to stay at the end to clean up any caches allocated. */
     TEST_DECL(test_wolfSSL_Cleanup)
 };

+ 22 - 0
wolfcrypt/src/asn.c

@@ -23610,6 +23610,28 @@ void FreeSignerTable(Signer** table, int rows, void* heap)
     }
 }
 
+void FreeSignerTableType(Signer** table, int rows, byte type, void* heap)
+{
+    int i;
+
+    for (i = 0; i < rows; i++) {
+        Signer* signer = table[i];
+        Signer** next = &table[i];
+
+        while (signer) {
+            if (signer->type == type) {
+                *next = signer->next;
+                FreeSigner(signer, heap);
+                signer = *next;
+            }
+            else {
+                next = &signer->next;
+                signer = signer->next;
+            }
+        }
+    }
+}
+
 #ifdef WOLFSSL_TRUST_PEER_CERT
 /* Free an individual trusted peer cert.
  *

+ 3 - 0
wolfssl/ssl.h

@@ -3063,6 +3063,7 @@ WOLFSSL_API int wolfSSL_make_eap_keys(WOLFSSL* ssl, void* key, unsigned int len,
 #ifndef NO_CERTS
     /* SSL_CTX versions */
     WOLFSSL_API int wolfSSL_CTX_UnloadCAs(WOLFSSL_CTX* ctx);
+    WOLFSSL_API int wolfSSL_CTX_UnloadIntermediateCerts(WOLFSSL_CTX* ctx);
 #ifdef WOLFSSL_TRUST_PEER_CERT
     WOLFSSL_API int wolfSSL_CTX_Unload_trust_peers(WOLFSSL_CTX* ctx);
 #ifdef WOLFSSL_LOCAL_X509_STORE
@@ -3617,6 +3618,8 @@ WOLFSSL_API void wolfSSL_CTX_SetPerformTlsRecordProcessingCb(WOLFSSL_CTX* ctx,
         const unsigned char* buff, long sz, int format);
 
     WOLFSSL_API int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm);
+    WOLFSSL_API int wolfSSL_CertManagerUnloadIntermediateCerts(
+        WOLFSSL_CERT_MANAGER* cm);
 #ifdef WOLFSSL_TRUST_PEER_CERT
     WOLFSSL_API int wolfSSL_CertManagerUnload_trust_peers(
         WOLFSSL_CERT_MANAGER* cm);

+ 3 - 0
wolfssl/wolfcrypt/asn.h

@@ -2022,6 +2022,7 @@ struct Signer {
     byte *sapkiDer;
     int sapkiLen;
 #endif /* WOLFSSL_DUAL_ALG_CERTS */
+    byte type;
 
     Signer* next;
 };
@@ -2167,6 +2168,8 @@ WOLFSSL_LOCAL const byte* OidFromId(word32 id, word32 type, word32* oidSz);
 WOLFSSL_LOCAL Signer* MakeSigner(void* heap);
 WOLFSSL_LOCAL void    FreeSigner(Signer* signer, void* heap);
 WOLFSSL_LOCAL void    FreeSignerTable(Signer** table, int rows, void* heap);
+WOLFSSL_LOCAL void    FreeSignerTableType(Signer** table, int rows, byte type,
+                                          void* heap);
 #ifdef WOLFSSL_TRUST_PEER_CERT
 WOLFSSL_LOCAL void    FreeTrustedPeer(TrustedPeerCert* tp, void* heap);
 WOLFSSL_LOCAL void    FreeTrustedPeerTable(TrustedPeerCert** table, int rows,