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 
4ceceb2014-05-05Henrik Grubbström (Grubba) //! SSL.Connection keeps the state relevant for a single SSL connection.
938d512014-05-16Martin Nilsson //! This includes the @[Context] object (which doesn't change), various //! buffers, the @[Session] object (reused or created as appropriate),
4ceceb2014-05-05Henrik Grubbström (Grubba) //! and pending read and write states being negotiated.
f5bb032001-09-17Martin Nilsson //!
938d512014-05-16Martin Nilsson //! Each connection will have two sets of read and write @[State]s: 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.
4ceceb2014-05-05Henrik Grubbström (Grubba) //!
938d512014-05-16Martin Nilsson //! This object is also responsible for managing incoming and outgoing
565b332014-05-17Henrik Grubbström (Grubba) //! packets. Outgoing packets are stored in queue objects and sent in //! priority order.
938d512014-05-16Martin Nilsson //!
4ceceb2014-05-05Henrik Grubbström (Grubba) //! @note
938d512014-05-16Martin Nilsson //! This class should never be created directly, instead one of the //! classes that inherits it should be used (ie either
4ceceb2014-05-05Henrik Grubbström (Grubba) //! @[ClientConnection] or @[ServerConnection]) depending on whether
938d512014-05-16Martin Nilsson //! this is to be a client-side or server-side connection. These in
fc7f092014-06-01Martin Nilsson //! turn are typically created by @[File()->create()].
4ceceb2014-05-05Henrik Grubbström (Grubba) //! //! @seealso
938d512014-05-16Martin Nilsson //! @[ClientConnection], @[ServerConnection], @[Context],
fc7f092014-06-01Martin Nilsson //! @[Session], @[File], @[State]
c79dc12001-06-14Pär Svensson  //#define SSL3_PROFILING
3c859d2015-02-25Martin Nilsson #include "tls.h"
4f5e1d2003-01-27Martin Nilsson import .Constants;
3f2ef02015-01-05Henrik Grubbström (Grubba)  private constant State = .State; private constant Session = .Session; private constant Context = .Context; private constant Buffer = .Buffer;
33ef431997-03-13Niels Möller 
c65c582014-05-15Martin Nilsson Session session;
dc90a52014-05-15Martin Nilsson Context context;
33ef431997-03-13Niels Möller 
1604ca2015-01-10Henrik Grubbström (Grubba) array(State) pending_read_state = ({}); array(State) pending_write_state = ({});
33ef431997-03-13Niels Möller  /* State variables */
5e3a142014-04-30Martin Nilsson int handshake_state; // Constant.STATE_*
b9909a2015-01-06Henrik Grubbström (Grubba) int previous_handshake; // Constant.HANDSHAKE_*
fab1c62014-11-22Henrik Grubbström (Grubba) int reuse;
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 */
87740f2011-01-10Henrik Grubbström (Grubba) // RFC 5746-related fields int secure_renegotiation;
2d40602014-05-16Martin Nilsson string(8bit) client_verify_data = ""; string(8bit) server_verify_data = "";
ca94982013-12-08Henrik Grubbström (Grubba) // 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. */
88cfa12005-10-28H. William Welliver III 
f5bb032001-09-17Martin Nilsson //! Random cookies, sent and received with the hello-messages.
2d40602014-05-16Martin Nilsson string(8bit) client_random; string(8bit) server_random;
33ef431997-03-13Niels Möller 
3f2ef02015-01-05Henrik Grubbström (Grubba) private constant Packet = .Packet; private constant Alert = .Alert;
47f84c2014-04-12Henrik Grubbström (Grubba) 
372b2a2016-07-13Henrik Grubbström (Grubba) int(0..3) tickets_enabled = 0;
bf53f32015-07-06Henrik Grubbström (Grubba) // RFC 7301 (ALPN) 3.1: // Unlike many other TLS extensions, this extension does not establish // properties of the session, only of the connection. When session // resumption or session tickets [RFC5077] are used, the previous // contents of this extension are irrelevant, and only the values in the // new handshake messages are considered.
dc93732015-08-22Martin Nilsson //! Selected ALPN (@rfc{7301@}) protocol (if any).
bf53f32015-07-06Henrik Grubbström (Grubba) //! //! @note //! Note that this is a connection property, and needs to be renegotiated //! on session resumption. string(8bit) application_protocol;
2d40602014-05-16Martin Nilsson Alert alert(int(1..2) level, int(8bit) description,
7f45cf2014-05-15Martin Nilsson  string|void message)
47f84c2014-04-12Henrik Grubbström (Grubba) { return context->alert_factory(this, level, description, version,
74b5eb2014-04-24Martin Nilsson  message);
47f84c2014-04-12Henrik Grubbström (Grubba) }
9eb76c2014-11-24Martin Nilsson Buffer get_signature_algorithms()
47c33a2014-04-13Henrik Grubbström (Grubba) {
7d55002014-11-24Martin Nilsson  Buffer sign_algs = Buffer();
cec12e2014-07-07Henrik Grubbström (Grubba)  foreach(context->get_signature_algorithms(), [int hash, int sign])
ef87a82014-05-20Martin Nilsson  {
16d2f12014-11-21Martin Nilsson  sign_algs->add_int(hash, 1); sign_algs->add_int(sign, 1);
47c33a2014-04-13Henrik Grubbström (Grubba)  }
9eb76c2014-11-24Martin Nilsson  return sign_algs;
47c33a2014-04-13Henrik Grubbström (Grubba) }
c79dc12001-06-14Pär Svensson #ifdef SSL3_PROFILING
bc15c22014-05-02Martin Nilsson System.Timer timer = System.Timer();
e52ddd2015-03-31Martin Nilsson float last_time = 0.0;
c79dc12001-06-14Pär Svensson void addRecord(int t,int s) {
e52ddd2015-03-31Martin Nilsson  addRecord(sprintf("sender: %d type: %s", s, fmt_constant(t, "HANDSHAKE"))); } variant void addRecord(string label) { float stamp = timer->peek(); Stdio.stdout.write("time: %.6f (%.6f) %s\n", stamp, stamp-last_time, label); last_time = stamp;
c79dc12001-06-14Pär Svensson } #endif
a239312015-04-15Martin Nilsson Buffer handshake_messages = Buffer(); protected void add_handshake_message(Buffer|Stdio.Buffer|string(8bit) data) { handshake_messages->add(data); }
33ef431997-03-13Niels Möller 
3f2ef02015-01-05Henrik Grubbström (Grubba) Packet handshake_packet(int(8bit) type, string(8bit)|Buffer|object(Stdio.Buffer) data)
33ef431997-03-13Niels Möller {
c79dc12001-06-14Pär Svensson #ifdef SSL3_PROFILING addRecord(type,1); #endif
f404dd2015-04-15Martin Nilsson  string(8bit) str = sprintf("%1c%3H", type, (string(8bit))data);
a239312015-04-15Martin Nilsson  add_handshake_message(str);
09f63c2014-11-25Martin Nilsson 
f404dd2015-04-15Martin Nilsson  /* FIXME: One need to split large packages. */ return Packet(version, PACKET_handshake, str);
33ef431997-03-13Niels Möller }
b6345f2004-01-23Martin Nilsson Packet change_cipher_packet()
33ef431997-03-13Niels Möller {
1604ca2015-01-10Henrik Grubbström (Grubba)  expect_change_cipher++;
4d15372014-11-25Martin Nilsson  return Packet(version, PACKET_change_cipher_spec, "\001");
33ef431997-03-13Niels Möller }
33aabf2015-01-11Henrik Grubbström (Grubba) string(8bit) hash_messages(string(8bit) sender, int|void len)
33ef431997-03-13Niels Möller {
68b67e2014-04-05Henrik Grubbström (Grubba)  if(version == PROTOCOL_SSL_3_0) {
a239312015-04-15Martin Nilsson  string(8bit) data = (string(8bit))handshake_messages + sender;
e52ddd2015-03-31Martin Nilsson  return .Cipher.MACmd5(session->master_secret)->hash(data) +
2a87c82014-11-26Martin Nilsson  .Cipher.MACsha(session->master_secret)->hash(data);
aa77d52001-04-18Pär Svensson  }
68b67e2014-04-05Henrik Grubbström (Grubba)  else if(version <= PROTOCOL_TLS_1_1) {
e52ddd2015-03-31Martin Nilsson  return session->cipher_spec->prf(session->master_secret, sender,
0791b12013-11-24Henrik Grubbström (Grubba)  Crypto.MD5.hash(handshake_messages)+
79c92e2015-10-27Henrik Grubbström (Grubba)  Crypto.SHA1.hash(handshake_messages), len || 12);
aa77d52001-04-18Pär Svensson  }
e52ddd2015-03-31Martin Nilsson  return session->cipher_spec->prf(session->master_secret, sender, session->cipher_spec->hash
00ec6a2015-07-31Martin Nilsson  ->hash(handshake_messages),
e52ddd2015-03-31Martin Nilsson  len || 12);
33ef431997-03-13Niels Möller }
2d40602014-05-16Martin Nilsson Packet certificate_packet(array(string(8bit)) certificates)
88cfa12005-10-28H. William Welliver III {
09f63c2014-11-25Martin Nilsson  return handshake_packet(HANDSHAKE_certificate, Buffer()->add_string_array(certificates, 3, 3));
88cfa12005-10-28H. William Welliver III }
5321c22015-01-18Henrik Grubbström (Grubba) Packet certificate_verify_packet(string(8bit)|void signature_context)
2e19a42014-12-30Henrik Grubbström (Grubba) { SSL3_DEBUG_MSG("SSL.Connection: CERTIFICATE_VERIFY\n" "%O: handshake_messages: %d bytes.\n",
f960bd2015-07-31Martin Nilsson  this, sizeof(handshake_messages));
2e19a42014-12-30Henrik Grubbström (Grubba)  Buffer struct = Buffer();
5321c22015-01-18Henrik Grubbström (Grubba)  if (signature_context) { // TLS 1.3 and later. session->cipher_spec->sign(session, signature_context + session->cipher_spec->hash
00ec6a2015-07-31Martin Nilsson  ->hash(handshake_messages),
5321c22015-01-18Henrik Grubbström (Grubba)  struct); } else {
a239312015-04-15Martin Nilsson  session->cipher_spec->sign(session, (string(8bit))handshake_messages, struct);
5321c22015-01-18Henrik Grubbström (Grubba)  }
2e19a42014-12-30Henrik Grubbström (Grubba)  return handshake_packet(HANDSHAKE_certificate_verify, struct); }
5321c22015-01-18Henrik Grubbström (Grubba) int(-1..0) validate_certificate_verify(Buffer input, string(8bit) signature_context) { int(0..1) verification_ok;
a239312015-04-15Martin Nilsson  string(8bit) signed = (string(8bit))handshake_messages;
82a77e2015-04-04Martin Nilsson  if (version >= PROTOCOL_TLS_1_3) signed = signature_context + session->cipher_spec->hash->hash(signed);
5321c22015-01-18Henrik Grubbström (Grubba)  mixed err = catch { verification_ok = session->cipher_spec->verify(
82a77e2015-04-04Martin Nilsson  session, signed, input);
5321c22015-01-18Henrik Grubbström (Grubba)  }; #ifdef SSL3_DEBUG if (err) { master()->handle_error(err); } #endif err = UNDEFINED; // Get rid of warning.
1e3a132015-02-25Martin Nilsson  COND_FATAL(!verification_ok, ALERT_unexpected_message, "Validation of CertificateVerify failed.\n");
5321c22015-01-18Henrik Grubbström (Grubba)  return 0; }
09f63c2014-11-25Martin Nilsson Packet heartbeat_packet(Buffer s)
978f572014-04-14Henrik Grubbström (Grubba) {
09f63c2014-11-25Martin Nilsson  return Packet(version, PACKET_heartbeat, s->read());
978f572014-04-14Henrik Grubbström (Grubba) } 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.
7d55002014-11-24Martin Nilsson  Buffer hb_msg = Buffer();
16d2f12014-11-21Martin Nilsson  hb_msg->add_int(HEARTBEAT_MESSAGE_request, 1); hb_msg->add_int(16, 2);
978f572014-04-14Henrik Grubbström (Grubba)  int now = gethrtime();
16d2f12014-11-21Martin Nilsson  hb_msg->add(heartbeat_encode->crypt(sprintf("%8c%8c", now, 0)));
978f572014-04-14Henrik Grubbström (Grubba)  // No padding.
09f63c2014-11-25Martin Nilsson  return heartbeat_packet(hb_msg);
978f572014-04-14Henrik Grubbström (Grubba) }
0f48d72014-12-21Martin Nilsson // Verify that a certificate chain is acceptable
0a6d7b2015-01-26Martin Nilsson private array(Standards.X509.TBSCertificate) verify_certificate_chain(array(string) certs)
7e78212004-01-23H. William Welliver III {
0f48d72014-12-21Martin Nilsson  // If we're not requiring the certificate, and we don't provide one,
d67d3e2015-02-27Martin Nilsson  // that should be okay.
88cfa12005-10-28H. William Welliver III  if((context->auth_level < AUTHLEVEL_require) && !sizeof(certs))
0a6d7b2015-01-26Martin Nilsson  return ({});
88cfa12005-10-28H. William Welliver III 
1f845f2015-12-02Martin Nilsson  // If we are not verifying the certificates, we only need to decode // the leaf certificate for its public key. if(context->auth_level == AUTHLEVEL_none) return ({ Standards.X509.decode_certificate(certs[0]) });
0f48d72014-12-21Martin Nilsson  // A lack of certificates when we reqiure and must verify the
868f712012-05-20Martin Nilsson  // certificates is probably a failure.
0f48d72014-12-21Martin Nilsson  if(!sizeof(certs))
88cfa12005-10-28H. William Welliver III  return 0;
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.
166eee2015-11-08Martin Nilsson  // NOTE: This code is only relevant when acting as a server dealing // with client certificates.
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  }
166eee2015-11-08Martin Nilsson  // Decode the chain, verify each certificate and verify that the // chain is unbroken. mapping result = ([]); catch { result = Standards.X509.verify_certificate_chain(certs,
200b092015-12-06Henrik Grubbström (Grubba)  context->trusted_issuers_cache, context->auth_level >= AUTHLEVEL_require);
166eee2015-11-08Martin Nilsson  };
8d4b302015-12-10Martin Nilsson  if( !result ) return 0;
9142c42015-11-08Martin Nilsson 
747a762015-12-04Henrik Grubbström (Grubba)  if (session->server_name && sizeof([array](result->certificates || ({})))) {
67510a2015-12-03Henrik Grubbström (Grubba)  array(Standards.X509.TBSCertificate) certs = [array(Standards.X509.TBSCertificate)](result->certificates); Standards.X509.TBSCertificate cert = certs[-1]; array(string) globs = Standards.PKCS.Certificate.
1d98a42015-12-03Henrik Grubbström (Grubba)  decode_distinguished_name(cert->subject)->commonName - ({ 0 });
67510a2015-12-03Henrik Grubbström (Grubba)  if (cert->ext_subjectAltName_dNSName) { globs += cert->ext_subjectAltName_dNSName; }
fdc3262015-12-04Henrik Grubbström (Grubba)  result->verified = glob(map(globs, lower_case), lower_case(session->server_name));
67510a2015-12-03Henrik Grubbström (Grubba)  }
9142c42015-11-08Martin Nilsson  // This data isn't actually used internally. session->cert_data = result;
7655672004-01-27H. William Welliver III  if(result->verified)
0a6d7b2015-01-26Martin Nilsson  return [array(Standards.X509.TBSCertificate)]result->certificates;
7e78212004-01-23H. William Welliver III 
0f11582015-01-19Martin Nilsson  return 0;
7e78212004-01-23H. William Welliver III }
aa77d52001-04-18Pär Svensson 
d7ffcb2015-01-26Martin Nilsson // Decodes certificate data. Leaves session->peer_certificate_chain // either 0 or with an array with 1 or more certificates. If // certificates are received session->peer_public_key is updated with // the public key object. If that is an ECC object, the curve is set // in session->curve.
0a6d7b2015-01-26Martin Nilsson int(0..1) handle_certificates(Buffer packet)
d7ffcb2015-01-26Martin Nilsson { // FIXME: Throw exception if called more than once?
0a6d7b2015-01-26Martin Nilsson  Stdio.Buffer input = packet->read_hbuffer(3);
d7ffcb2015-01-26Martin Nilsson  array(string(8bit)) certs = ({ }); while(sizeof(input)) certs += ({ input->read_hstring(3) }); // No need to check remainder input, as the above loop will either // drain input fully or read out of bounds and trigger a decode // error alert packet.
0a6d7b2015-01-26Martin Nilsson  if(sizeof(packet)) { send_packet(alert(ALERT_fatal, ALERT_unexpected_message, "Unknown additional data in packet.\n")); return 0; } // This array is in the reverse order of the certs array. array(Standards.X509.TBSCertificate) decoded = verify_certificate_chain(certs); if( !decoded )
d7ffcb2015-01-26Martin Nilsson  { send_packet(alert(ALERT_fatal, ALERT_bad_certificate,
5e47392015-01-27Martin Nilsson  "Bad certificate chain.\n"));
d7ffcb2015-01-26Martin Nilsson  return 0; } if( !sizeof(certs) ) return 1;
9ad63b2015-01-26Martin Nilsson  // This data isn't actually used internally.
d7ffcb2015-01-26Martin Nilsson  session->peer_certificate_chain = certs;
0a6d7b2015-01-26Martin Nilsson  session->peer_public_key = decoded[-1]->public_key->pkc;
d7ffcb2015-01-26Martin Nilsson  return 1; }
72a2d02015-01-06Henrik Grubbström (Grubba) //! Generate new pending cipher states. void new_cipher_states(); //! Derive the master secret from the premaster_secret //! and the random seeds, and configure the keys. void derive_master_secret(string(8bit) premaster_secret) { SSL3_DEBUG_MSG("%O: derive_master_secret: %s (%s)\n",
76cd912015-01-11Henrik Grubbström (Grubba)  this, fmt_constant(handshake_state, "STATE"),
72a2d02015-01-06Henrik Grubbström (Grubba)  fmt_version(version));
ad2ac42017-12-09Martin Nilsson  if (!sizeof(premaster_secret)) {
19a2f12015-01-24Henrik Grubbström (Grubba)  // Clear text mode. session->master_secret = "";
1b04c72015-02-22Henrik Grubbström (Grubba)  } else if (session->extended_master_secret) { // Extended Master Secret Draft. session->master_secret = premaster_secret; session->master_secret = hash_messages("extended master secret", 48);
76cd912015-01-11Henrik Grubbström (Grubba)  } else { session->master_secret = session->cipher_spec->prf(premaster_secret, "master secret", client_random + server_random, 48); }
72a2d02015-01-06Henrik Grubbström (Grubba)  new_cipher_states(); }
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.
af9ae22015-03-30Martin Nilsson int(-1..1) handle_handshake(int type, Buffer input, Stdio.Buffer raw);
33ef431997-03-13Niels Möller 
4ceceb2014-05-05Henrik Grubbström (Grubba) //! Initialize the connection state. //!
6262d42011-12-15Henrik Grubbström (Grubba) //! @param ctx //! The context for the connection.
dc90a52014-05-15Martin Nilsson protected void create(Context ctx)
33ef431997-03-13Niels Möller {
91f9c72014-05-15Martin Nilsson  current_read_state = State(this); current_write_state = State(this);
84b90d2014-05-04Martin Nilsson 
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 }
00e5f22015-08-05Henrik Grubbström (Grubba) //! Remove cyclic references as best we can. void shutdown() { current_read_state = current_write_state = UNDEFINED; pending_read_state = pending_write_state = ({}); ke = UNDEFINED; alert_callback = UNDEFINED; }
84b90d2014-05-04Martin Nilsson  // // --- Old connection.pike below //
91f9c72014-05-15Martin Nilsson State current_read_state; State current_write_state;
1396b12015-03-31Martin Nilsson Stdio.Buffer read_buffer = Stdio.Buffer();
84b90d2014-05-04Martin Nilsson Packet packet;
2ed01a2014-05-23Henrik Grubbström (Grubba) //! Number of application data bytes sent by us.
84b90d2014-05-04Martin Nilsson int sent;
2ed01a2014-05-23Henrik Grubbström (Grubba)  //! Bitfield with the current connection state. ConnectionState state = CONNECTION_handshaking;
84b90d2014-05-04Martin Nilsson  function(object,int|object,string:void) alert_callback; constant PRI_alert = 1; constant PRI_urgent = 2; constant PRI_application = 3;
7f45cf2014-05-15Martin Nilsson protected ADT.Queue alert_q = ADT.Queue(); protected ADT.Queue urgent_q = ADT.Queue(); protected ADT.Queue application_q = ADT.Queue();
84b90d2014-05-04Martin Nilsson 
2ed01a2014-05-23Henrik Grubbström (Grubba) //! Returns a string describing the current connection state. string describe_state() { if (!state) return "ready"; array(string) res = ({}); if (state & CONNECTION_handshaking) res += ({ "handshaking" }); if (state & CONNECTION_local_failing) { if (state & CONNECTION_local_fatal) { res += ({ "local_fatal" }); } else { res += ({ "local_failing" }); } } if (state & CONNECTION_local_closing) { if (state & CONNECTION_local_closed) { res += ({ "local_closed" }); } else { res += ({ "local_closing" }); } } if (state & CONNECTION_peer_fatal) res += ({ "peer_fatal" }); if (state & CONNECTION_peer_closed) res += ({ "peer_closed" }); return res * "|"; }
423a552014-08-01Henrik Grubbström (Grubba) protected string _sprintf(int t) { if (t == 'O') return sprintf("SSL.Connection(%s)", describe_state()); }
84b90d2014-05-04Martin Nilsson //! 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.
59a60b2015-04-13Martin Nilsson protected Packet recv_packet()
84b90d2014-05-04Martin Nilsson {
1396b12015-03-31Martin Nilsson  if (!packet)
6dfd422014-08-07Martin Nilsson  packet = Packet(version, 2048);
84b90d2014-05-04Martin Nilsson 
6a935b2015-04-13Martin Nilsson  int res = packet->recv(read_buffer);
1396b12015-03-31Martin Nilsson 
6a935b2015-04-13Martin Nilsson  switch(res) { case 1: // Finished a packet if (current_read_state)
938d512014-05-16Martin Nilsson  SSL3_DEBUG_MSG("SSL.Connection->recv_packet(): version=0x%x\n",
84b90d2014-05-04Martin Nilsson  version);
6a935b2015-04-13Martin Nilsson  return current_read_state->decrypt_packet(packet); case 0: SSL3_DEBUG_MSG("SSL.Connection->recv_packet(): current_read_state is zero!\n"); return 0; case -1: return alert(ALERT_fatal, ALERT_unexpected_message); default: error("Internal error.\n");
84b90d2014-05-04Martin Nilsson  }
1396b12015-03-31Martin Nilsson  return 0;
84b90d2014-05-04Martin Nilsson } //! Queues a packet for write. Handshake and and change cipher //! must use the same priority, so must application data and //! close_notifies.
31e6502014-05-16Martin Nilsson void send_packet(Packet packet, int|void priority)
84b90d2014-05-04Martin Nilsson {
b7459d2015-04-05Henrik Grubbström (Grubba)  if (state & (CONNECTION_local_closed | CONNECTION_local_failing)) { SSL3_DEBUG_MSG("send_packet: Ignoring packet after close/fail.\n");
84b90d2014-05-04Martin Nilsson  return; }
7197b02015-04-22Martin Nilsson  session->last_activity = time(1);
2ed01a2014-05-23Henrik Grubbström (Grubba)  if (packet->content_type == PACKET_alert) { if (packet->level == ALERT_fatal) { state = [int(0..0)|ConnectionState](state | CONNECTION_local_failing); } else if (packet->description == ALERT_close_notify) { state = [int(0..0)|ConnectionState](state | CONNECTION_local_closing); } }
84b90d2014-05-04Martin Nilsson  if (!priority) priority = ([ PACKET_alert : PRI_alert, PACKET_change_cipher_spec : PRI_urgent, PACKET_handshake : PRI_urgent, PACKET_heartbeat : PRI_urgent,
b492c82014-11-25Martin Nilsson  PACKET_application_data : PRI_application ])[packet->content_type];
5c41912014-08-24Henrik Grubbström (Grubba)  if ((packet->content_type == PACKET_handshake) && (priority == PRI_application)) { // Assume the packet is either hello_request or client_hello, // and that we want to renegotiate. expect_change_cipher = 0; certificate_state = 0; state = [int(0..0)|ConnectionState](state | CONNECTION_handshaking); handshake_state = STATE_wait_for_hello;
b9909a2015-01-06Henrik Grubbström (Grubba)  previous_handshake = 0;
5c41912014-08-24Henrik Grubbström (Grubba)  }
938d512014-05-16Martin Nilsson  SSL3_DEBUG_MSG("SSL.Connection->send_packet: type %d, pri %d, %O\n",
31e6502014-05-16Martin Nilsson  packet->content_type, priority, packet->fragment[..5]);
84b90d2014-05-04Martin Nilsson  switch (priority) { default: error( "Internal error\n" ); case PRI_alert:
7f45cf2014-05-15Martin Nilsson  alert_q->put(packet);
84b90d2014-05-04Martin Nilsson  break; case PRI_urgent:
7f45cf2014-05-15Martin Nilsson  urgent_q->put(packet);
84b90d2014-05-04Martin Nilsson  break; case PRI_application:
7f45cf2014-05-15Martin Nilsson  application_q->put(packet);
84b90d2014-05-04Martin Nilsson  break; } }
02bb9d2014-07-13Henrik Grubbström (Grubba) //! Returns the number of packets queued for writing. //! //! @returns //! Returns the number of times @[to_write()] can be called before //! it stops returning non-empty strings. int query_write_queue_size() { return sizeof(alert_q) + sizeof(urgent_q) + sizeof(application_q); }
3f605c2015-03-31Martin Nilsson //! Extracts data from the packet queues. Returns 2 if data has been //! written, 0 if there are no pending packets, 1 of the connection is //! being closed politely, and -1 if the connection died unexpectedly.
84b90d2014-05-04Martin Nilsson //! //! This function is intended to be called from an i/o write callback.
02bb9d2014-07-13Henrik Grubbström (Grubba) //! //! @seealso //! @[query_write_queue_size()], @[send_streaming_data()].
3f605c2015-03-31Martin Nilsson int(-1..2) to_write(Stdio.Buffer output)
84b90d2014-05-04Martin Nilsson {
2ed01a2014-05-23Henrik Grubbström (Grubba)  if (state & CONNECTION_local_fatal)
84b90d2014-05-04Martin Nilsson  return -1;
7f45cf2014-05-15Martin Nilsson  Packet packet = [object(Packet)](alert_q->get() || urgent_q->get() || application_q->get());
e28e032015-03-31Martin Nilsson  if (!packet) return !!(state & CONNECTION_local_closing);
84b90d2014-05-04Martin Nilsson 
938d512014-05-16Martin Nilsson  SSL3_DEBUG_MSG("SSL.Connection: writing packet of type %d, %O\n",
84b90d2014-05-04Martin Nilsson  packet->content_type, packet->fragment[..6]); if (packet->content_type == PACKET_alert) { if (packet->level == ALERT_fatal) {
6fda6f2014-10-14Henrik Grubbström (Grubba)  state = [int(0..0)|ConnectionState](state | CONNECTION_local_fatal | CONNECTION_peer_closed);
00e5f22015-08-05Henrik Grubbström (Grubba)  current_read_state = UNDEFINED; pending_read_state = ({});
84b90d2014-05-04Martin Nilsson  // 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); }
2ed01a2014-05-23Henrik Grubbström (Grubba)  } else if (packet->description == ALERT_close_notify) { state = [int(0..0)|ConnectionState](state | CONNECTION_local_closed);
84b90d2014-05-04Martin Nilsson  } }
504fc62015-03-31Martin Nilsson  packet = current_write_state->encrypt_packet(packet, context);
5208152015-01-09Henrik Grubbström (Grubba)  if (packet->content_type == PACKET_change_cipher_spec) {
1604ca2015-01-10Henrik Grubbström (Grubba)  if (sizeof(pending_write_state)) { current_write_state = pending_write_state[0]; pending_write_state = pending_write_state[1..]; } else { error("Invalid Change Cipher Spec.\n"); }
5208152015-01-09Henrik Grubbström (Grubba)  }
504fc62015-03-31Martin Nilsson 
3f605c2015-03-31Martin Nilsson  packet->send(output); return 2;
84b90d2014-05-04Martin Nilsson } //! Initiate close. void send_close() {
7f45cf2014-05-15Martin Nilsson  send_packet(alert(ALERT_warning, ALERT_close_notify,
84b90d2014-05-04Martin Nilsson  "Closing connection.\n"), PRI_application); }
5c41912014-08-24Henrik Grubbström (Grubba) //! Renegotiate the connection. void send_renegotiate();
84b90d2014-05-04Martin Nilsson //! 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) {
b5c5912014-11-25Martin Nilsson  int size = sizeof(data); if (!size) return 0;
84b90d2014-05-04Martin Nilsson  if ((!sent) && (version < PROTOCOL_TLS_1_1) &&
b5c5912014-11-25Martin Nilsson  (session->cipher_spec->cipher_type == CIPHER_block) && (size>1)) {
84b90d2014-05-04Martin Nilsson  // 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.
b5c5912014-11-25Martin Nilsson  send_packet(Packet(version, PACKET_application_data, data[..0])); data = data[1..];
84b90d2014-05-04Martin Nilsson  }
b5c5912014-11-25Martin Nilsson  send_packet(Packet(version, PACKET_application_data, data[..session->max_packet_size-1]));;
84b90d2014-05-04Martin Nilsson  sent += size; return size; }
0bf8452015-03-31Martin Nilsson // @returns // @int // @elem value -1 // A Fatal error occurred and processing should stop. // @elem value 0 // Processing can continue. // @elem value 1 // Connection should close. // @endint protected int(-1..1) handle_alert(string s)
84b90d2014-05-04Martin Nilsson { // sizeof(s)==2, checked at caller. int level = s[0]; int description = s[1];
1e3a132015-02-25Martin Nilsson  COND_FATAL(!(ALERT_levels[level] && ALERT_descriptions[description]), ALERT_unexpected_message, "Invalid alert\n");
b3fa862015-04-05Martin Nilsson  // Consider all deprecated alerts as fatals. COND_FATAL((ALERT_deprecated[description] && ALERT_deprecated[description] < version), ALERT_unexpected_message, "Deprecated alert\n");
84b90d2014-05-04Martin Nilsson  if (level == ALERT_fatal) {
a032542014-05-19Martin Nilsson  SSL3_DEBUG_MSG("SSL.Connection: Fatal alert %O\n", ALERT_descriptions[description]);
6fda6f2014-10-14Henrik Grubbström (Grubba)  state = [int(0..0)|ConnectionState](state | CONNECTION_peer_fatal | CONNECTION_peer_closed);
9e98b92014-12-05Henrik Grubbström (Grubba)  // 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); }
84b90d2014-05-04Martin Nilsson  return -1; } if (description == ALERT_close_notify) {
a032542014-05-19Martin Nilsson  SSL3_DEBUG_MSG("SSL.Connection: %O\n", ALERT_descriptions[description]);
2ed01a2014-05-23Henrik Grubbström (Grubba)  state = [int(0..0)|ConnectionState](state | CONNECTION_peer_closed);
84b90d2014-05-04Martin Nilsson  return 1; } if (description == ALERT_no_certificate) {
a032542014-05-19Martin Nilsson  SSL3_DEBUG_MSG("SSL.Connection: %O\n", ALERT_descriptions[description]);
84b90d2014-05-04Martin Nilsson 
b492c82014-11-25Martin Nilsson  if ( (certificate_state == CERT_requested) && (context->auth_level == AUTHLEVEL_ask) )
84b90d2014-05-04Martin Nilsson  { certificate_state = CERT_no_certificate; return 0; } else {
1e3a132015-02-25Martin Nilsson  COND_FATAL(1, ((certificate_state == CERT_requested) ? ALERT_handshake_failure : ALERT_unexpected_message), "Certificate required.\n");
84b90d2014-05-04Martin Nilsson  } } #ifdef SSL3_DEBUG else
a032542014-05-19Martin Nilsson  werror("SSL.Connection: Received warning alert %O\n", ALERT_descriptions[description]);
84b90d2014-05-04Martin Nilsson #endif return 0; }
da33812004-01-14H. William Welliver III 
c3e9412015-07-31Martin Nilsson int(-1..0) handle_change_cipher(int c)
84b90d2014-05-04Martin Nilsson {
1e3a132015-02-25Martin Nilsson  COND_FATAL(!expect_change_cipher || (c != 1), ALERT_unexpected_message, "Unexpected change cipher!\n"); if (sizeof(pending_read_state)) { SSL3_DEBUG_MSG("%O: Changing read state.\n", this); current_read_state = pending_read_state[0]; pending_read_state = pending_read_state[1..]; } else { error("No new read state pending!\n");
84b90d2014-05-04Martin Nilsson  }
1e3a132015-02-25Martin Nilsson  expect_change_cipher--; return 0;
84b90d2014-05-04Martin Nilsson } void send_heartbeat() {
2ed01a2014-05-23Henrik Grubbström (Grubba)  if ((state != CONNECTION_ready) ||
84b90d2014-05-04Martin Nilsson  (session->heartbeat_mode != HEARTBEAT_MODE_peer_allowed_to_send)) { // We're not allowed to send heartbeats. return; }
7d55002014-11-24Martin Nilsson  Buffer hb_msg = Buffer();
16d2f12014-11-21Martin Nilsson  hb_msg->add_int(HEARTBEAT_MESSAGE_request, 1); hb_msg->add_int(16, 2);
84b90d2014-05-04Martin Nilsson  int now = gethrtime();
16d2f12014-11-21Martin Nilsson  hb_msg->add(heartbeat_encode->crypt(sprintf("%8c%8c", now, now)));
84b90d2014-05-04Martin Nilsson  // We pad to an even 64 bytes.
d2e7292016-04-04Martin Nilsson  int(0..) bytes = [int(0..)]max(0, 64 - sizeof(hb_msg)); hb_msg->add(random_string(bytes));
09f63c2014-11-25Martin Nilsson  send_packet(heartbeat_packet(hb_msg));
84b90d2014-05-04Martin Nilsson } void handle_heartbeat(string(8bit) s) { if (sizeof(s) < 19) return; // Minimum size for valid heartbeats.
7d55002014-11-24Martin Nilsson  Buffer hb_msg = Buffer(s);
16d2f12014-11-21Martin Nilsson  int hb_type = hb_msg->read_int(1); int hb_len = hb_msg->read_int(2);
84b90d2014-05-04Martin Nilsson 
dfad6e2015-03-11Henrik Grubbström (Grubba)  SSL3_DEBUG_MSG("SSL.Connection: Heartbeat %s (%d bytes)\n",
84b90d2014-05-04Martin Nilsson  fmt_constant(hb_type, "HEARTBEAT_MESSAGE"), hb_len); string(8bit) payload;
d2e7292016-04-04Martin Nilsson  int(0..) pad_len = 16;
84b90d2014-05-04Martin Nilsson  // 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
16d2f12014-11-21Martin Nilsson  payload = hb_msg->read();
84b90d2014-05-04Martin Nilsson  if (sizeof(payload) < hb_len) { payload = payload + random_string(hb_len - sizeof(payload)); } else { payload = payload[..hb_len-1]; } #else return; #endif } else {
16d2f12014-11-21Martin Nilsson  payload = hb_msg->read(hb_len);
84b90d2014-05-04Martin Nilsson  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.
7d55002014-11-24Martin Nilsson  hb_msg = Buffer();
16d2f12014-11-21Martin Nilsson  hb_msg->add_int(HEARTBEAT_MESSAGE_response, 1); hb_msg->add_int(hb_len, 2);
3210bb2017-02-03Henrik Grubbström (Grubba)  hb_msg->add(payload); hb_msg->add(random_string(pad_len));
09f63c2014-11-25Martin Nilsson  send_packet(heartbeat_packet(hb_msg));
84b90d2014-05-04Martin Nilsson  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) {
7d55002014-11-24Martin Nilsson  hb_msg = Buffer(heartbeat_decode->crypt(payload));
16d2f12014-11-21Martin Nilsson  int a = hb_msg->read_int(8); int b = hb_msg->read_int(8);
84b90d2014-05-04Martin Nilsson  if (a != b) { if (!b) { // Heartbleed probe response.
7f45cf2014-05-15Martin Nilsson  send_packet(alert(ALERT_fatal, ALERT_insufficient_security,
84b90d2014-05-04Martin Nilsson  "Peer suffers from a bleeding heart.\n")); } break; } #ifdef SSL3_DEBUG int delta = gethrtime() - a;
938d512014-05-16Martin Nilsson  SSL3_DEBUG_MSG("SSL.Connection: Heartbeat roundtrip: %dus\n", delta);
84b90d2014-05-04Martin Nilsson #endif } break; default: break; } }
af9ae22015-03-30Martin Nilsson Stdio.Buffer handshake_buffer = Stdio.Buffer(); // Error mode 0.
0bf8452015-03-31Martin Nilsson Stdio.Buffer alert_buffer = Stdio.Buffer();
84b90d2014-05-04Martin Nilsson 
4eacaa2014-05-18Henrik Grubbström (Grubba) //! Main receive handler. //! //! @param data //! String of data received from the peer. //! //! @returns //! Returns one of: //! @mixed //! @type string(zero) //! Returns an empty string if there's neither application data //! nor errors (eg during the initial handshake). //! @type string(8bit) //! Returns a string of received application data. //! @type int(1..1) //! Returns @expr{1@} if the peer has closed the connection. //! @type int(-1..-1) //! Returns @expr{-1@} if an error has occurred. //! //! These are the main cases of errors: //! @ul //! @item //! There was a low-level protocol communications failure //! (the data didn't look like an SSL packet), in which case //! the alert_callback will be called with the raw packet data. //! This can eg be used to detect HTTP clients connecting to //! an HTTPS server and similar. //! @item //! The peer has sent an @[Alert] packet, and @[handle_alert()] //! for it has returned -1. //! @item //! The peer has sent an unsupported/illegal sequence of //! packets, in which case a suitable @[Alert] will have been //! generated and queued for sending to the peer. //! @endul //! @endmixed
84b90d2014-05-04Martin Nilsson //! //! This function is intended to be called from an i/o read callback.
c3e9412015-07-31Martin Nilsson string(8bit)|int(-1..1) got_data(string(8bit) data)
84b90d2014-05-04Martin Nilsson {
2ed01a2014-05-23Henrik Grubbström (Grubba)  if (state & CONNECTION_peer_closed) {
4eacaa2014-05-18Henrik Grubbström (Grubba)  // The peer has closed the connection.
84b90d2014-05-04Martin Nilsson  return 1; }
2ed01a2014-05-23Henrik Grubbström (Grubba)  // If closing we continue to try to read a remote close message. // That enables the caller to check for a clean close, and
84b90d2014-05-04Martin Nilsson  // to get the leftovers after the SSL connection.
7197b02015-04-22Martin Nilsson  session->last_activity = time(1);
59a60b2015-04-13Martin Nilsson  read_buffer->add(data);
ce5ffa2015-04-13Martin Nilsson  Stdio.Buffer.RewindKey read_buffer_key = read_buffer->rewind_key();
59a60b2015-04-13Martin Nilsson 
4eacaa2014-05-18Henrik Grubbström (Grubba)  string(8bit) res = "";
84b90d2014-05-04Martin Nilsson  Packet packet;
59a60b2015-04-13Martin Nilsson  while (packet = recv_packet())
84b90d2014-05-04Martin Nilsson  { if (packet->is_alert)
4d3b392015-04-13Martin Nilsson  { // recv_packet returns packets with is_alert set if it is // generated on our side, as opposed to an alert that is // received. These are always fatal (wrong packet type, packet // version, packet size).
938d512014-05-16Martin Nilsson  SSL3_DEBUG_MSG("SSL.Connection: Bad received packet\n");
84b90d2014-05-04Martin Nilsson  if (alert_callback)
ce5ffa2015-04-13Martin Nilsson  { Stdio.Buffer.RewindKey here = read_buffer->rewind_key(); read_buffer_key->rewind(); alert_callback(packet, current_read_state->seq_num, (string)read_buffer); here->rewind(); }
4d3b392015-04-13Martin Nilsson  // We or the packet may have been destructed by the // alert_callback.
68ac5e2014-11-13Henrik Grubbström (Grubba)  if (this && packet) send_packet(packet);
4d3b392015-04-13Martin Nilsson  return -1;
84b90d2014-05-04Martin Nilsson  }
4d3b392015-04-13Martin Nilsson  SSL3_DEBUG_MSG("SSL.Connection: received packet of type %d\n", packet->content_type); switch (packet->content_type)
84b90d2014-05-04Martin Nilsson  {
4d3b392015-04-13Martin Nilsson  case PACKET_alert:
84b90d2014-05-04Martin Nilsson  {
4d3b392015-04-13Martin Nilsson  SSL3_DEBUG_MSG("SSL.Connection: ALERT\n"); COND_FATAL(!sizeof(packet->fragment), ALERT_unexpected_message, "Zero length Alert fragments not allowed.\n");
c3e9412015-07-31Martin Nilsson  int(-1..1) err = 0;
4d3b392015-04-13Martin Nilsson  alert_buffer->add( packet->fragment ); while(!err && sizeof(alert_buffer)>1) err = handle_alert(alert_buffer->read(2)); if (err)
c3e9412015-07-31Martin Nilsson  {
4d3b392015-04-13Martin Nilsson  if (err > 0 && sizeof (res))
c3e9412015-07-31Martin Nilsson  { // If we get a close then we return the data we got so // far. state has CONNECTION_peer_closed at this point.
4d3b392015-04-13Martin Nilsson  return res;
c3e9412015-07-31Martin Nilsson  } return err; }
4d3b392015-04-13Martin Nilsson  break; } case PACKET_change_cipher_spec: { SSL3_DEBUG_MSG("SSL.Connection: CHANGE_CIPHER_SPEC\n"); COND_FATAL(!sizeof(packet->fragment), ALERT_unexpected_message, "Zero length ChangeCipherSpec fragments not allowed.\n"); COND_FATAL(version >= PROTOCOL_TLS_1_3, ALERT_unexpected_message, "ChangeCipherSpec not allowed in TLS 1.3 and later.\n"); foreach(packet->fragment;; int c) {
c3e9412015-07-31Martin Nilsson  int(-1..0) err = handle_change_cipher(c);
4d3b392015-04-13Martin Nilsson  SSL3_DEBUG_MSG("tried change_cipher: %d\n", err); if (err) return err; } break; } case PACKET_handshake: { SSL3_DEBUG_MSG("SSL.Connection: HANDSHAKE\n"); COND_FATAL(!sizeof(packet->fragment), ALERT_unexpected_message, "Zero length Handshake fragments not allowed.\n"); // 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. COND_FATAL(!(state & CONNECTION_handshaking) && !secure_renegotiation, ALERT_no_renegotiation, "Renegotiation not supported in unsecure mode.\n");
c22fcb2015-09-13Henrik Grubbström (Grubba)  COND_FATAL(!(state & CONNECTION_handshaking) && !context->enable_renegotiation, ALERT_no_renegotiation, "Renegotiation disabled by context.\n");
4d3b392015-04-13Martin Nilsson  /* 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. COND_FATAL(expect_change_cipher && (version < PROTOCOL_TLS_1_3), ALERT_unexpected_message, "Expected change cipher.\n");
c3e9412015-07-31Martin Nilsson  int(-1..1) err;
4d3b392015-04-13Martin Nilsson  handshake_buffer->add( packet->fragment ); while (sizeof(handshake_buffer) >= 4) { Stdio.Buffer.RewindKey key = handshake_buffer->rewind_key(); int type = handshake_buffer->read_int8(); Buffer input = Buffer(handshake_buffer->read_hbuffer(3)); if(!input) { // Not enough data. key->rewind(); break; } int len = 1+3+sizeof(input); key->rewind(); Stdio.Buffer raw = handshake_buffer->read_buffer(len);
6f35e92014-05-05Martin Nilsson  mixed exception = catch {
4d3b392015-04-13Martin Nilsson  err = handle_handshake(type, input, raw); COND_FATAL(err>=0 && sizeof(input), ALERT_record_overflow, sprintf("Extraneous handshake packet data (%O).\n", type));
6f35e92014-05-05Martin Nilsson  }; if( exception ) {
7d55002014-11-24Martin Nilsson  if( objectp(exception) && ([object]exception)->buffer_error )
6f35e92014-05-05Martin Nilsson  { Error.Generic e = [object(Error.Generic)]exception;
1e3a132015-02-25Martin Nilsson  COND_FATAL(1, ALERT_decode_error, e->message());
6f35e92014-05-05Martin Nilsson  } throw(exception); }
4d3b392015-04-13Martin Nilsson  if (err < 0) return err; if (err > 0) { state &= ~CONNECTION_handshaking; if ((version >= PROTOCOL_TLS_1_3) || expect_change_cipher) { // NB: Renegotiation is available in TLS 1.2 and earlier. COND_FATAL(sizeof(handshake_buffer), ALERT_unexpected_message, "Extraneous handshake packets.\n"); } COND_FATAL(sizeof(handshake_buffer) && !secure_renegotiation, ALERT_no_renegotiation, "Renegotiation not supported in unsecure mode.\n"); } } break; } case PACKET_application_data: SSL3_DEBUG_MSG("SSL.Connection: APPLICATION_DATA\n"); COND_FATAL(state & CONNECTION_handshaking, ALERT_unexpected_message, "Handshake not finished yet!\n"); res += packet->fragment; break; case PACKET_heartbeat: { // RFC 6520. SSL3_DEBUG_MSG("SSL.Connection: Heartbeat.\n"); if (state != CONNECTION_ready) { // 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; } mixed exception = catch { handle_heartbeat(packet->fragment); }; if( exception ) { if( objectp(exception) && ([object]exception)->buffer_error ) { Error.Generic e = [object(Error.Generic)]exception; COND_FATAL(1, ALERT_decode_error, e->message()); } throw(exception); }
6f35e92014-05-05Martin Nilsson 
84b90d2014-05-04Martin Nilsson  }
4d3b392015-04-13Martin Nilsson  break; default: COND_FATAL(state & CONNECTION_handshaking, ALERT_unexpected_message, "Unexpected message during handshake!\n"); // 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;
84b90d2014-05-04Martin Nilsson  }
813b392000-08-04Andreas Sigfridsson  }
59a60b2015-04-13Martin Nilsson 
4eacaa2014-05-18Henrik Grubbström (Grubba)  if (sizeof(res)) return res;
2ed01a2014-05-23Henrik Grubbström (Grubba)  if (state & CONNECTION_peer_closed) return 1;
4eacaa2014-05-18Henrik Grubbström (Grubba)  return "";
33ef431997-03-13Niels Möller }