From: Victor Julien Date: Tue, 23 Aug 2022 09:32:24 +0000 (+0200) Subject: tls: parse client certificates X-Git-Tag: suricata-7.0.0-beta1~194 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e817a8f9682da61571c55667ec19edd13dc13d87;p=thirdparty%2Fsuricata.git tls: parse client certificates 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. --- diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 41aab58629..67a447cea0 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -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); diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 7ec2b9cb18..57521bac1b 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -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)