diff --git a/lib/modules/SSL.pmod/connection.pike b/lib/modules/SSL.pmod/connection.pike index 8fc0ca26016172ec72d3b10b0c070591ec24edb3..3a698dcfac897dc9f2aabdb23d1be0b7f493f753 100644 --- a/lib/modules/SSL.pmod/connection.pike +++ b/lib/modules/SSL.pmod/connection.pike @@ -200,10 +200,10 @@ int send_streaming_data (string data) if (!sizeof(data)) return 0; Packet packet = Packet(); packet->content_type = PACKET_application_data; - int max_packet_size = current_write_state->session->max_packet_size; + int max_packet_size = session->max_packet_size; int size; if ((!sent) && (version < PROTOCOL_TLS_1_1) && - (current_write_state->session->cipher_spec->cipher_type == + (session->cipher_spec->cipher_type == CIPHER_block)) { // Workaround for the BEAST attack. // This method is known as the 1/(n-1) split: diff --git a/lib/modules/SSL.pmod/handshake.pike b/lib/modules/SSL.pmod/handshake.pike index bd8ae5c92f3a7be2e8da8dc56cb2bf60a2757b1c..7b0b626fc648550f66f2a4c32b2c6ac5bd4f0360 100644 --- a/lib/modules/SSL.pmod/handshake.pike +++ b/lib/modules/SSL.pmod/handshake.pike @@ -402,7 +402,7 @@ Packet client_key_exchange_packet() } array(.state) res = - session->new_client_states(client_random, server_random, version); + session->new_client_states(this, client_random, server_random, version); pending_read_state = res[0]; pending_write_state = res[1]; @@ -1159,7 +1159,8 @@ int(-1..1) handle_handshake(int type, string(0..255) data, string(0..255) raw) array(.state) res; mixed err; - if( err = catch(res = session->new_server_states(client_random, + if( err = catch(res = session->new_server_states(this, + client_random, server_random, version)) ) { @@ -1309,7 +1310,8 @@ int(-1..1) handle_handshake(int type, string(0..255) data, string(0..255) raw) // trace(1); array(.state) res = - session->new_server_states(client_random, server_random, version); + session->new_server_states(this, client_random, server_random, + version); pending_read_state = res[0]; pending_write_state = res[1]; diff --git a/lib/modules/SSL.pmod/session.pike b/lib/modules/SSL.pmod/session.pike index cf995d8ee8d67d06d6a9a138acf83bb886c95c0d..1c8d050aaa9acb8aac7b83acb97d06778d08686b 100644 --- a/lib/modules/SSL.pmod/session.pike +++ b/lib/modules/SSL.pmod/session.pike @@ -601,12 +601,13 @@ array(string(0..255)) generate_keys(string(0..255) client_random, //! @elem SSL.state write_state //! Write state //! @endarray -array(.state) new_server_states(string(0..255) client_random, +array(.state) new_server_states(object/*(connection)*/ con, + string(0..255) client_random, string(0..255) server_random, ProtocolVersion version) { - .state write_state = .state(this); - .state read_state = .state(this); + .state write_state = .state(con); + .state read_state = .state(con); array(string) keys = generate_keys(client_random, server_random, version); if (cipher_spec->mac_algorithm) @@ -676,12 +677,13 @@ array(.state) new_server_states(string(0..255) client_random, //! @elem SSL.state write_state //! Write state //! @endarray -array(.state) new_client_states(string(0..255) client_random, +array(.state) new_client_states(object/*(connection)*/ con, + string(0..255) client_random, string(0..255) server_random, ProtocolVersion version) { - .state write_state = .state(this); - .state read_state = .state(this); + .state write_state = .state(con); + .state read_state = .state(con); array(string) keys = generate_keys(client_random, server_random, version); if (cipher_spec->mac_algorithm) diff --git a/lib/modules/SSL.pmod/state.pike b/lib/modules/SSL.pmod/state.pike index c7f71820a1c635def5036ad13e0836a7eed64281..ba06cd1ebe3f3853715200cafebd929b0b9529e1 100644 --- a/lib/modules/SSL.pmod/state.pike +++ b/lib/modules/SSL.pmod/state.pike @@ -9,13 +9,19 @@ import .Constants; -protected void create(object/*(.session)*/ s) +//! +constant Alert = .alert; + +function(int, int, string|void: Alert) alert; + +protected void create(object/*(.connection)*/ con) { - session = s; + connection = con; + alert = con->Alert; } //! Information about the used algorithms. -object/*(.session)*/ session; +object/*(.connection)*/ connection; //! Message Authentication Code .Cipher.MACAlgorithm mac; @@ -28,9 +34,6 @@ object compress; //! 64-bit sequence number. int seq_num = 0; /* Bignum, values 0, .. 2^64-1 are valid */ -//! -constant Alert = .alert; - //! TLS IV prefix length. int tls_iv; @@ -53,21 +56,21 @@ Alert|.packet decrypt_packet(.packet packet, ProtocolVersion version) * function, and attempt to make the same amount of work * even if we have already detected a failure. */ - object(Alert) alert; + object(Alert) fail; #ifdef SSL3_DEBUG_CRYPT werror("SSL.state->decrypt_packet (3.%d, type: %d): data = %O\n", version & 0xff, packet->content_type, packet->fragment); #endif - int hmac_size = session->truncated_hmac ? 10 : - session->cipher_spec?->hash_size; + int hmac_size = mac && (connection->session->truncated_hmac ? 10 : + connection->session->cipher_spec?->hash_size); int padding; if (crypt) { #ifdef SSL3_DEBUG_CRYPT - werror("SSL.state: Trying decrypt..\n"); + werror("SSL.state: Trying decrypt...\n"); // werror("SSL.state: The encrypted packet is:%O\n",packet->fragment); werror("sizeof of the encrypted packet is:"+sizeof(packet->fragment)+"\n"); #endif @@ -75,14 +78,16 @@ Alert|.packet decrypt_packet(.packet packet, ProtocolVersion version) string msg = packet->fragment; if (!msg) { packet->fragment = #string "alert.pike"; // Some junk data. - alert = Alert(ALERT_fatal, ALERT_unexpected_message, version); + fail = alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.state: Failed to get fragment.\n"); } else { - switch(session->cipher_spec->cipher_type) { + switch(connection->session->cipher_spec->cipher_type) { case CIPHER_stream: // If data is too small, we can safely abort early. if( sizeof(msg) < hmac_size+1 ) - return Alert(ALERT_fatal, ALERT_unexpected_message, version); + return alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.state: Too short message.\n"); msg = crypt->crypt(msg); break; @@ -92,21 +97,28 @@ Alert|.packet decrypt_packet(.packet packet, ProtocolVersion version) // If data is too small or doesn't match block size, we can // safely abort early. if( sizeof(msg) < hmac_size+1 || sizeof(msg) % crypt->block_size() ) - return Alert(ALERT_fatal, ALERT_unexpected_message, version); + return alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.state: Too short message.\n"); if(version == PROTOCOL_SSL_3_0) { // crypt->unpad() performs decrypt. if (catch { msg = crypt->unpad(msg, Crypto.PAD_SSL); }) - alert = Alert(ALERT_fatal, ALERT_unexpected_message, version); + fail = alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.state: Invalid padding.\n"); } else if (version >= PROTOCOL_TLS_1_0) { - if (catch { msg = crypt->unpad(msg, Crypto.PAD_TLS); }) - alert = Alert(ALERT_fatal, ALERT_unexpected_message, version); - else if (!msg) { +#ifdef SSL3_DEBUG_CRYPT + werror("SSL.state: Decrypted message: %O.\n", msg); +#endif + if (catch { msg = crypt->unpad(msg, Crypto.PAD_TLS); }) { + fail = alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.state: Invalid padding.\n"); + } else if (!msg) { // TLS 1.1 requires a bad_record_mac alert on invalid padding. // Note that mac will still be calculated below even if // padding was wrong, to mitigate Lucky Thirteen attacks. - alert = Alert(ALERT_fatal, ALERT_bad_record_mac, version); + fail = alert(ALERT_fatal, ALERT_bad_record_mac, + "SSL.state: Invalid padding.\n"); } } break; @@ -115,7 +127,7 @@ Alert|.packet decrypt_packet(.packet packet, ProtocolVersion version) // NB: Only valid in TLS 1.2 and later. // The message consists of explicit_iv + crypted-msg + digest. - string iv = salt + msg[..session->cipher_spec->explicit_iv_size-1]; + string iv = salt + msg[..connection->session->cipher_spec->explicit_iv_size-1]; int digest_size = crypt->digest_size(); string digest = msg[<digest_size-1..]; crypt->set_iv(iv); @@ -123,18 +135,16 @@ Alert|.packet decrypt_packet(.packet packet, ProtocolVersion version) seq_num, packet->content_type, packet->protocol_version, sizeof(msg) - - (session->cipher_spec->explicit_iv_size + + (connection->session->cipher_spec->explicit_iv_size + digest_size)); crypt->update(auth_data); - msg = crypt->crypt(msg[session->cipher_spec->explicit_iv_size.. + msg = crypt->crypt(msg[connection->session->cipher_spec->explicit_iv_size.. <digest_size]); seq_num++; if (digest != crypt->digest()) { // Bad digest. -#ifdef SSL3_DEBUG - werror("Failed AEAD-verification!!\n"); -#endif - alert = Alert(ALERT_fatal, ALERT_bad_record_mac, version); + fail = alert(ALERT_fatal, ALERT_bad_record_mac, + "Failed AEAD-verification!!\n"); } break; } @@ -176,7 +186,7 @@ Alert|.packet decrypt_packet(.packet packet, ProtocolVersion version) string pad_string = "\0"*block_size; string junk = pad_string[<padding-1..]; if (!((sizeof(packet->fragment) + - mac->hash_header_size - session->cipher_spec->hash_size) % + mac->hash_header_size - connection->session->cipher_spec->hash_size) % block_size ) || !(padding % block_size)) { // We're at the edge of a MAC block, so we need to @@ -196,7 +206,8 @@ Alert|.packet decrypt_packet(.packet packet, ProtocolVersion version) "Seqence number: %O\n", digest, mac->hash_packet(packet, seq_num), seq_num); #endif - alert = alert || Alert(ALERT_fatal, ALERT_bad_record_mac, version); + fail = fail || alert(ALERT_fatal, ALERT_bad_record_mac, + "Bad MAC.\n"); } seq_num++; } @@ -208,11 +219,12 @@ Alert|.packet decrypt_packet(.packet packet, ProtocolVersion version) #endif string msg = [string]compress(packet->fragment); if (!msg) - alert = alert || Alert(ALERT_fatal, ALERT_unexpected_message, version); + fail = fail || alert(ALERT_fatal, ALERT_unexpected_message, + "Invalid compression.\n"); packet->fragment = msg; } - if (alert) return alert; + if (fail) return fail; return [object(Alert)]packet->check_size(version) || packet; } @@ -230,14 +242,14 @@ Alert|.packet encrypt_packet(.packet packet, ProtocolVersion version) if (mac) { digest = mac->hash_packet(packet, seq_num); - if (session->truncated_hmac) + if (connection->session->truncated_hmac) digest = digest[..9]; } else digest = ""; if (crypt) { - switch(session->cipher_spec->cipher_type) { + switch(connection->session->cipher_spec->cipher_type) { case CIPHER_stream: packet->fragment=crypt->crypt(packet->fragment + digest); break; @@ -264,7 +276,8 @@ Alert|.packet encrypt_packet(.packet packet, ProtocolVersion version) // The nonce_explicit MAY be the 64-bit sequence number. // FIXME: Do we need to pay attention to threads here? string explicit_iv = - sprintf("%*c", session->cipher_spec->explicit_iv_size, seq_num); + sprintf("%*c", connection->session->cipher_spec->explicit_iv_size, + seq_num); crypt->set_iv(salt + explicit_iv); string auth_data = sprintf("%8c%c%2c%2c", seq_num, packet->content_type,