From ae562df5dbf3a32cfdf974086201f6d3d13a6ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se> Date: Sat, 27 Jun 1998 00:25:02 +0200 Subject: [PATCH] Fix for Bleichenbacher's chosen ciphertext attack. Basically, don't send an ALERT-messages immediately if decryption of the session key failes. Continue handshaking as if nothing is wrong. Either some other invalid message is recieved, and handshaking failes at that time, or the client sends a change cipher message, followed by a completely garbled finished-message (as the server and client will not be using the same keys), or the client will wait for ever for an answer. Rev: lib/modules/SSL.pmod/handshake.pike:1.9 --- lib/modules/SSL.pmod/handshake.pike | 70 +++++++++++++++++++---------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/lib/modules/SSL.pmod/handshake.pike b/lib/modules/SSL.pmod/handshake.pike index d3aa4d8c78..56e597600e 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; -- GitLab