int ssl3_change_cipher_spec_decoder( void* decoder_stack, NM_PacketDir dir, u_char* data, uint32_t len, uint32_t* processed ) { dssl_decoder_stack* stack = (dssl_decoder_stack*) decoder_stack; /* unused parameters */ dir; /* check packet data to comply to CSS protocol */ if( len != 1 ) return NM_ERROR( NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ) ); if(data[0] != 1 ) return NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR ); *processed = 1; return dssl_decoder_stack_flip_cipher( stack ); }
/* ========== CLIENT-MASTER-KEY ========== */ static int ssl2_decode_client_master_key( DSSL_Session* sess, u_char* data, uint32_t len, uint32_t* processed ) { int rc = DSSL_RC_OK; uint16_t clearKeyLen = 0; uint16_t encKeyLen = 0; uint16_t keyArgLen = 0; u_char* pClearKey = NULL; u_char* pEncKey = NULL; u_char* pKeyArg = NULL; _ASSERT( processed && data && sess ); if( len < SSL20_CLIENT_MASTER_KEY_MIN_LEN ) { return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); } /* CIPHER-KIND - convert to 2 byte DSSL_Session::cipher_suite */ rc = DSSL_ConvertSSL2CipherSuite( data, &sess->cipher_suite ); /* CLEAR-KEY-LENGTH, ENCRYPTED-KEY-LENGTH, KEY-ARG-LENGTH */ if( rc == DSSL_RC_OK ) { clearKeyLen = MAKE_UINT16( data[3], data[4] ); encKeyLen = MAKE_UINT16( data[5], data[6] ); keyArgLen = MAKE_UINT16( data[7], data[8] ); if( len != (uint32_t)clearKeyLen + encKeyLen + keyArgLen + SSL20_CLIENT_MASTER_KEY_MIN_LEN ) { rc = NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); } *processed = len; } /* reconstitute the master secret */ if( rc == DSSL_RC_OK ) { EVP_PKEY *pk = NULL; pClearKey = data + SSL20_CLIENT_MASTER_KEY_MIN_LEN; pEncKey = pClearKey + clearKeyLen; pKeyArg = pEncKey + encKeyLen; if( clearKeyLen ) { memcpy( sess->master_secret, pClearKey, clearKeyLen ); } pk = ssls_get_session_private_key( sess ); /* if SSL server key is not found, try to find a matching one from the key pool */ if(pk == NULL) { u_char buff[1024]; _ASSERT( sess->last_packet); memcpy(buff, pEncKey, encKeyLen); pk = ssls_try_ssl_keys( sess, pEncKey, encKeyLen ); /* if a matching key found, register it with the server IP:port */ if(pk != NULL) { if( ssls_register_ssl_key( sess, pk ) == DSSL_RC_OK) { /* ssls_register_ssl_key clones the key, query the key back */ //pk = ssls_get_session_private_key( sess ); } else { pk = NULL; } } } if( pk ) { uint32_t encLen2 = RSA_private_decrypt( encKeyLen, pEncKey, sess->master_secret + clearKeyLen, pk->pkey.rsa, RSA_PKCS1_PADDING ); if( clearKeyLen + encLen2 >= sizeof( sess->master_secret ) ) { rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR ); } sess->master_key_len = clearKeyLen + encLen2; } else { rc = NM_ERROR( DSSL_E_SSL_SERVER_KEY_UNKNOWN ); ssls_register_missing_key_server( sess ); } } /* generate session keys */ if( rc == DSSL_RC_OK ) { rc = ssls2_generate_keys( sess, pKeyArg, keyArgLen ); } /* turn on new ciphers */ if( rc == DSSL_RC_OK ) { rc = dssl_decoder_stack_flip_cipher( &sess->c_dec ); if (rc == DSSL_RC_OK ) { rc = dssl_decoder_stack_flip_cipher( &sess->s_dec ); } } return rc; }
/* ========== SERVER-HELLO ========== */ static int ssl2_decode_server_hello( DSSL_Session* sess, u_char* data, uint32_t len, uint32_t* processed ) { int rc = DSSL_RC_OK; uint16_t certLen = 0; uint16_t cipherSpecLen = 0; uint16_t connectionIdLen = 0; int session_id_hit = 0; _ASSERT( processed && data && sess ); if( len < SSL20_SERVER_HELLO_MIN_LEN ) { return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); } /* check SESSION-ID-HIT */ session_id_hit = data[0]; /* decode CERTIFICATE-TYPE */ if( rc == DSSL_RC_OK && (data[1] && data[1] != SSL2_CT_X509_CERTIFICATE) ) { rc = NM_ERROR( DSSL_E_SSL2_INVALID_CERTIFICATE_TYPE ); } /* SERVER-VERSION*/ /* TODO: add server version check */ /* CERTIFICATE-LENGTH, CIPHER-SPECS-LENGTH, CONNECTION-ID-LENGTH */ if( rc == DSSL_RC_OK ) { certLen = MAKE_UINT16( data[4], data[5] ); cipherSpecLen = MAKE_UINT16( data[6], data[7] ); connectionIdLen = MAKE_UINT16( data[8], data[9] ); if( (uint32_t)certLen + cipherSpecLen + connectionIdLen + SSL20_SERVER_HELLO_MIN_LEN != len ) { rc = NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); } else if( connectionIdLen < 16 || connectionIdLen > 32 ) { rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR ); } if( rc == DSSL_RC_OK ) { u_char* connIdData = data + SSL20_SERVER_HELLO_MIN_LEN + certLen + cipherSpecLen; sess->server_connection_id_len = connectionIdLen; memset( sess->server_random, 0, sizeof(sess->server_random) ); memcpy( sess->server_random, connIdData, connectionIdLen ); } } /* TODO: Check the certificate to match what DSSL has been initialized with */ if( rc == DSSL_RC_OK ) { } if( session_id_hit ) { if( sess->flags & SSF_CLIENT_SESSION_ID_SET ) { rc = ssls_lookup_session( sess ); /* re-generate the session keys and turn on ciphers right away */ if( rc == DSSL_RC_OK) { rc = ssls2_generate_keys( sess, sess->ssl2_key_arg, sess->ssl2_key_arg_len ); } /* turn on new ciphers */ if( rc == DSSL_RC_OK ) { rc = dssl_decoder_stack_flip_cipher( &sess->c_dec ); if (rc == DSSL_RC_OK ) { rc = dssl_decoder_stack_flip_cipher( &sess->s_dec ); } } } else { /* client didn't send the session id */ rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR ); } } if( rc == DSSL_RC_OK ) { *processed = certLen + cipherSpecLen + connectionIdLen + SSL20_SERVER_HELLO_MIN_LEN; } return rc; }