@ -70,24 +70,20 @@ static SCEnumCharMap tls_state_client_table[] = {
static SCEnumCharMap tls_state_server_table [ ] = {
{
" server_ in_progress " ,
TLS_STATE_SERVER_ IN_PROGRESS ,
" server_ started " ,
TLS_STATE_SERVER_ STARTED ,
} ,
{
" server_hello " ,
TLS_STATE_SERVER_HELLO ,
} ,
{
" server_cert _done " ,
TLS_STATE_SERVER_CERT _DONE ,
" server_cert " ,
TLS_STATE_SERVER_CERT ,
} ,
{
" server_hello_done " ,
TLS_STATE_SERVER_HELLO_DONE ,
} ,
{
" server_handshake_done " ,
TLS_STATE_SERVER_HANDSHAKE_DONE ,
" server_data " ,
TLS_STATE_SERVER_DATA ,
} ,
{
" server_finished " ,
@ -440,19 +436,15 @@ static void TlsDecodeHSCertificateErrSetEvent(SSLState *ssl_state, uint32_t err)
}
static inline int TlsDecodeHSCertificateFingerprint (
SSLStateConnp * connp , const uint8_t * input , uint32_t cert_len )
char * * out , const uint8_t * input , uint32_t cert_len )
{
if ( unlikely ( connp - > cert0_fingerprint ! = NULL ) )
return 0 ;
connp - > cert0_fingerprint = SCCalloc ( 1 , SHA1_STRING_LENGTH ) ;
if ( connp - > cert0_fingerprint = = NULL )
* out = SCCalloc ( 1 , SHA1_STRING_LENGTH ) ;
if ( * out = = NULL )
return - 1 ;
uint8_t hash [ SC_SHA1_LEN ] ;
if ( SCSha1HashBuffer ( input , cert_len , hash , sizeof ( hash ) ) = = 1 ) {
SCToHex_sep (
( uint8_t * ) connp - > cert0_fingerprint , SHA1_STRING_LENGTH , ' : ' , hash , SC_SHA1_LEN ) ;
SCToHex_sep ( ( uint8_t * ) * out , SHA1_STRING_LENGTH , ' : ' , hash , SC_SHA1_LEN ) ;
}
return 0 ;
}
@ -472,13 +464,23 @@ static inline int TlsDecodeHSCertificateAddCertToChain(
}
static int TlsDecodeHSCertificate ( SSLState * ssl_state , SSLStateConnp * connp ,
const uint8_t * const initial_input , const uint32_t input_len , const int certn )
const uint8_t * const initial_input , const uint32_t input_len , const int certn ,
bool * extract_event_sent )
{
const uint8_t * input = ( uint8_t * ) initial_input ;
uint32_t err_code = 0 ;
X509 * x509 = NULL ;
int rc = 0 ;
/* stashed cert0 extraction: published to connp only when the whole
* certificate decodes ( see the cert0 fill below ) */
uint8_t * st_subject = NULL , * st_issuer = NULL , * st_serial = NULL ;
SSLSubjectAltName * st_sans = NULL ;
char * st_fingerprint = NULL ;
uint32_t st_subject_len = 0 , st_issuer_len = 0 , st_serial_len = 0 ;
uint16_t st_sans_num = 0 ;
int64_t st_not_before = 0 , st_not_after = 0 ;
if ( ! ( HAS_SPACE ( 3 ) ) )
goto invalid_cert ;
@ -493,74 +495,121 @@ static int TlsDecodeHSCertificate(SSLState *ssl_state, SSLStateConnp *connp,
connp - > cert0_serial = = NULL ) {
x509 = SCX509Decode ( input , cert_len , & err_code ) ;
if ( x509 = = NULL ) {
/* an undecodable certificate: report it once and let the
* caller skip it - the rest of the chain must still be
* decoded */
TlsDecodeHSCertificateErrSetEvent ( ssl_state , err_code ) ;
goto next ;
goto fail ;
}
SCX509GetSubject ( x509 , & connp - > cert0_subject , & connp - > cert0_subject_len ) ;
if ( connp - > cert0_subject = = NULL ) {
/* extract into the stashes and publish to connp->cert0_* only
* when the whole certificate yields every field : a partial fill
* would otherwise block the next certificate from completing the
* fields */
SCX509GetSubject ( x509 , & st_subject , & st_subject_len ) ;
if ( st_subject = = NULL ) {
err_code = ERR_EXTRACT_SUBJECT ;
goto error ;
}
SCX509GetIssuer ( x509 , & connp- > cert0_issuerdn , & connp - > cert0_issuerdn _len) ;
if ( connp- > cert0_issuerdn = = NULL ) {
SCX509GetIssuer ( x509 , & st_issuer, & st_issuer _len) ;
if ( st_issuer = = NULL ) {
err_code = ERR_EXTRACT_ISSUER ;
goto error ;
}
connp- > cert0 _sans_num = SCX509GetSubjectAltNameLen ( x509 ) ;
if ( connp- > cert0_sans_num = = TLS_MAX_SAN ) {
st _sans_num = SCX509GetSubjectAltNameLen ( x509 ) ;
if ( st_sans_num = = TLS_MAX_SAN & & ! * extract_event_sent ) {
SSLSetEvent ( ssl_state , TLS_DECODER_EVENT_TOO_MANY_SUBJECT_ALTERNATIVE_NAMES ) ;
* extract_event_sent = true ;
}
connp - > cert0_sans = SCCalloc ( connp - > cert0_sans_num , sizeof ( SSLSubjectAltName ) ) ;
if ( connp - > cert0_sans = = NULL ) {
connp - > cert0_sans_num = 0 ;
if ( st_sans_num > 0 ) {
st_sans = SCCalloc ( st_sans_num , sizeof ( SSLSubjectAltName ) ) ;
if ( st_sans = = NULL ) {
st_sans_num = 0 ;
goto error ;
}
for ( uint16_t i = 0 ; i < connp- > cert0 _sans_num; i + + ) {
SCX509GetSubjectAltNameAt (
x509 , i , & connp - > cert0_sans [ i ] . san , & connp - > cert0_sans [ i ] . san_len ) ;
for ( uint16_t i = 0 ; i < st _sans_num; i + + ) {
SCX509GetSubjectAltNameAt ( x509 , i , & st_sans [ i ] . san , & st_sans [ i ] . san_len ) ;
}
}
SCX509GetSerial ( x509 , & connp- > cert0_serial , & connp - > cert0 _serial_len) ;
if ( connp- > cert0 _serial = = NULL ) {
SCX509GetSerial ( x509 , & st_serial, & st _serial_len) ;
if ( st _serial = = NULL ) {
err_code = ERR_INVALID_SERIAL ;
goto error ;
}
rc = SCX509GetValidity ( x509 , & connp- > cert0_not_before , & connp - > cert0 _not_after) ;
rc = SCX509GetValidity ( x509 , & st_not_before, & st _not_after) ;
if ( rc ! = 0 ) {
err_code = ERR_EXTRACT_VALIDITY ;
goto error ;
}
SCX509Free ( x509 ) ;
x509 = NULL ;
rc = TlsDecodeHSCertificateFingerprint ( connp , input , cert_len ) ;
rc = TlsDecodeHSCertificateFingerprint ( & st_fingerprint , input , cert_len ) ;
if ( rc ! = 0 ) {
SCLogDebug ( " TlsDecodeHSCertificateFingerprint failed with %d " , rc ) ;
goto error ;
}
/* the certificate yielded every field: publish it */
connp - > cert0_subject = st_subject ;
connp - > cert0_subject_len = st_subject_len ;
connp - > cert0_issuerdn = st_issuer ;
connp - > cert0_issuerdn_len = st_issuer_len ;
connp - > cert0_sans = st_sans ;
connp - > cert0_sans_num = st_sans_num ;
connp - > cert0_serial = st_serial ;
connp - > cert0_serial_len = st_serial_len ;
connp - > cert0_not_before = st_not_before ;
connp - > cert0_not_after = st_not_after ;
connp - > cert0_fingerprint = st_fingerprint ;
st_subject = st_issuer = st_serial = NULL ;
st_sans = NULL ;
st_fingerprint = NULL ;
SCX509Free ( x509 ) ;
x509 = NULL ;
}
/* every certificate of the chain is kept, also for certn > 0 */
rc = TlsDecodeHSCertificateAddCertToChain ( connp , input , cert_len ) ;
if ( rc ! = 0 ) {
SCLogDebug ( " TlsDecodeHSCertificateAddCertToChain failed with %d " , rc ) ;
goto error ;
}
next :
input + = cert_len ;
return ( int ) ( input - initial_input ) ;
error :
if ( err_code ! = 0 )
if ( err_code ! = 0 & & ! * extract_event_sent ) {
/* the message no longer aborts at the first failing certificate:
* report the first extraction failure once */
TlsDecodeHSCertificateErrSetEvent ( ssl_state , err_code ) ;
* extract_event_sent = true ;
}
/* the certificate failed before the publish block: nothing was
* published , release the stashed extraction so the next certificate
* can fill cert0 */
if ( st_subject ! = NULL )
SCX509ArrayFree ( st_subject , st_subject_len ) ;
if ( st_issuer ! = NULL )
SCX509ArrayFree ( st_issuer , st_issuer_len ) ;
if ( st_serial ! = NULL )
SCX509ArrayFree ( st_serial , st_serial_len ) ;
if ( st_fingerprint ! = NULL )
SCFree ( st_fingerprint ) ;
if ( st_sans ! = NULL ) {
for ( uint16_t i = 0 ; i < st_sans_num ; i + + )
SCX509ArrayFree ( st_sans [ i ] . san , st_sans [ i ] . san_len ) ;
SCFree ( st_sans ) ;
}
if ( x509 ! = NULL )
SCX509Free ( x509 ) ;
return - 1 ;
fail :
return - 1 ;
invalid_cert :
@ -589,10 +638,17 @@ static int TlsDecodeHSCertificates(SSLState *ssl_state, SSLStateConnp *connp,
return - 1 ;
if ( connp - > certs_buffer ! = NULL ) {
// TODO should we set an event here?
/* one-shot buffer: a second certificate message must not
* overwrite or invalidate the data of the first one ( base
* semantics , renegotiation re - sends the same certificate ) */
return - 1 ;
}
/* this connp's certificate message: until it decodes fully the
* certificate data is incomplete - only a fully decoded certificate
* message completes it , never a later handshake message */
connp - > cert_data_incomplete = true ;
connp - > certs_buffer = SCCalloc ( 1 , cert_chain_len ) ;
if ( connp - > certs_buffer = = NULL ) {
return - 1 ;
@ -602,21 +658,42 @@ static int TlsDecodeHSCertificates(SSLState *ssl_state, SSLStateConnp *connp,
int cert_cnt = 0 ;
uint32_t processed_len = 0 ;
bool cert_failed = false ;
bool extract_event_sent = false ;
/* coverity[tainted_data] */
while ( processed_len < cert_chain_len ) {
int rc = TlsDecodeHSCertificate ( ssl_state , connp , connp - > certs_buffer + processed_len ,
connp - > certs_buffer_size - processed_len , cert_cnt ) ;
if ( rc < = 0 ) { // 0 should be impossible, but lets be defensive
return - 1 ;
}
connp - > certs_buffer_size - processed_len , cert_cnt , & extract_event_sent ) ;
if ( rc > 0 ) {
DEBUG_VALIDATE_BUG_ON ( processed_len + ( uint32_t ) rc > cert_chain_len ) ;
if ( processed_len + ( uint32_t ) rc > cert_chain_len ) {
return - 1 ;
}
processed_len + = ( uint32_t ) rc ;
continue ;
}
/* a certificate failed to decode: skip its bytes so the rest
* of the chain is still decoded ; an invalid length aborts the
* message */
const uint8_t * cert = connp - > certs_buffer + processed_len ;
if ( processed_len + 3 > cert_chain_len )
return - 1 ;
const uint32_t skip = cert [ 0 ] < < 16 | cert [ 1 ] < < 8 | cert [ 2 ] ;
if ( processed_len + 3 + skip > cert_chain_len )
return - 1 ;
processed_len + = 3 + skip ;
cert_failed = true ;
}
if ( cert_failed ) {
/* the message contains an undecodable certificate: the phase
* data is incomplete , so the caller suppresses the cert phase ;
* the decoded rest of the chain is kept */
return - 1 ;
}
connp - > cert_data_incomplete = false ;
connp - > cert_chain_final = true ;
return processed_len + 3 ;
}
@ -1490,15 +1567,19 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state,
int ret ;
uint32_t parsed = 0 ;
/* a failed sub-decode must not fail the parse: the message bytes are
* consumed either way . The phase advance that follows relies on a
* fully parsed message , so suppress it via the connp flag instead . */
ret = TLSDecodeHSHelloVersion ( ssl_state , input , input_len ) ;
if ( ret < 0 )
goto end ;
goto fail ;
parsed + = ret ;
ret = TLSDecodeHSHelloRandom ( ssl_state , input + parsed , input_len - parsed ) ;
if ( ret < 0 )
goto end ;
goto fail ;
parsed + = ret ;
@ -1510,7 +1591,7 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state,
ret = TLSDecodeHSHelloSessionID ( ssl_state , input + parsed ,
input_len - parsed ) ;
if ( ret < 0 )
goto end ;
goto fail ;
parsed + = ret ;
}
@ -1518,7 +1599,7 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state,
ret = TLSDecodeHSHelloCipherSuites ( ssl_state , input + parsed ,
input_len - parsed ) ;
if ( ret < 0 )
goto end ;
goto fail ;
parsed + = ret ;
@ -1530,7 +1611,7 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state,
ret = TLSDecodeHSHelloCompressionMethods ( ssl_state , input + parsed ,
input_len - parsed ) ;
if ( ret < 0 )
goto end ;
goto fail ;
parsed + = ret ;
}
@ -1538,16 +1619,15 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state,
ret = TLSDecodeHSHelloExtensions ( ssl_state , input + parsed ,
input_len - parsed ) ;
if ( ret < 0 )
goto end ;
goto fail ;
if ( SC_ATOMIC_GET ( ssl_config . enable_ja3 ) & & ssl_state - > curr_connp - > ja3_hash = = NULL ) {
ssl_state - > curr_connp - > ja3_hash = Ja3GenerateHash ( ssl_state - > curr_connp - > ja3_str ) ;
}
return 0 ;
if ( ssl_state - > curr_connp ! = & ssl_state - > client_connp ) {
UpdateServerState ( ssl_state , TLS_STATE_SERVER_HELLO ) ;
}
end :
fail :
ssl_state - > curr_connp - > phase_suppressed = true ;
return 0 ;
}
@ -1571,10 +1651,12 @@ static inline int SSLv3ParseHandshakeTypeCertificate(SSLState *ssl_state, SSLSta
} else if ( rc < 0 ) {
SCLogDebug ( " error parsing cert, reset state " ) ;
SSLParserHSReset ( connp ) ;
/* fall through to still consume the cert bytes */
}
if ( connp ! = & ssl_state - > client_connp ) {
UpdateServerState ( ssl_state , TLS_STATE_SERVER_CERT_DONE ) ;
/* the certificate data is incomplete (an undecodable certificate);
* the track is already in the certificate phase ( entered at the
* message header ) , so nothing to suppress here . cert_data_incomplete
* only gates the handshake - done shortcut at the end of SSLDecode
* ( the cert - fields based tail ) , not the record - level data - phase
* advance ( app data and CCS records advance the track regardless ) */
}
return input_len ;
}
@ -1647,9 +1729,20 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, const uint8_t *input,
case SSLV3_HS_CLIENT_KEY_EXCHANGE :
ssl_state - > current_flags = SSL_AL_FLAG_STATE_CLIENT_KEYX ;
/* a client flight message: the server flight is over, no
* CertificateRequest can still arrive . Only the client ' s own
* message settles it - the parser accepts the type from either
* direction . */
if ( ! direction )
ssl_state - > current_flags | = SSL_AL_FLAG_SERVER_FLIGHT_DECIDED ;
break ;
case SSLV3_HS_CERTIFICATE :
if ( ! direction ) {
/* the client certificate: its own flight (and so the
* server ' s CertificateRequest decision ) is past */
ssl_state - > current_flags | = SSL_AL_FLAG_SERVER_FLIGHT_DECIDED ;
}
rc = SSLv3ParseHandshakeTypeCertificate ( ssl_state ,
direction ? & ssl_state - > server_connp : & ssl_state - > client_connp , initial_input ,
input_len ) ;
@ -1661,21 +1754,28 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, const uint8_t *input,
break ;
case SSLV3_HS_CERTIFICATE_REQUEST :
if ( direction ) {
ssl_state - > current_flags = SSL_AL_FLAG_NEED_CLIENT_CERT ;
ssl_state - > current_flags =
SSL_AL_FLAG_NEED_CLIENT_CERT | SSL_AL_FLAG_SERVER_FLIGHT_DECIDED ;
}
break ;
case SSLV3_HS_CERTIFICATE_VERIFY :
case SSLV3_HS_FINISHED :
case SSLV3_HS_CERTIFICATE_URL :
case SSLV3_HS_CERTIFICATE_STATUS :
break ;
case SSLV3_HS_NEW_SESSION_TICKET :
SCLogDebug ( " new session ticket " ) ;
case SSLV3_HS_FINISHED :
/* a finished ends its flight in either direction: the server
* flight ( and any CertificateRequest ) is past */
ssl_state - > current_flags | = SSL_AL_FLAG_SERVER_FLIGHT_DECIDED ;
break ;
case SSLV3_HS_SERVER_HELLO_DONE :
if ( direction ) {
UpdateServerState ( ssl_state , TLS_STATE_SERVER_HELLO_DONE ) ;
}
/* the server flight's last message: only the server direction
* settles it - the parser accepts the type from either
* direction */
if ( direction )
ssl_state - > current_flags | = SSL_AL_FLAG_SERVER_FLIGHT_DECIDED ;
break ;
case SSLV3_HS_NEW_SESSION_TICKET :
SCLogDebug ( " new session ticket " ) ;
break ;
default :
SSLSetEvent ( ssl_state , TLS_DECODER_EVENT_INVALID_SSL_RECORD ) ;
@ -1690,21 +1790,41 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, const uint8_t *input,
return input_len ;
}
/**
* \ brief advance the phase state once a handshake message is fully parsed
*
* A handshake message may span several records : the started states stay
* in place until the final fragment completes the message , so the phase
* data ( SNI , certificates ) is available when its state is entered .
*/
static void SSLv3HandshakePhaseAdvance ( SSLState * ssl_state )
/* the phase of a message is entered when the message starts, so all of its
* fragments belong to it ( HTTP1 : request_line starts at the first byte of the
* line , not when the line is complete ) */
static void SSLv3HandshakePhaseEnter ( SSLState * ssl_state , const uint8_t hs_type )
{
/* one message is one phase: the flag is per message, reset at its
* start ( the header is read once per message ) */
ssl_state - > curr_connp - > phase_suppressed = false ;
if ( ssl_state - > curr_connp = = & ssl_state - > client_connp ) {
if ( ssl_state - > curr_connp - > handshake_type = = SSLV3_HS_CLIENT_HELLO ) {
if ( hs_type = = SSLV3_HS_CLIENT_HELLO )
UpdateClientState ( ssl_state , TLS_STATE_CLIENT_HELLO ) ;
} else if ( ssl_state- > curr_connp - > hand shake _type = = SSLV3_HS_CERTIFICATE ) {
else if ( hs_type = = SSLV3_HS_CERTIFICATE )
UpdateClientState ( ssl_state , TLS_STATE_CLIENT_CERT ) ;
} else if ( hs_type = = SSLV3_HS_SERVER_HELLO ) {
UpdateServerState ( ssl_state , TLS_STATE_SERVER_HELLO ) ;
} else if ( hs_type = = SSLV3_HS_CERTIFICATE ) {
UpdateServerState ( ssl_state , TLS_STATE_SERVER_CERT ) ;
}
}
/* a complete hello hands the track over to the certificate phase, before any
* certificate byte arrives ( HTTP1 : request_line - > request_headers at line
* completion ) . A hello that failed to decode keeps the track in the hello
* phase : its data never existed */
static void SSLv3HandshakePhaseLeave ( SSLState * ssl_state , const uint8_t hs_type )
{
/* some handshake messages (certificates) clear the connp handshake
* type before returning , so the message type is passed in */
if ( ssl_state - > curr_connp - > phase_suppressed )
return ;
if ( ssl_state - > curr_connp = = & ssl_state - > client_connp ) {
if ( hs_type = = SSLV3_HS_CLIENT_HELLO )
UpdateClientState ( ssl_state , TLS_STATE_CLIENT_CERT ) ;
} else if ( hs_type = = SSLV3_HS_SERVER_HELLO ) {
UpdateServerState ( ssl_state , TLS_STATE_SERVER_CERT ) ;
}
}
@ -1775,7 +1895,7 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, const uint8_t *input
}
SCLogDebug ( " retval %d " , retval ) ;
SSLv3HandshakePhase Advance( ssl_stat e) ;
SSLv3HandshakePhase Leave( ssl_state , ssl_state - > curr_connp - > hs_buffer_message_typ e) ;
/* data processed, reset buffer */
SCFree ( ssl_state - > curr_connp - > hs_buffer ) ;
@ -1805,6 +1925,8 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, const uint8_t *input
ssl_state - > curr_connp - > handshake_type = input [ 0 ] ;
ssl_state - > curr_connp - > message_length = input [ 1 ] < < 16 | input [ 2 ] < < 8 | input [ 3 ] ;
/* the fragments of this message all belong to its phase */
SSLv3HandshakePhaseEnter ( ssl_state , ssl_state - > curr_connp - > handshake_type ) ;
SCLogDebug ( " handshake_type %u message len %u input %p input_len %u " ,
ssl_state - > curr_connp - > handshake_type , ssl_state - > curr_connp - > message_length , input ,
input_len ) ;
@ -1865,14 +1987,17 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, const uint8_t *input
} else {
/* full record, parse it now */
const uint8_t full_record_hs_type = ssl_state - > curr_connp - > handshake_type ;
int retval = SSLv3ParseHandshakeType (
ssl_state , input , ssl_state - > curr_connp - > message_length , direction ) ;
if ( retval < 0 | | retval > ( int ) input_len ) {
DEBUG_VALIDATE_BUG_ON ( retval > ( int ) input_len ) ;
if ( retval < 0 )
SSLParserHSReset ( ssl_state - > curr_connp ) ;
return ( retval ) ;
}
SCLogDebug ( " retval %d input_len %u " , retval , input_len ) ;
SSLv3HandshakePhase Advance( ssl_stat e) ;
SSLv3HandshakePhase Leave( ssl_state , full_record_hs_typ e) ;
input + = retval ;
input_len - = retval ;
@ -2327,8 +2452,11 @@ static struct SSLDecoderResult SSLv2Decode(uint8_t direction, SSLState *ssl_stat
" direction! " ) ;
} else {
ssl_state - > current_flags = SSL_AL_FLAG_STATE_CLIENT_KEYX ;
/* a v2 client certificate message names the client's
* certificate phase , even if the v2 certificate payload is
* not extracted */
UpdateClientState ( ssl_state , TLS_STATE_CLIENT_CERT ) ;
}
UpdateServerState ( ssl_state , TLS_STATE_SERVER_CERT_DONE ) ;
/* fall through */
case SSLV2_MT_SERVER_VERIFY :
@ -2588,7 +2716,7 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat
if ( ssl_state - > curr_connp = = & ssl_state - > client_connp ) {
UpdateClientState ( ssl_state , TLS_STATE_CLIENT_DATA ) ;
} else {
UpdateServerState ( ssl_state , TLS_STATE_SERVER_ HANDSHAKE_DONE ) ;
UpdateServerState ( ssl_state , TLS_STATE_SERVER_ DATA ) ;
}
if ( ssl_config . encrypt_mode ! = SSL_CNF_ENC_HANDLE_FULL ) {
@ -2821,17 +2949,32 @@ static AppLayerResult SSLDecode(Flow *f, uint8_t direction, void *alstate,
counter + + ;
} /* while (input_len) */
/* mark handshake as done if we have subject and issuer */
/* mark handshake as done if we have subject and issuer; the
* certificate data must be complete - a certificate message whose
* decode failed ( even with the rest of the chain decoded ) leaves the
* data incomplete until a certificate message decodes fully , so the
* tracks must not cross the cert phase on partial data */
if ( ( ssl_state - > flags & SSL_AL_FLAG_NEED_CLIENT_CERT ) & &
! ssl_state - > client_connp . cert_data_incomplete & &
ssl_state - > client_connp . cert0_subject & & ssl_state - > client_connp . cert0_issuerdn ) {
/* update both sides to keep existing behavior */
/* per track: a track's own certificate data decides its own track;
* pushing the peer track unconditionally would jump it over the
* certificate phase before its own certificate is parsed ( and
* progression is monotonic , so the phase could never be visited
* afterwards ) */
UpdateClientState ( ssl_state , TLS_STATE_CLIENT_DATA ) ;
UpdateServerState ( ssl_state , TLS_STATE_SERVER_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 ) {
/* update both sides to keep existing behavior */
UpdateClientState ( ssl_state , TLS_STATE_CLIENT_DATA ) ;
UpdateServerState ( ssl_state , TLS_STATE_SERVER_HANDSHAKE_DONE ) ;
/* an mTLS handshake is complete with the client certificate: by
* the flight order the server certificate phase was entered
* already , so advancing the server track skips nothing ( matters
* when its own chain decode failed and no server app data
* follows ) */
if ( ssl_state - > server_state > = TLS_STATE_SERVER_CERT ) {
UpdateServerState ( ssl_state , TLS_STATE_SERVER_DATA ) ;
}
}
if ( ! ssl_state - > server_connp . cert_data_incomplete & & ssl_state - > server_connp . cert0_subject & &
ssl_state - > server_connp . cert0_issuerdn ) {
UpdateServerState ( ssl_state , TLS_STATE_SERVER_DATA ) ;
}
/* flag session as finished if APP_LAYER_PARSER_EOF is set */
@ -2845,6 +2988,62 @@ static AppLayerResult SSLDecode(Flow *f, uint8_t direction, void *alstate,
return APP_LAYER_OK ;
}
/* tls event content readiness: everything the logger may emit must be
* final . cert0 fields are final as soon as any certificate decoded
* into the slot - a later undecodable one in the same message does not
* invalidate them ( base parity : the old completion teleport logged on
* fields alone ) . Where fields stay empty ( resumption , a fully - garbage
* chain ) , the track advance beyond the certificate phase makes the
* data final ; a track stuck below it can only end at close , where the
* end - of - file pass logs . The cert_data_incomplete flag is not needed
* here : it only gates phase advancement , and loggers run between
* parses , never during one . The client certificate decision must also
* be settled : the standard flight order puts the CertificateRequest
* after the server Certificate , so server content readiness alone can
* precede it - logging there would miss the client certificate
* content and the decoder events a client flight may still raise ( the
* TLS tx logs once ; base logged at server flight end , where both were
* included ) . The decision is settled by the NEED_CLIENT_CERT flag , by
* any message at or past the CertificateRequest position ( server
* flight : CertificateRequest , ServerHelloDone , Finished ; client
* flight : its Certificate or ClientKeyExchange - flag
* SERVER_FLIGHT_DECIDED ) , by a change cipher spec record , or by the
* client ' s first application data - a TLS 1.3 flight is encrypted
* past the ServerHello , so its encrypted records are the mid - flow
* settlement signal there ( anything else leaves the log to close ,
* the generic release through SERVER_FINISHED ) . The mTLS branch is
* separate and unaffected . */
static bool TlsConnpLogReady ( const SSLStateConnp * connp , const uint8_t track_done )
{
if ( connp - > cert0_subject & & connp - > cert0_issuerdn ) {
return true ;
}
return track_done ;
}
bool SSLV3TxLogReady ( void * tx )
{
SSLState * ssl_state = ( SSLState * ) tx ;
if ( ! TlsConnpLogReady (
& ssl_state - > server_connp , ssl_state - > server_state > = TLS_STATE_SERVER_DATA ) ) {
return false ;
}
if ( ssl_state - > flags & SSL_AL_FLAG_NEED_CLIENT_CERT ) {
if ( ! TlsConnpLogReady (
& ssl_state - > client_connp , ssl_state - > client_state > = TLS_STATE_CLIENT_DATA ) ) {
return false ;
}
} else if ( ( ssl_state - > flags &
( SSL_AL_FLAG_SERVER_FLIGHT_DECIDED | SSL_AL_FLAG_CHANGE_CIPHER_SPEC ) ) = = 0 & &
ssl_state - > server_state < TLS_STATE_SERVER_FINISHED & &
ssl_state - > client_state < TLS_STATE_CLIENT_DATA ) {
/* a CertificateRequest may still arrive in this flight */
return false ;
}
return true ;
}
static AppLayerResult SSLParseClientRecord ( Flow * f , void * alstate , AppLayerParserState * pstate ,
StreamSlice stream_slice , void * local_data )
{