diff --git a/lib/modules/SSL.pmod/handshake.pike b/lib/modules/SSL.pmod/handshake.pike index 234167aa53a6e5d2ae01249d7fa8986a2983ca6f..2ca493df93bd7fa02fec23629c990673b4b675a8 100644 --- a/lib/modules/SSL.pmod/handshake.pike +++ b/lib/modules/SSL.pmod/handshake.pike @@ -1,4 +1,4 @@ -/* $Id: handshake.pike,v 1.12 1999/03/03 14:15:24 nisse Exp $ +/* $Id: handshake.pike,v 1.13 1999/03/09 15:07:41 nisse Exp $ * */ @@ -36,8 +36,11 @@ int expect_change_cipher; /* Reset to 0 if a change_cipher message is object temp_key; /* Key used for session key exchange (if not the same * as the server's certified key) */ +object dh_state; /* For diffie-hellman key exchange */ + int rsa_message_was_bad; + int reuse; string my_random; @@ -80,6 +83,52 @@ object server_hello_packet() return handshake_packet(HANDSHAKE_server_hello, data); } +object server_key_exchange_packet() +{ + object struct; + + switch (session->ke_method) + { + case KE_rsa: + temp_key = (session->cipher_spec->is_exportable + ? context->short_rsa + : context->long_rsa); + if (temp_key) + { + /* Send a ServerKeyExchange message. */ + +#ifdef SSL3_DEBUG + werror(sprintf("Sending a server key exchange-message, " + "with a %d-bits key.\n", temp_key->rsa_size())); +#endif + struct = Struct(); + struct->put_bignum(temp_key->n); + struct->put_bignum(temp_key->e); + } + else + return 0; + break; + case KE_dhe_dss: + case KE_dhe_rsa: + case KE_dh_anon: + struct = Struct(); + + dh_state = dh_key_exchange(context->dh_params); + dh_state->new_secret(); + + struct->put_bignum(context->dh_params->p); + struct->put_bignum(context->dh_params->g); + struct->put_bignum(dh_state->our); + break; + default: + return 0; + } + + session->cipher_spec->sign(context, other_random + my_random, struct); + return handshake_packet(HANDSHAKE_server_key_exchange, + struct->pop_data()); +} + int reply_new_session(array(int) cipher_suites, array(int) compression_methods) { reuse = 0; @@ -134,39 +183,11 @@ int reply_new_session(array(int) cipher_suites, array(int) compression_methods) struct->put_var_string(cert, 3); send_packet(handshake_packet(HANDSHAKE_certificate, struct->pop_data())); } - temp_key = (session->cipher_spec->is_exportable - ? context->short_rsa - : context->long_rsa); - if (temp_key) - { - /* Send a ServerKeyExchange message. */ - -#ifdef SSL3_DEBUG - werror(sprintf("Sending a server key exchange-message, " - "with a %d-bits key.\n", temp_key->rsa_size())); -#endif - object struct = Struct(); - struct->put_bignum(temp_key->n); - struct->put_bignum(temp_key->e); - - /* Exactly how is the signature process defined? */ - string params = other_random + my_random + struct->contents(); - string digest = Crypto.md5()->update(params)->digest() - + Crypto.sha()->update(params)->digest(); + object key_exchange = server_key_exchange_packet(); - object s = context->rsa->raw_sign(digest); -#ifdef SSL3_DEBUG - werror(sprintf(" Digest: '%O'\n" - " Signature: '%O'\n", - digest, s->digits(256))); -#endif - - struct->put_bignum(s); - - send_packet(handshake_packet(HANDSHAKE_server_key_exchange, - struct->pop_data())); - } + if (key_exchange) + send_packet(key_exchange); if (context->auth_level >= AUTHLEVEL_ask) { @@ -207,7 +228,8 @@ object finished_packet(string sender) string server_derive_master_secret(string data) { - string res = ""; + string premaster_secret; + #ifdef SSL3_DEBUG werror(sprintf("server_derive_master_secret: ke_method %d\n", session->ke_method)); @@ -216,23 +238,56 @@ string server_derive_master_secret(string data) { default: throw( ({ "SSL.handshake: internal error\n", backtrace() }) ); +#if 0 + /* What is this for? */ case 0: return 0; +#endif case KE_dhe_dss: - throw( ({ "Not implemented.\n", backtrace() }) ); - + case KE_dhe_rsa: + if (!strlen(data)) + { + /* Implicit encoding; Should never happen unless we have + * requested and received a client certificate of type + * rsa_fixed_dh or dss_fixed_dh. Not supported. */ + werror("SSL.handshake: Client uses implicit encoding if its DH-value.\n" + " Hanging up.\n"); + send_packet(Alert(ALERT_fatal, ALERT_certificate_unknown)); + return 0; + } + /* Fall through */ + case KE_dh_anon: + { + /* Explicit encoding */ + object struct = Struct(data); + + if (catch + { + dh_state->set_other(struct->get_bignum); + } || !struct->is_empty()) + { + send_packet(Alert(ALERT_fatal, ALERT_unexpected_message)); + return 0; + } + + premaster_secret = dh_state->get_shared(); + dh_state = 0; + break; + } case KE_rsa: { - /* Decrypt the pre_master_secret */ + /* Decrypt the premaster_secret */ #ifdef SSL3_DEBUG werror(sprintf("encrypted premaster_secret: '%O'\n", data)); #endif // trace(1); - string s = (temp_key || context->rsa)->decrypt(data); + premaster_secret = (temp_key || context->rsa)->decrypt(data); #ifdef SSL3_DEBUG - werror(sprintf("premaster_secret: '%O'\n", s)); + werror(sprintf("premaster_secret: '%O'\n", premaster_secret)); #endif - if (!s || (strlen(s) != 48) || (s[0] != 3)) + if (!premaster_secret + || (strlen(premaster_secret) != 48) + || (premaster_secret[0] != 3)) { /* To avoid the chosen ciphertext attack discovered by Daniel @@ -244,26 +299,30 @@ string server_derive_master_secret(string data) werror("SSL.handshake: Invalid premaster_secret! " "A chosen ciphertext attack?\n"); - s = context->random(48); + premaster_secret = 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) + if (premaster_secret[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) - res += md5->hash_raw(s + sha->hash_raw(cookie + s + - other_random + my_random)); break; } } + string res = ""; + + object sha = mac_sha(); + object md5 = mac_md5(); + foreach( ({ "A", "BB", "CCC" }), string cookie) + res += md5->hash_raw(premaster_secret + + sha->hash_raw(cookie + premaster_secret + + other_random + my_random)); + #ifdef SSL3_DEBUG -// werror(sprintf("master: '%O'\n", res)); + werror(sprintf("master: '%O'\n", res)); #endif return res; } @@ -484,7 +543,7 @@ int handle_handshake(int type, string data, string raw) if (!(session->master_secret = server_derive_master_secret(data))) { - throw( ({ "SSL.handshake: internal error\n", backtrace() }) ); + return -1; } else { // trace(1);