3709192002-03-20Martin Nilsson #pike __REAL_VERSION__
18c01f2004-01-25Martin Nilsson #pragma strict_types
e1fb092014-02-14Martin Nilsson #require constant(SSL.Cipher)
3709192002-03-20Martin Nilsson 
f5bb032001-09-17Martin Nilsson //! SSL.handshake keeps the state relevant for SSL handshaking. This //! includes a pointer to a context object (which doesn't change), various //! buffers, a pointer to a session object (reuse or created as //! appropriate), and pending read and write states being negotiated. //!
2f77da2013-11-23Henrik Grubbström (Grubba) //! Each connection will have two sets of read and write states: The
f5bb032001-09-17Martin Nilsson //! current read and write states used for encryption, and pending read //! and write states to be taken into use when the current keyexchange //! handshake is finished.
c79dc12001-06-14Pär Svensson  //#define SSL3_PROFILING
4f5e1d2003-01-27Martin Nilsson import .Constants;
33ef431997-03-13Niels Möller 
813b392000-08-04Andreas Sigfridsson #ifdef SSL3_DEBUG
6244142003-01-27Martin Nilsson #define SSL3_DEBUG_MSG(X ...) werror(X)
813b392000-08-04Andreas Sigfridsson #else /*! SSL3_DEBUG */
6244142003-01-27Martin Nilsson #define SSL3_DEBUG_MSG(X ...)
813b392000-08-04Andreas Sigfridsson #endif /* SSL3_DEBUG */
b6345f2004-01-23Martin Nilsson .session session; .context context;
33ef431997-03-13Niels Möller 
b6345f2004-01-23Martin Nilsson .state pending_read_state; .state pending_write_state;
33ef431997-03-13Niels Möller  /* State variables */
5e3a142014-04-30Martin Nilsson int handshake_state; // Constant.STATE_*
33ef431997-03-13Niels Möller 
da8a2c2011-01-10Henrik Grubbström (Grubba) int handshake_finished = 0;
33ef431997-03-13Niels Möller constant CERT_none = 0; constant CERT_requested = 1;
b1b57a1997-03-17Niels Möller constant CERT_received = 2;
33ef431997-03-13Niels Möller constant CERT_no_certificate = 3; int certificate_state;
da12091998-08-26Niels Möller int expect_change_cipher; /* Reset to 0 if a change_cipher message is * received */
9d05912013-12-31Henrik Grubbström (Grubba) multiset(int) remote_extensions = (<>);
87740f2011-01-10Henrik Grubbström (Grubba) // RFC 5746-related fields int secure_renegotiation;
ca94982013-12-08Henrik Grubbström (Grubba) string(0..255) client_verify_data = ""; string(0..255) server_verify_data = ""; // 3.2: Initially of zero length for both the // ClientHello and the ServerHello.
87740f2011-01-10Henrik Grubbström (Grubba) 
2f77da2013-11-23Henrik Grubbström (Grubba) //! The active @[Cipher.KeyExchange] (if any). .Cipher.KeyExchange ke;
33ef431997-03-13Niels Möller 
68b67e2014-04-05Henrik Grubbström (Grubba) ProtocolVersion version; ProtocolVersion client_version; /* Used to check for version roll-back attacks. */
33ef431997-03-13Niels Möller int reuse;
3af33b2011-12-15Henrik Grubbström (Grubba) //! A few storage variables for client certificate handling on the client side.
88cfa12005-10-28H. William Welliver III array(int) client_cert_types;
ca94982013-12-08Henrik Grubbström (Grubba) array(string(0..255)) client_cert_distinguished_names;
88cfa12005-10-28H. William Welliver III 
f5bb032001-09-17Martin Nilsson //! Random cookies, sent and received with the hello-messages.
ca94982013-12-08Henrik Grubbström (Grubba) string(0..255) client_random; string(0..255) server_random;
33ef431997-03-13Niels Möller 
8dcd741997-03-15Niels Möller constant Session = SSL.session;
08afc72014-05-01Martin Nilsson #define Packet .Packet
47f84c2014-04-12Henrik Grubbström (Grubba) 
ee37502014-05-04Martin Nilsson .Alert Alert(int(1..2) level, int(0..255) description, string|void message)
47f84c2014-04-12Henrik Grubbström (Grubba) { // NB: We are always inherited by SSL.connection. return context->alert_factory(this, level, description, version,
74b5eb2014-04-24Martin Nilsson  message);
47f84c2014-04-12Henrik Grubbström (Grubba) }
33ef431997-03-13Niels Möller 
73cbaf2013-09-02Martin Nilsson int has_application_layer_protocol_negotiation;
ca94982013-12-08Henrik Grubbström (Grubba) string(0..255) next_protocol;
c79dc12001-06-14Pär Svensson 
47c33a2014-04-13Henrik Grubbström (Grubba) string(8bit) get_signature_algorithms() { ADT.struct sign_algs = ADT.struct(); foreach(sort(indices(HASH_lookup)), int h) { sign_algs->put_uint(h, 1); sign_algs->put_uint(SIGNATURE_rsa, 1); sign_algs->put_uint(h, 1); sign_algs->put_uint(SIGNATURE_dsa, 1); #if constant(Crypto.ECC.Curve) // NB: MD5 is not supported with ECDSA signatures. if (h != HASH_md5) { sign_algs->put_uint(h, 1); sign_algs->put_uint(SIGNATURE_ecdsa, 1); } #endif } return sign_algs->pop_data(); }
c79dc12001-06-14Pär Svensson #ifdef SSL3_PROFILING
bc15c22014-05-02Martin Nilsson System.Timer timer = System.Timer();
c79dc12001-06-14Pär Svensson void addRecord(int t,int s) {
bc15c22014-05-02Martin Nilsson  Stdio.stdout.write("time: %.6f sender: %d type: %s\n", timer->get(), s, fmt_constant(t, "HANDSHAKE"));
c79dc12001-06-14Pär Svensson } #endif
ca94982013-12-08Henrik Grubbström (Grubba) string(0..255) handshake_messages;
33ef431997-03-13Niels Möller 
ee37502014-05-04Martin Nilsson Packet handshake_packet(int(0..255) type, string data)
33ef431997-03-13Niels Möller {
c79dc12001-06-14Pär Svensson  #ifdef SSL3_PROFILING addRecord(type,1); #endif
33ef431997-03-13Niels Möller  /* Perhaps one need to split large packages? */
b6345f2004-01-23Martin Nilsson  Packet packet = Packet();
33ef431997-03-13Niels Möller  packet->content_type = PACKET_handshake;
ee37502014-05-04Martin Nilsson  packet->fragment = sprintf("%1c%3H", type, [string(0..255)]data);
33ef431997-03-13Niels Möller  handshake_messages += packet->fragment; return packet; }
18c01f2004-01-25Martin Nilsson Packet server_hello_packet()
33ef431997-03-13Niels Möller {
b6345f2004-01-23Martin Nilsson  ADT.struct struct = ADT.struct();
33ef431997-03-13Niels Möller  /* Build server_hello message */
68b67e2014-04-05Henrik Grubbström (Grubba)  struct->put_uint(version, 2); /* version */
77928b2014-04-05Henrik Grubbström (Grubba)  SSL3_DEBUG_MSG("Writing server hello, with version: %s\n", fmt_version(version));
813b392000-08-04Andreas Sigfridsson  struct->put_fix_string(server_random);
33ef431997-03-13Niels Möller  struct->put_var_string(session->identity, 1);
5a66b31998-04-20Niels Möller  struct->put_uint(session->cipher_suite, 2); struct->put_uint(session->compression_algorithm, 1);
33ef431997-03-13Niels Möller 
27e1172012-04-07Arne Goedeke  ADT.struct extensions = ADT.struct();
87740f2011-01-10Henrik Grubbström (Grubba) 
27e1172012-04-07Arne Goedeke  if (secure_renegotiation) {
87740f2011-01-10Henrik Grubbström (Grubba)  // RFC 5746 3.7: // The server MUST include a "renegotiation_info" extension // containing the saved client_verify_data and server_verify_data in // the ServerHello.
ce2e5e2011-01-11Henrik Grubbström (Grubba)  extensions->put_uint(EXTENSION_renegotiation_info, 2);
87740f2011-01-10Henrik Grubbström (Grubba)  ADT.struct extension = ADT.struct(); extension->put_var_string(client_verify_data + server_verify_data, 1); extensions->put_var_string(extension->pop_data(), 2); }
0dd4f82014-03-20Henrik Grubbström (Grubba)  if (session->max_packet_size != PACKET_MAX_SIZE) { // RFC 3546 3.2. ADT.struct extension = ADT.struct(); extension->put_uint(EXTENSION_max_fragment_length, 2); switch(session->max_packet_size) { case 512: extension->put_uint(FRAGMENT_512, 1); break; case 1024: extension->put_uint(FRAGMENT_1024, 1); break; case 2048: extension->put_uint(FRAGMENT_2048, 1); break; case 4096: extension->put_uint(FRAGMENT_4096, 1); break; default:
56e8852014-04-12Martin Nilsson  return Alert(ALERT_fatal, ALERT_illegal_parameter,
47f84c2014-04-12Henrik Grubbström (Grubba)  "Invalid fragment size.\n");
0dd4f82014-03-20Henrik Grubbström (Grubba)  } extensions->put_var_string(extension->pop_data(), 2); }
6a0e942014-02-02Henrik Grubbström (Grubba)  if (sizeof(session->ecc_curves) && remote_extensions[EXTENSION_ec_point_formats]) {
8d6ac22013-12-30Henrik Grubbström (Grubba)  // RFC 4492 5.2: // The Supported Point Formats Extension is included in a // ServerHello message in response to a ClientHello message // containing the Supported Point Formats Extension when // negotiating an ECC cipher suite. ADT.struct extension = ADT.struct(); extension->put_uint(POINT_uncompressed, 1); extension->put_var_string(extension->pop_data(), 1); extensions->put_uint(EXTENSION_ec_point_formats, 2); extensions->put_var_string(extension->pop_data(), 2); }
3db50f2014-03-23Henrik Grubbström (Grubba)  if (session->truncated_hmac) { // RFC 3546 3.5 "Truncated HMAC" extensions->put_uint(EXTENSION_truncated_hmac, 2); extensions->put_var_string("", 2); }
4b28272014-03-30Henrik Grubbström (Grubba)  if (session->heartbeat_mode) { // RFC 6520 ADT.struct extension = ADT.struct(); extension->put_uint(HEARTBEAT_MODE_peer_allowed_to_send, 1); extensions->put_uint(EXTENSION_heartbeat, 2); extensions->put_var_string(extension->pop_data(), 2); }
2542ed2013-09-03Martin Nilsson  if (has_application_layer_protocol_negotiation && next_protocol) {
63cfef2013-09-09Martin Nilsson  extensions->put_uint(EXTENSION_application_layer_protocol_negotiation,2);
2542ed2013-09-03Martin Nilsson  extensions->put_uint(sizeof(next_protocol)+3, 2); extensions->put_uint(sizeof(next_protocol)+1, 2); extensions->put_var_string(next_protocol, 1); }
27e1172012-04-07Arne Goedeke  if (!extensions->is_empty()) struct->put_var_string(extensions->pop_data(), 2);
33ef431997-03-13Niels Möller  string data = struct->pop_data(); return handshake_packet(HANDSHAKE_server_hello, data); }
b6345f2004-01-23Martin Nilsson Packet server_key_exchange_packet()
fada191999-03-09Niels Möller {
2f77da2013-11-23Henrik Grubbström (Grubba)  if (ke) error("KE!\n");
52d3e52013-12-29Henrik Grubbström (Grubba)  ke = session->ke_factory(context, session, this, client_version);
5277132013-11-24Henrik Grubbström (Grubba)  string data = ke->server_key_exchange_packet(client_random, server_random);
2f77da2013-11-23Henrik Grubbström (Grubba)  return data && handshake_packet(HANDSHAKE_server_key_exchange, data);
fada191999-03-09Niels Möller }
18c01f2004-01-25Martin Nilsson Packet client_key_exchange_packet()
813b392000-08-04Andreas Sigfridsson {
52d3e52013-12-29Henrik Grubbström (Grubba)  ke = ke || session->ke_factory(context, session, this, client_version);
5277132013-11-24Henrik Grubbström (Grubba)  string data = ke->client_key_exchange_packet(client_random, server_random, version);
2f77da2013-11-23Henrik Grubbström (Grubba)  if (!data) {
56e8852014-04-12Martin Nilsson  send_packet(Alert(ALERT_fatal, ALERT_unexpected_message,
74b5eb2014-04-24Martin Nilsson  "Invalid KEX.\n"));
813b392000-08-04Andreas Sigfridsson  return 0; }
bda8782013-10-26Henrik Grubbström (Grubba) 
5277132013-11-24Henrik Grubbström (Grubba)  array(.state) res =
b272d32014-04-27Henrik Grubbström (Grubba)  session->new_client_states(this, client_random, server_random, version);
bda8782013-10-26Henrik Grubbström (Grubba)  pending_read_state = res[0]; pending_write_state = res[1];
813b392000-08-04Andreas Sigfridsson  return handshake_packet(HANDSHAKE_client_key_exchange, data); }
7f41972014-04-10Martin Nilsson // FIXME: The certificate code has changed, so this no longer works, // if it ever did. #if 0
88cfa12005-10-28H. William Welliver III Packet certificate_verify_packet() { ADT.struct struct = ADT.struct();
c101832014-03-08Henrik Grubbström (Grubba)  // FIXME: This temporary context is probably not needed.
88cfa12005-10-28H. William Welliver III  .context cx = .context();
c101832014-03-08Henrik Grubbström (Grubba)  cx->private_key = context->private_key;
ceff2c2007-11-15H. William Welliver III 
88cfa12005-10-28H. William Welliver III  session->cipher_spec->sign(cx, handshake_messages, struct); return handshake_packet (HANDSHAKE_certificate_verify, struct->pop_data());
8d6ac22013-12-30Henrik Grubbström (Grubba) }
7f41972014-04-10Martin Nilsson #endif
8d6ac22013-12-30Henrik Grubbström (Grubba)  int(0..1) not_ecc_suite(int cipher_suite) { array(int) suite = [array(int)]CIPHER_SUITES[cipher_suite]; return suite && !(< KE_ecdh_ecdsa, KE_ecdhe_ecdsa, KE_ecdh_rsa, KE_ecdhe_rsa >)[suite[0]];
88cfa12005-10-28H. William Welliver III }
b6345f2004-01-23Martin Nilsson int(-1..0) reply_new_session(array(int) cipher_suites, array(int) compression_methods)
33ef431997-03-13Niels Möller {
0ca1e52013-10-21Martin Nilsson  SSL3_DEBUG_MSG("ciphers: me:\n%s, client:\n%s",
b3addf2014-02-12Martin Nilsson  .Constants.fmt_cipher_suites(context->preferred_suites), .Constants.fmt_cipher_suites(cipher_suites));
e9428a2013-10-21Martin Nilsson  cipher_suites = context->preferred_suites & cipher_suites;
0ca1e52013-10-21Martin Nilsson  SSL3_DEBUG_MSG("intersection:\n%s\n",
b3addf2014-02-12Martin Nilsson  .Constants.fmt_cipher_suites((array(int))cipher_suites));
813b392000-08-04Andreas Sigfridsson 
6a0e942014-02-02Henrik Grubbström (Grubba)  if (!sizeof(session->ecc_curves) || (session->ecc_point_format == -1)) {
8d6ac22013-12-30Henrik Grubbström (Grubba)  // No overlapping support for ecc. // Filter the ECC suites from the set. SSL3_DEBUG_MSG("ECC not supported.\n"); cipher_suites = filter(cipher_suites, not_ecc_suite); }
e85ce52013-11-26Henrik Grubbström (Grubba)  if (!sizeof(cipher_suites) ||
68b67e2014-04-05Henrik Grubbström (Grubba)  !session->select_cipher_suite(context, cipher_suites, version)) {
1ecaa22014-02-03Henrik Grubbström (Grubba)  // No overlapping cipher suites, or obsolete cipher suite selected, // or incompatible certificates.
57df062014-03-08Henrik Grubbström (Grubba)  SSL3_DEBUG_MSG("No common suites.\n");
56e8852014-04-12Martin Nilsson  send_packet(Alert(ALERT_fatal, ALERT_handshake_failure,
47f84c2014-04-12Henrik Grubbström (Grubba)  "No common suites!\n"));
33ef431997-03-13Niels Möller  return -1; }
21df722014-01-02Henrik Grubbström (Grubba) 
e9428a2013-10-21Martin Nilsson  compression_methods = context->preferred_compressors & compression_methods;
33ef431997-03-13Niels Möller  if (sizeof(compression_methods)) session->set_compression_method(compression_methods[0]); else {
57df062014-03-08Henrik Grubbström (Grubba)  SSL3_DEBUG_MSG("Unsupported compression method.\n");
56e8852014-04-12Martin Nilsson  send_packet(Alert(ALERT_fatal, ALERT_handshake_failure,
47f84c2014-04-12Henrik Grubbström (Grubba)  "Unsupported compression method.\n"));
33ef431997-03-13Niels Möller  return -1; } send_packet(server_hello_packet());
c51f9c2012-08-30Bill Welliver 
21df722014-01-02Henrik Grubbström (Grubba)  // Don't send any certificate in anonymous mode. if (session->cipher_spec->sign != .Cipher.anon_sign) { /* Send Certificate, ServerKeyExchange and CertificateRequest as * appropriate, and then ServerHelloDone.
1ecaa22014-02-03Henrik Grubbström (Grubba)  * * NB: session->certificate_chain is set by * session->select_cipher_suite() above.
21df722014-01-02Henrik Grubbström (Grubba)  */
1ecaa22014-02-03Henrik Grubbström (Grubba)  if (session->certificate_chain)
21df722014-01-02Henrik Grubbström (Grubba)  { SSL3_DEBUG_MSG("Sending Certificate.\n");
1ecaa22014-02-03Henrik Grubbström (Grubba)  send_packet(certificate_packet(session->certificate_chain));
21df722014-01-02Henrik Grubbström (Grubba)  } else { // Otherwise the server will just silently send an invalid // ServerHello sequence. error ("Certificate(s) missing.\n"); }
33ef431997-03-13Niels Möller  }
da12091998-08-26Niels Möller 
18c01f2004-01-25Martin Nilsson  Packet key_exchange = server_key_exchange_packet();
da12091998-08-26Niels Möller 
aa77d52001-04-18Pär Svensson  if (key_exchange) {
fada191999-03-09Niels Möller  send_packet(key_exchange);
aa77d52001-04-18Pär Svensson  }
671d132004-01-23H. William Welliver III  if (context->auth_level >= AUTHLEVEL_ask)
33ef431997-03-13Niels Möller  {
88cfa12005-10-28H. William Welliver III  // we can send a certificate request packet, even if we don't have // any authorized issuers. send_packet(certificate_request_packet(context));
33ef431997-03-13Niels Möller  certificate_state = CERT_requested; } send_packet(handshake_packet(HANDSHAKE_server_hello_done, "")); return 0; }
b6345f2004-01-23Martin Nilsson  Packet change_cipher_packet()
33ef431997-03-13Niels Möller {
b6345f2004-01-23Martin Nilsson  Packet packet = Packet();
33ef431997-03-13Niels Möller  packet->content_type = PACKET_change_cipher_spec; packet->fragment = "\001"; return packet; }
ca94982013-12-08Henrik Grubbström (Grubba) string(0..255) hash_messages(string(0..255) sender)
33ef431997-03-13Niels Möller {
68b67e2014-04-05Henrik Grubbström (Grubba)  if(version == PROTOCOL_SSL_3_0) {
1ff5512014-03-29Martin Nilsson  return .Cipher.MACmd5(session->master_secret)->hash(handshake_messages + sender) + .Cipher.MACsha(session->master_secret)->hash(handshake_messages + sender);
aa77d52001-04-18Pär Svensson  }
68b67e2014-04-05Henrik Grubbström (Grubba)  else if(version <= PROTOCOL_TLS_1_1) {
0791b12013-11-24Henrik Grubbström (Grubba)  return session->cipher_spec->prf(session->master_secret, sender, Crypto.MD5.hash(handshake_messages)+ Crypto.SHA1.hash(handshake_messages), 12);
68b67e2014-04-05Henrik Grubbström (Grubba)  } else if(version >= PROTOCOL_TLS_1_2) {
0791b12013-11-24Henrik Grubbström (Grubba)  return session->cipher_spec->prf(session->master_secret, sender,
4b0f8e2013-12-04Henrik Grubbström (Grubba)  session->cipher_spec->hash->hash(handshake_messages), 12);
aa77d52001-04-18Pär Svensson  }
33ef431997-03-13Niels Möller }
ca94982013-12-08Henrik Grubbström (Grubba) Packet finished_packet(string(0..255) sender)
33ef431997-03-13Niels Möller {
7871142013-08-01Martin Nilsson  SSL3_DEBUG_MSG("Sending finished_packet, with sender=\""+sender+"\"\n" );
ca94982013-12-08Henrik Grubbström (Grubba)  string(0..255) verify_data = hash_messages(sender);
87740f2011-01-10Henrik Grubbström (Grubba)  if (handshake_state >= STATE_client_min) { // We're the client. client_verify_data = verify_data; } else { // We're the server. server_verify_data = verify_data; } return handshake_packet(HANDSHAKE_finished, verify_data);
33ef431997-03-13Niels Möller }
88cfa12005-10-28H. William Welliver III Packet certificate_request_packet(SSL.context context) { /* Send a CertificateRequest message */ ADT.struct struct = ADT.struct(); struct->put_var_uint_array(context->preferred_auth_methods, 1, 1);
47c33a2014-04-13Henrik Grubbström (Grubba)  if (version >= PROTOCOL_TLS_1_2) { // TLS 1.2 has var_uint_array of hash and sign pairs here. struct->put_var_string(get_signature_algorithms(), 2); }
ca94982013-12-08Henrik Grubbström (Grubba)  struct->put_var_string([string(0..255)] sprintf("%{%2H%}", context->authorities_cache), 2);
88cfa12005-10-28H. William Welliver III  return handshake_packet(HANDSHAKE_certificate_request, struct->pop_data()); }
ca94982013-12-08Henrik Grubbström (Grubba) Packet certificate_packet(array(string(0..255)) certificates)
88cfa12005-10-28H. William Welliver III { ADT.struct struct = ADT.struct(); int len = 0;
c51f9c2012-08-30Bill Welliver 
88cfa12005-10-28H. William Welliver III  if(certificates && sizeof(certificates)) len = `+( @ Array.map(certificates, sizeof));
7871142013-08-01Martin Nilsson  // SSL3_DEBUG_MSG("SSL.handshake: certificate_message size %d\n", len);
88cfa12005-10-28H. William Welliver III  struct->put_uint(len + 3 * sizeof(certificates), 3);
ca94982013-12-08Henrik Grubbström (Grubba)  foreach(certificates, string(0..255) cert)
88cfa12005-10-28H. William Welliver III  struct->put_var_string(cert, 3); return handshake_packet(HANDSHAKE_certificate, struct->pop_data()); }
ee37502014-05-04Martin Nilsson Packet heartbeat_packet(string(8bit) s)
978f572014-04-14Henrik Grubbström (Grubba) { Packet packet = Packet(); packet->content_type = PACKET_heartbeat; packet->fragment = s; return packet; } protected Crypto.AES heartbeat_encode; protected Crypto.AES heartbeat_decode; Packet heartbleed_packet() { if (!heartbeat_encode) { // NB: We encrypt the payload with a random AES key // to reduce the amount of known plaintext in // the heartbeat masseages. This is needed now // that many cipher suites (such as GCM and CCM) // use xor with a cipher stream, to reduce risk // of revealing larger segments of the stream. heartbeat_encode = Crypto.AES(); heartbeat_decode = Crypto.AES(); string(8bit) heartbeat_key = random_string(16); heartbeat_encode->set_encrypt_key(heartbeat_key); heartbeat_decode->set_decrypt_key(heartbeat_key); } // This packet probes for the Heartbleed vulnerability (CVE-2014-0160) // by crafting a heartbeat packet with insufficient (0) padding. // // If we get a response, the peer doesn't validate the message sizes // properly, and probably suffers from the Heartbleed vulnerability. // // Note that we don't use negative padding (as per the actual attack), // to avoid actually stealing information from the peer. // // Note that we detect the packet on return by it having all zeros // in the second field. ADT.struct hb_msg = ADT.struct(); hb_msg->put_uint(HEARTBEAT_MESSAGE_request, 1); hb_msg->put_uint(16, 2); int now = gethrtime(); hb_msg->put_fix_string(heartbeat_encode->crypt(sprintf("%8c%8c", now, 0))); // No padding. return heartbeat_packet(hb_msg->pop_data()); }
ca94982013-12-08Henrik Grubbström (Grubba) string(0..255) server_derive_master_secret(string(0..255) data)
33ef431997-03-13Niels Möller {
ee37502014-05-04Martin Nilsson  string(0..255)|int(0..255) res =
5277132013-11-24Henrik Grubbström (Grubba)  ke->server_derive_master_secret(data, client_random, server_random, version);
2f77da2013-11-23Henrik Grubbström (Grubba)  if (stringp(res)) return [string]res;
ee37502014-05-04Martin Nilsson  send_packet(Alert(ALERT_fatal, [int(0..255)]res,
47f84c2014-04-12Henrik Grubbström (Grubba)  "Failed to derive master secret.\n"));
2f77da2013-11-23Henrik Grubbström (Grubba)  return 0;
813b392000-08-04Andreas Sigfridsson }
aa77d52001-04-18Pär Svensson 
7655672004-01-27H. William Welliver III // verify that a certificate chain is acceptable
f591dd2004-01-29H. William Welliver III //
b6345f2004-01-23Martin Nilsson int verify_certificate_chain(array(string) certs)
7e78212004-01-23H. William Welliver III {
526a402004-01-30H. William Welliver III  // do we need to verify the certificate chain? if(!context->verify_certificates) return 1;
88cfa12005-10-28H. William Welliver III  // if we're not requiring the certificate, and we don't provide one, // that should be okay. if((context->auth_level < AUTHLEVEL_require) && !sizeof(certs)) return 1;
868f712012-05-20Martin Nilsson  // a lack of certificates when we reqiure and must verify the // certificates is probably a failure.
88cfa12005-10-28H. William Welliver III  if(!certs || !sizeof(certs)) return 0;
7e78212004-01-23H. William Welliver III 
09aa4f2013-12-04Martin Nilsson  // See if the issuer of the certificate is acceptable. This means // the issuer of the certificate must be one of the authorities.
526a402004-01-30H. William Welliver III  if(sizeof(context->authorities_cache))
7e78212004-01-23H. William Welliver III  {
9cade82014-02-15Martin Nilsson  string r=Standards.X509.decode_certificate(certs[-1])->issuer
09aa4f2013-12-04Martin Nilsson  ->get_der(); int issuer_known = 0; foreach(context->authorities_cache, string c)
7e78212004-01-23H. William Welliver III  {
09aa4f2013-12-04Martin Nilsson  if(r == c) // we have a trusted issuer
526a402004-01-30H. William Welliver III  { issuer_known = 1; break; }
7e78212004-01-23H. William Welliver III  }
526a402004-01-30H. William Welliver III  if(issuer_known==0) { return 0; }
f591dd2004-01-29H. William Welliver III  }
7655672004-01-27H. William Welliver III  // ok, so we have a certificate chain whose client certificate is // issued by an authority known to us.
7e78212004-01-23H. William Welliver III 
7655672004-01-27H. William Welliver III  // next we must verify the chain to see if the chain is unbroken
d13f3f2013-11-24Henrik Grubbström (Grubba)  mapping result =
81bef22013-12-04Martin Nilsson  Standards.X509.verify_certificate_chain(certs, context->trusted_issuers_cache,
d13f3f2013-11-24Henrik Grubbström (Grubba)  context->require_trust);
7655672004-01-27H. William Welliver III  if(result->verified)
f591dd2004-01-29H. William Welliver III  {
81bef22013-12-04Martin Nilsson  // This data isn't actually used internally.
f591dd2004-01-29H. William Welliver III  session->cert_data = result;
7655672004-01-27H. William Welliver III  return 1;
f591dd2004-01-29H. William Welliver III  }
7e78212004-01-23H. William Welliver III 
868f712012-05-20Martin Nilsson  return 0;
7e78212004-01-23H. William Welliver III }
aa77d52001-04-18Pär Svensson 
f5bb032001-09-17Martin Nilsson //! Do handshake processing. Type is one of HANDSHAKE_*, data is the //! contents of the packet, and raw is the raw packet received (needed //! for supporting SSLv2 hello messages). //!
4c0c472013-10-27Henrik Grubbström (Grubba) //! This function returns 0 if handshake is in progress, 1 if handshake
3a5f8e2010-02-21Stephen R. van den Berg //! is finished, and -1 if a fatal error occurred. It uses the
5f883e2008-09-05Martin Stjernholm //! send_packet() function to transmit packets.
5e6d4e2014-05-04Henrik Grubbström (Grubba) int(-1..1) handle_handshake(int type, string(0..255) data, string(0..255) raw);
33ef431997-03-13Niels Möller 
6262d42011-12-15Henrik Grubbström (Grubba) //! @param is_server //! Whether this is the server end of the connection or not. //! @param ctx //! The context for the connection.
84b90d2014-05-04Martin Nilsson protected void create(SSL.context ctx)
33ef431997-03-13Niels Möller {
84b90d2014-05-04Martin Nilsson  current_read_state = SSL.state(this); current_write_state = SSL.state(this);
f466b62014-04-04Henrik Grubbström (Grubba)  if ((ctx->max_version < PROTOCOL_SSL_3_0) || (ctx->max_version > PROTOCOL_TLS_MAX)) { ctx->max_version = PROTOCOL_TLS_MAX;
6262d42011-12-15Henrik Grubbström (Grubba)  }
f466b62014-04-04Henrik Grubbström (Grubba)  if (ctx->min_version < PROTOCOL_SSL_3_0) { ctx->min_version = PROTOCOL_SSL_3_0; } else if (ctx->min_version > ctx->max_version) { ctx->min_version = ctx->max_version;
6262d42011-12-15Henrik Grubbström (Grubba)  }
68b67e2014-04-05Henrik Grubbström (Grubba)  version = ctx->max_version;
a300792003-10-24Martin Stjernholm  context = ctx;
84b90d2014-05-04Martin Nilsson } // // --- Old connection.pike below // //! SSL packet layer. //! //! @[SSL.connection] inherits @[SSL.handshake], and in addition to the state in //! the handshake super class, it contains the current read and write //! states, packet queues. This object is responsible for receiving and //! sending packets, processing handshake packets, and providing clear //! text packets for some application. // SSL/TLS Protocol Specification documents: // // SSL 2 http://wp.netscape.com/eng/security/SSL_2.html // SSL 3.0 http://wp.netscape.com/eng/ssl3/draft302.txt // (aka draft-freier-ssl-version3-02.txt). // TLS 1.0 (SSL 3.1) RFC 2246 "The TLS Protocol Version 1.0". // TLS 1.1 (SSL 3.2) draft-ietf-tls-rfc2246-bis // Renegotiation RFC 5746 "Renegotiation Indication Extension". .state current_read_state; .state current_write_state; string left_over; Packet packet; int sent; int dying; int closing; // Bitfield: 1 if a close is sent, 2 of one is received. function(object,int|object,string:void) alert_callback; constant PRI_alert = 1; constant PRI_urgent = 2; constant PRI_application = 3; protected ADT.Queue alert = ADT.Queue(); protected ADT.Queue urgent = ADT.Queue(); protected ADT.Queue application = ADT.Queue(); //! Called with alert object, sequence number of bad packet, //! and raw data as arguments, if a bad packet is received. //! //! Can be used to support a fallback redirect https->http. void set_alert_callback(function(object,int|object,string:void) callback) { alert_callback = callback; } //! Low-level receive handler. Returns a packet, an alert, or zero if //! more data is needed to get a complete packet. protected Packet recv_packet(string data) { string|Packet res; // SSL3_DEBUG_MSG("SSL.connection->recv_packet(%O)\n", data); if (left_over || !packet) { packet = Packet(2048); res = packet->recv( (left_over || "") + data, version); } else res = packet->recv(data, version); if (stringp(res)) { /* Finished a packet */ left_over = [string]res; if (current_read_state) { SSL3_DEBUG_MSG("SSL.connection->recv_packet(): version=0x%x\n", version); return current_read_state->decrypt_packet(packet, version); } else { SSL3_DEBUG_MSG("SSL.connection->recv_packet(): current_read_state is zero!\n"); return 0; } } else /* Partial packet read, or error */ left_over = 0; return [object]res; } //! Queues a packet for write. Handshake and and change cipher //! must use the same priority, so must application data and //! close_notifies. void send_packet(object packet, int|void priority) { if (closing & 1) { SSL3_DEBUG_MSG("SSL.connection->send_packet: ignoring packet after close\n"); return; } if (packet->content_type == PACKET_alert && packet->description == ALERT_close_notify) closing |= 1; if (!priority) priority = ([ PACKET_alert : PRI_alert, PACKET_change_cipher_spec : PRI_urgent, PACKET_handshake : PRI_urgent, PACKET_heartbeat : PRI_urgent, PACKET_application_data : PRI_application ])[packet->content_type]; SSL3_DEBUG_MSG("SSL.connection->send_packet: type %d, desc %d, pri %d, %O\n", packet->content_type, packet->description, priority, packet->fragment[..5]); switch (priority) { default: error( "Internal error\n" ); case PRI_alert: alert->put(packet); break; case PRI_urgent: urgent->put(packet); break; case PRI_application: application->put(packet); break; } } //! Extracts data from the packet queues. Returns a string of data //! to be written, "" if there are no pending packets, 1 of the //! connection is being closed politely, and -1 if the connection //! died unexpectedly. //! //! This function is intended to be called from an i/o write callback. string|int to_write() { if (dying) return -1; Packet packet = [object(Packet)](alert->get() || urgent->get() || application->get()); if (!packet) { return closing ? 1 : ""; } SSL3_DEBUG_MSG("SSL.connection: writing packet of type %d, %O\n", packet->content_type, packet->fragment[..6]); if (packet->content_type == PACKET_alert) { if (packet->level == ALERT_fatal) { dying = 1; // SSL3 5.4: // Alert messages with a level of fatal result in the immediate // termination of the connection. In this case, other // connections corresponding to the session may continue, but // the session identifier must be invalidated, preventing the // failed session from being used to establish new connections. if (session) { context->purge_session(session); } } } string res = current_write_state->encrypt_packet(packet, version)->send(); if (packet->content_type == PACKET_change_cipher_spec) current_write_state = pending_write_state; return res; } //! Initiate close. void send_close() { send_packet(Alert(ALERT_warning, ALERT_close_notify, "Closing connection.\n"), PRI_application); } //! Send an application data packet. If the data block is too large //! then as much as possible of the beginning of it is sent. The size //! of the sent data is returned. int send_streaming_data (string(8bit) data) { if (!sizeof(data)) return 0; Packet packet = Packet(); packet->content_type = PACKET_application_data; int max_packet_size = session->max_packet_size; int size; if ((!sent) && (version < PROTOCOL_TLS_1_1) && (session->cipher_spec->cipher_type == CIPHER_block)) { // Workaround for the BEAST attack. // This method is known as the 1/(n-1) split: // Send just one byte of payload in the first packet // to improve the initialization vectors in TLS 1.0. size = sizeof((packet->fragment = data[..0])); if (sizeof(data) > 1) { // If we have more data, take the opportunity to queue some of it too. send_packet(packet); packet = Packet(); packet->content_type = PACKET_application_data; size += sizeof((packet->fragment = data[1..max_packet_size-1])); } } else { size = sizeof ((packet->fragment = data[..max_packet_size-1])); } send_packet (packet); sent += size; return size; } protected int handle_alert(string s) { // sizeof(s)==2, checked at caller. int level = s[0]; int description = s[1]; if (! (ALERT_levels[level] && ALERT_descriptions[description])) { send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, "invalid alert\n")); return -1; } if (level == ALERT_fatal) { SSL3_DEBUG_MSG("SSL.connection: Fatal alert %d\n", description); return -1; } if (description == ALERT_close_notify) { SSL3_DEBUG_MSG("SSL.connection: Close notify alert %d\n", description); closing |= 2; return 1; } if (description == ALERT_no_certificate) { SSL3_DEBUG_MSG("SSL.connection: No certificate alert %d\n", description); if ((certificate_state == CERT_requested) && (context->auth_level == AUTHLEVEL_ask)) { certificate_state = CERT_no_certificate; return 0; } else { send_packet(Alert(ALERT_fatal, ((certificate_state == CERT_requested) ? ALERT_handshake_failure : ALERT_unexpected_message), "Certificate required.\n")); return -1; } } #ifdef SSL3_DEBUG else werror("SSL.connection: Received warning alert %d\n", description); #endif return 0; }
da33812004-01-14H. William Welliver III 
84b90d2014-05-04Martin Nilsson int handle_change_cipher(int c) { if (!expect_change_cipher || (c != 1)) { SSL3_DEBUG_MSG("SSL.connection: handle_change_cipher: Unexcepted message!"); send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, "Unexpected change cipher!\n")); return -1; }
33ef431997-03-13Niels Möller  else
813b392000-08-04Andreas Sigfridsson  {
84b90d2014-05-04Martin Nilsson  current_read_state = pending_read_state; expect_change_cipher = 0; return 0; } } void send_heartbeat() { if (!handshake_finished || (session->heartbeat_mode != HEARTBEAT_MODE_peer_allowed_to_send)) { // We're not allowed to send heartbeats. return; } ADT.struct hb_msg = ADT.struct(); hb_msg->put_uint(HEARTBEAT_MESSAGE_request, 1); hb_msg->put_uint(16, 2); int now = gethrtime(); hb_msg->put_fix_string(heartbeat_encode->crypt(sprintf("%8c%8c", now, now))); // We pad to an even 64 bytes. hb_msg->put_fix_string(random_string(64 - sizeof(hb_msg))); send_packet(heartbeat_packet(hb_msg->pop_data())); } void handle_heartbeat(string(8bit) s) { if (sizeof(s) < 19) return; // Minimum size for valid heartbeats. ADT.struct hb_msg = ADT.struct(s); int hb_type = hb_msg->get_uint(1); int hb_len = hb_msg->get_uint(2); SSL3_DEBUG_MSG("SSL.connection: Heartbeat %s (%d bytes)", fmt_constant(hb_type, "HEARTBEAT_MESSAGE"), hb_len); string(8bit) payload; int pad_len = 16; // RFC 6520 4: // If the payload_length of a received HeartbeatMessage is too // large, the received HeartbeatMessage MUST be discarded silently. if ((hb_len < 0) || ((hb_len + 16) > sizeof(hb_msg))) { #ifdef SSL3_SIMULATE_HEARTBLEED payload = hb_msg->get_rest(); if (sizeof(payload) < hb_len) { payload = payload + random_string(hb_len - sizeof(payload)); } else { payload = payload[..hb_len-1]; } #else return; #endif } else { payload = hb_msg->get_fix_string(hb_len); pad_len = sizeof(hb_msg); } switch(hb_type) { case HEARTBEAT_MESSAGE_request: // RFC 6520 4: // When a HeartbeatRequest message is received and sending a // HeartbeatResponse is not prohibited as described elsewhere in // this document, the receiver MUST send a corresponding // HeartbeatResponse message carrying an exact copy of the payload // of the received HeartbeatRequest. hb_msg = ADT.struct(); hb_msg->put_uint(HEARTBEAT_MESSAGE_response, 1); hb_msg->put_uint(hb_len, 2); hb_msg->put_fix_string(payload); hb_msg->put_fix_string(random_string(pad_len)); send_packet(heartbeat_packet(hb_msg->pop_data())); break; case HEARTBEAT_MESSAGE_response: // RFC 6520 4: // If a received HeartbeatResponse message does not contain the // expected payload, the message MUST be discarded silently. if ((sizeof(payload) == 16) && heartbeat_decode) { hb_msg = ADT.struct(heartbeat_decode->crypt(payload)); int a = hb_msg->get_uint(8); int b = hb_msg->get_uint(8); if (a != b) { if (!b) { // Heartbleed probe response. send_packet(Alert(ALERT_fatal, ALERT_insufficient_security, "Peer suffers from a bleeding heart.\n")); } break; } #ifdef SSL3_DEBUG int delta = gethrtime() - a; SSL3_DEBUG_MSG("SSL.connection: Heartbeat roundtrip: %dus\n", delta); #endif } break; default: break; } } string(8bit) alert_buffer = ""; string(8bit) handshake_buffer = ""; //! Main receive handler. Returns a string of received application //! data, or 1 if a close was received, or -1 if an error occurred. //! //! This function is intended to be called from an i/o read callback. string|int got_data(string|int s) { if(!stringp(s)) { return s; } if (closing & 2) { return 1; } // If closing == 1 we continue to try to read a remote close // message. That enables the caller to check for a clean close, and // to get the leftovers after the SSL connection. /* If alert_callback is called, this data is passed as an argument */ string alert_context = (left_over || "") + s; string res = ""; Packet packet; while (packet = recv_packet([string]s)) { s = ""; if (packet->is_alert) { /* Reply alert */ SSL3_DEBUG_MSG("SSL.connection: Bad received packet\n"); send_packet(packet); if (alert_callback) alert_callback(packet, current_read_state->seq_num, alert_context); if ((!packet) || (!this) || (packet->level == ALERT_fatal)) return -1; if (alert_callback) break; } else { SSL3_DEBUG_MSG("SSL.connection: received packet of type %d\n", packet->content_type); switch (packet->content_type) { case PACKET_alert: { SSL3_DEBUG_MSG("SSL.connection: ALERT\n"); int i; int err = 0; alert_buffer += packet->fragment; for (i = 0; !err && ((sizeof(alert_buffer) - i) >= 2); i+= 2) err = handle_alert(alert_buffer[i..i+1]); alert_buffer = alert_buffer[i..]; if (err) if (err > 0 && sizeof (res)) // If we get a close then we return the data we got so far. return res; else return err; break; } case PACKET_change_cipher_spec: { SSL3_DEBUG_MSG("SSL.connection: CHANGE_CIPHER_SPEC\n"); int i; int err; for (i = 0; (i < sizeof(packet->fragment)); i++) { err = handle_change_cipher(packet->fragment[i]); SSL3_DEBUG_MSG("tried change_cipher: %d\n", err); if (err) return err; } break; } case PACKET_handshake: { SSL3_DEBUG_MSG("SSL.connection: HANDSHAKE\n"); if (handshake_finished && !secure_renegotiation) { // Don't allow renegotiation in unsecure mode, to address // http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-3555. // For details see: http://www.g-sec.lu/practicaltls.pdf and // RFC 5746. send_packet(Alert(ALERT_warning, ALERT_no_renegotiation, "Renegotiation not supported in unsecure mode.\n")); return -1; } if (expect_change_cipher) { /* No change_cipher message was received */ // FIXME: There's a bug somewhere since expect_change_cipher often // remains set after the handshake is completed. The effect is that // renegotiation doesn't work all the time. // // A side effect is that we are partly invulnerable to the // renegotiation vulnerability mentioned above. It is however not // safe to assume that, since there might be routes past this, // maybe through the use of a version 2 hello message below. send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, "Expected change cipher.\n")); return -1; } int err, len; handshake_buffer += packet->fragment; while (sizeof(handshake_buffer) >= 4) { sscanf(handshake_buffer, "%*c%3c", len); if (sizeof(handshake_buffer) < (len + 4)) break; err = handle_handshake(handshake_buffer[0], handshake_buffer[4..len + 3], handshake_buffer[.. len + 3]); handshake_buffer = handshake_buffer[len + 4..]; if (err < 0) return err; if (err > 0) { handshake_finished = 1; } } break; } case PACKET_application_data: SSL3_DEBUG_MSG("SSL.connection: APPLICATION_DATA\n"); if (!handshake_finished) { send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, "Handshake not finished yet!\n")); return -1; } res += packet->fragment; break; case PACKET_heartbeat: { // RFC 6520. SSL3_DEBUG_MSG("SSL.connection: Heartbeat.\n"); if (!handshake_finished) { // RFC 6520 3: // The receiving peer SHOULD discard the message silently, // if it arrives during the handshake. break; } if (!session->heartbeat_mode) { // RFC 6520 2: // If an endpoint that has indicated peer_not_allowed_to_send // receives a HeartbeatRequest message, the endpoint SHOULD // drop the message silently and MAY send an unexpected_message // Alert message. send_packet(Alert(ALERT_warning, ALERT_unexpected_message, "Heart beat mode not enabled.\n")); break; } handle_heartbeat(packet->fragment); } break; default: if (!handshake_finished) { send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, "Unexpected message during handshake!\n")); return -1; } // RFC 4346 6: // If a TLS implementation receives a record type it does not // understand, it SHOULD just ignore it. SSL3_DEBUG_MSG("SSL.connection: Ignoring packet of type %s\n", fmt_constant(packet->content_type, "PACKET")); break; } }
813b392000-08-04Andreas Sigfridsson  }
84b90d2014-05-04Martin Nilsson  return closing & 2 ? 1 : res;
33ef431997-03-13Niels Möller }