]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
tls: parse client certificates
authorVictor Julien <vjulien@oisf.net>
Tue, 23 Aug 2022 09:32:24 +0000 (11:32 +0200)
committerVictor Julien <vjulien@oisf.net>
Wed, 21 Sep 2022 04:43:48 +0000 (06:43 +0200)
Parse client cerificates and store them in the state similar to how
this is done for server certificates.

Update "progress" handling to not consider the TLS handshake complete
if the server indicated a client cert was needed.

src/app-layer-ssl.c
src/app-layer-ssl.h

index 41aab58629763ae217e07314f65561005dd5b67d..67a447cea03f18aa087f90073edba4671f0dc26e 100644 (file)
@@ -1478,21 +1478,21 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, const uint8_t *input,
             break;
 
         case SSLV3_HS_CERTIFICATE:
-            /* For now, only decode the server certificate */
-            if (direction == 0) {
-                SCLogDebug("Incorrect SSL Record type sent in the toserver "
-                           "direction!");
-                break;
-            }
 
-            rc = SSLv3ParseHandshakeTypeCertificate(
-                    ssl_state, &ssl_state->server_connp, initial_input, input_len);
+            rc = SSLv3ParseHandshakeTypeCertificate(ssl_state,
+                    direction ? &ssl_state->server_connp : &ssl_state->client_connp, initial_input,
+                    input_len);
             if (rc < 0)
                 return rc;
             break;
 
         case SSLV3_HS_HELLO_REQUEST:
+            break;
         case SSLV3_HS_CERTIFICATE_REQUEST:
+            if (direction) {
+                ssl_state->current_flags = SSL_AL_FLAG_NEED_CLIENT_CERT;
+            }
+            break;
         case SSLV3_HS_CERTIFICATE_VERIFY:
         case SSLV3_HS_FINISHED:
         case SSLV3_HS_CERTIFICATE_URL:
@@ -2496,8 +2496,12 @@ static AppLayerResult SSLDecode(Flow *f, uint8_t direction, void *alstate,
     } /* while (input_len) */
 
     /* mark handshake as done if we have subject and issuer */
-    if (ssl_state->server_connp.cert0_subject &&
-            ssl_state->server_connp.cert0_issuerdn) {
+    if ((ssl_state->flags & SSL_AL_FLAG_NEED_CLIENT_CERT) &&
+            ssl_state->client_connp.cert0_subject && ssl_state->client_connp.cert0_issuerdn) {
+        SCLogDebug("SSL_AL_FLAG_HANDSHAKE_DONE");
+        ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE;
+    } else if ((ssl_state->flags & SSL_AL_FLAG_NEED_CLIENT_CERT) == 0 &&
+               ssl_state->server_connp.cert0_subject && ssl_state->server_connp.cert0_issuerdn) {
         SCLogDebug("SSL_AL_FLAG_HANDSHAKE_DONE");
         ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE;
     }
@@ -2539,6 +2543,7 @@ static void *SSLStateAlloc(void *orig_state, AppProto proto_orig)
     memset(ssl_state->client_connp.random, 0, TLS_RANDOM_LEN);
     memset(ssl_state->server_connp.random, 0, TLS_RANDOM_LEN);
     TAILQ_INIT(&ssl_state->server_connp.certs);
+    TAILQ_INIT(&ssl_state->client_connp.certs);
 
     return (void *)ssl_state;
 }
@@ -2603,6 +2608,12 @@ static void SSLStateFree(void *p)
         SCFree(item);
     }
     TAILQ_INIT(&ssl_state->server_connp.certs);
+    /* Free certificate chain */
+    while ((item = TAILQ_FIRST(&ssl_state->client_connp.certs))) {
+        TAILQ_REMOVE(&ssl_state->client_connp.certs, item, next);
+        SCFree(item);
+    }
+    TAILQ_INIT(&ssl_state->client_connp.certs);
 
     SCFree(ssl_state);
 
index 7ec2b9cb18e0d7b21ea5be66cb929286bd55d13e..57521bac1b1bca05a3e1e1d4e104272958f59748 100644 (file)
@@ -135,6 +135,8 @@ enum {
 /* flag to indicate that client random was filled */
 #define TLS_TC_RANDOM_SET BIT_U32(25)
 
+#define SSL_AL_FLAG_NEED_CLIENT_CERT BIT_U32(26)
+
 /* config flags */
 #define SSL_TLS_LOG_PEM                         (1 << 0)