/* ========== SERVER-FINISHED ========== */ static int ssl2_decode_server_finished( DSSL_Session* sess, u_char* data, uint32_t len, uint32_t* processed ) { _ASSERT( processed && data && sess ); if( len > sizeof( sess->session_id ) ) { return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); } /* set new session ID and add the session to the session cache */ memset( sess->session_id, 0, sizeof(sess->session_id ) ); memcpy( sess->session_id, data, len ); ssls_store_session( sess ); /* handshake is over, time to switch to application data protocol */ sess->c_dec.state = SS_Established; sess->s_dec.state = SS_Established; ssls_handshake_done( sess ); *processed = len; return DSSL_RC_OK; }
/* ========== Handshake decoding function ========== */ int ssl3_decode_handshake_record( dssl_decoder_stack* stack, NM_PacketDir dir, u_char* data, uint32_t len, uint32_t* processed ) { int rc = DSSL_E_UNSPECIFIED_ERROR; uint32_t recLen = 0; u_char hs_type = 0; u_char* org_data = data; DSSL_Session* sess = stack->sess; _ASSERT( processed != NULL ); _ASSERT((sess->flags & SSF_SSLV2_CHALLENGE) == 0); if( sess->version == 0 ) { return ssl_decode_first_client_hello( sess, data, len, processed ); } if( len < SSL3_HANDSHAKE_HEADER_LEN ) return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); DEBUG_TRACE_BUF("handshake", data, len); recLen = (((int32_t)data[1]) << 16) | (((int32_t)data[2]) << 8) | data[3]; hs_type = data[0]; data += SSL3_HANDSHAKE_HEADER_LEN; len -= SSL3_HANDSHAKE_HEADER_LEN; if( len < recLen )return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); #ifdef NM_TRACE_SSL_HANDSHAKE DEBUG_TRACE2( "===>Decoding SSL v3 handshake: %s len: %d...", SSL3_HandshakeTypeToString( hs_type ), (int) recLen ); #endif switch( hs_type ) { case SSL3_MT_HELLO_REQUEST: rc = ssl3_decode_dummy( sess, data, recLen ); break; case SSL3_MT_CLIENT_HELLO: rc = ssl3_decode_client_hello( sess, data, recLen ); break; case SSL3_MT_SERVER_HELLO: stack->state = SS_SeenServerHello; rc = ssl3_decode_server_hello( sess, data, recLen ); break; case SSL3_MT_CERTIFICATE: if( dir == ePacketDirFromServer ) { rc = ssl3_decode_server_certificate( sess, data, recLen ); } else { rc = ssl3_decode_dummy( sess, data, recLen ); } break; case SSL3_MT_SERVER_DONE: rc = ssl3_decode_dummy( sess, data, recLen ); break; case SSL3_MT_CLIENT_KEY_EXCHANGE: rc = ssl3_decode_client_key_exchange( sess, data, recLen ); break; case SSL3_MT_FINISHED: rc = (*sess->decode_finished_proc)( sess, dir, data, recLen ); if( rc == DSSL_RC_OK ) { stack->state = SS_Established; ssls_handshake_done( sess ); } break; case SSL3_MT_CERTIFICATE_STATUS: rc = ssl3_decode_dummy( sess, data, recLen ); break; case SSL3_MT_SERVER_KEY_EXCHANGE: /*at this point it is clear that the session is not decryptable due to ephemeral keys usage.*/ rc = NM_ERROR( DSSL_E_SSL_CANNOT_DECRYPT_EPHEMERAL ); break; case SSL3_MT_CERTIFICATE_REQUEST: /* TODO: track CertificateRequest- client certificate / certificate verify */ rc = ssl3_decode_dummy( sess, data, recLen ); break; case SSL3_MT_CERTIFICATE_VERIFY: /* TODO: track CertificateRequest- client certificate / certificate verify */ rc = ssl3_decode_dummy( sess, data, recLen ); break; case SSL3_MT_NEWSESSION_TICKET: rc = ssl3_decode_new_session_ticket( sess, data, recLen ); break; default: rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR ); break; } if( rc == DSSL_RC_OK ) { *processed = recLen + SSL3_HANDSHAKE_HEADER_LEN; if( hs_type == SSL3_MT_CLIENT_HELLO ) { ssl3_init_handshake_digests( sess ); } if( hs_type != SSL3_MT_HELLO_REQUEST ) { ssl3_update_handshake_digests( sess, org_data, *processed ); } } #ifdef NM_TRACE_SSL_HANDSHAKE if( rc == DSSL_RC_OK ) { DEBUG_TRACE0( "OK\n" ); } else { DEBUG_TRACE1( "Error! (%d)\n", (int)rc ); } #endif return rc; }