/* ========== 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; }
/* ========= 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; }