diff --git a/lib/modules/SSL.pmod/handshake.pike b/lib/modules/SSL.pmod/handshake.pike index d3aa4d8c78004813feb766eb7967d57d8aa0d9eb..56e597600e9e5d39617061834d41e23063deb457 100644 --- a/lib/modules/SSL.pmod/handshake.pike +++ b/lib/modules/SSL.pmod/handshake.pike @@ -1,4 +1,4 @@ -/* $Id: handshake.pike,v 1.8 1998/04/21 21:28:57 grubba Exp $ +/* $Id: handshake.pike,v 1.9 1998/06/26 22:25:02 nisse Exp $ * */ @@ -32,6 +32,8 @@ int certificate_state; int expect_change_cipher; /* Reset to 0 if a change_cipher message is received */ +int rsa_message_was_bad; + int reuse; string my_random; @@ -194,9 +196,27 @@ string server_derive_master_secret(string data) werror(sprintf("premaster_secret: '%O'\n", s)); #endif if (!s || (strlen(s) != 48) || (s[0] != 3)) - return 0; - if (s[1] > 0) - werror("SSL.handshake: Newer version detected in key exchange message.\n"); + { + + /* To avoid the chosen ciphertext attack discovered by Daniel + * Bleichenbacher, it is essential not to send any error * + * messages back to the client until after the client's * + * Finished-message (or some other invalid message) has been * + * recieved. */ + + werror("SSL.handshake: Invalid premaster_secret! " + "A chosen ciphertext attack?\n"); + + s = context->random(48); + rsa_message_was_bad = 1; + + } else { + /* FIXME: When versions beyond 3.0 are supported, + * the version number here must be checked more carefully + * for a version rollback attack. */ + if (s[1] > 0) + werror("SSL.handshake: Newer version detected in key exchange message.\n"); + } object sha = mac_sha(); object md5 = mac_md5(); foreach( ({ "A", "BB", "CCC" }), string cookie) @@ -231,7 +251,8 @@ int handle_handshake(int type, string data, string raw) /* Reset all extra state variables */ expect_change_cipher = certificate_state = 0; - + rsa_message_was_bad = 0; + handshake_messages = raw; my_random = sprintf("%4c%s", time(), context->random(28)); @@ -268,7 +289,7 @@ int handle_handshake(int type, string data, string raw) "extra data in hello message ignored\n"); if (version[1] > 0) - werror(sprintf("SSL.connection->handle_handshake: " + werror(sprintf("SSL.handshake->handle_handshake: " "Version %d.%d hello detected\n", @version)); #ifdef SSL3_DEBUG @@ -379,7 +400,8 @@ int handle_handshake(int type, string data, string raw) send_packet(Alert(ALERT_fatal, ALERT_unexpected_message)); return -1; } - if (my_digest != digest) + if (rsa_message_was_bad /* Error delayed until now */ + || (my_digest != digest)) { send_packet(Alert(ALERT_fatal, ALERT_unexpected_message)); return -1; @@ -421,24 +443,21 @@ int handle_handshake(int type, string data, string raw) backtrace())); return -1; } + if (!(session->master_secret = server_derive_master_secret(data))) { + throw( ({ "SSL.handshake: internal error\n", backtrace() }) ); + } else { + + // trace(1); + array res = session->new_server_states(other_random, my_random); + pending_read_state = res[0]; + pending_write_state = res[1]; + #ifdef SSL3_DEBUG - werror("server_derive_master_secret failed!\n"); + werror(sprintf("certificate_state: %d\n", certificate_state)); #endif - send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, - "SSL.session->handle_handshake: unexpected message\n", - backtrace())); - return -1; } - // trace(1); - array res = session->new_server_states(other_random, my_random); - pending_read_state = res[0]; - pending_write_state = res[1]; - -#ifdef SSL3_DEBUG - werror(sprintf("certificate_state: %d\n", certificate_state)); -#endif if (certificate_state != CERT_received) { handshake_state = STATE_server_wait_for_finish; @@ -481,10 +500,13 @@ int handle_handshake(int type, string data, string raw) backtrace())); return -1; case HANDSHAKE_certificate_verify: - session->client_challenge = - mac_md5(session->master_secret)->hash_master(handshake_messages) + - mac_sha(session->master_secret)->hash_master(handshake_messages); - session->client_signature = data; + if (!rsa_message_was_bad) + { + session->client_challenge = + mac_md5(session->master_secret)->hash_master(handshake_messages) + + mac_sha(session->master_secret)->hash_master(handshake_messages); + session->client_signature = data; + } handshake_messages += raw; handshake_state = STATE_server_wait_for_finish; expect_change_cipher = 1;