/* ========= ClientKeyExchange ========= */ int ssl3_decode_client_key_exchange( DSSL_Session* sess, u_char* data, uint32_t len ) { EVP_PKEY *pk = NULL; u_char* org_data = data; uint32_t org_len = len; int pms_len = 0; int rc = DSSL_RC_OK; if( sess->version < SSL3_VERSION || sess->version > TLS1_2_VERSION ) { return NM_ERROR( DSSL_E_SSL_UNKNOWN_VERSION ); } /* TLS is different as it sends the record length, while SSL3 implementaions don't (due to a bug in Netscape implementation) */ if( sess->version > SSL3_VERSION ) { uint16_t recLen = 0; if( !IS_ENOUGH_LENGTH( org_data, org_len, data, 2 ) ) { return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); } recLen = MAKE_UINT16( data[0], data[1] ); if( len != (uint32_t)recLen + 2 ) { /*TODO: set an option to tolerate this bug?*/ return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); } /* advance */ data += len - recLen; len = recLen; } if( !IS_ENOUGH_LENGTH( org_data, org_len, data, SSL_MAX_MASTER_KEY_LENGTH ) ) { return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); } 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) { _ASSERT( sess->last_packet); pk = ssls_try_ssl_keys( sess, data, len ); /* 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) { ssls_register_missing_key_server( sess ); return NM_ERROR( DSSL_E_SSL_SERVER_KEY_UNKNOWN ); } if(pk->type != EVP_PKEY_RSA) return NM_ERROR( DSSL_E_SSL_CANNOT_DECRYPT_NON_RSA ); pms_len = RSA_private_decrypt( len, data, sess->PMS, pk->pkey.rsa, RSA_PKCS1_PADDING ); if( pms_len != SSL_MAX_MASTER_KEY_LENGTH ) { return NM_ERROR( DSSL_E_SSL_CORRUPTED_PMS ); } if( MAKE_UINT16( sess->PMS[0], sess->PMS[1] ) != sess->client_version ) { return NM_ERROR( DSSL_E_SSL_PMS_VERSION_ROLLBACK ); } rc = ssls_decode_master_secret( sess ); OPENSSL_cleanse(sess->PMS, sizeof(sess->PMS) ); if( rc != DSSL_RC_OK ) return rc; rc = ssls_generate_keys( sess ); if( rc == DSSL_RC_OK ) { ssls_store_session( sess ); } return rc; }
/* ========== 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; }