c0b44e2003-01-27Martin Nilsson #pike __REAL_VERSION__
2e88fc2004-01-25Martin Nilsson #pragma strict_types
e1fb092014-02-14Martin Nilsson #require constant(SSL.Cipher)
33ef431997-03-13Niels Möller 
f5bb032001-09-17Martin Nilsson //! The most important information in a session object is a //! choice of encryption algorithms and a "master secret" created by //! keyexchange with a client. Each connection can either do a full key //! exchange to established a new session, or reuse a previously //! established session. That is why we have the session abstraction and //! the session cache. Each session is used by one or more connections, in //! sequence or simultaneously. //! //! It is also possible to change to a new session in the middle of a //! connection.
3c859d2015-02-25Martin Nilsson #include "tls.h"
a2d1fd2014-05-15Martin Nilsson import "."; import Constants;
33ef431997-03-13Niels Möller 
7197b02015-04-22Martin Nilsson //! When this session object was used last. int last_activity = time();
f5bb032001-09-17Martin Nilsson //! Identifies the session to the server
2d40602014-05-16Martin Nilsson string(8bit) identity;
33ef431997-03-13Niels Möller 
372b2a2016-07-13Henrik Grubbström (Grubba) //! Alternative identification of the session to the server. //! @seealso //! @rfc{4507@}, @rfc{5077@} string(8bit) ticket; //! Expiry time for @[ticket]. int ticket_expiry_time;
f5bb032001-09-17Martin Nilsson //! Always COMPRESSION_null.
33ef431997-03-13Niels Möller int compression_algorithm;
f5bb032001-09-17Martin Nilsson 
8a08a62003-10-24Martin Stjernholm //! Constant defining a choice of keyexchange, encryption and mac
f5bb032001-09-17Martin Nilsson //! algorithm.
33ef431997-03-13Niels Möller int cipher_suite;
f5bb032001-09-17Martin Nilsson  //! Information about the encryption method derived from the //! cipher_suite.
a2d1fd2014-05-15Martin Nilsson Cipher.CipherSpec cipher_spec;
f5bb032001-09-17Martin Nilsson  //! 48 byte secret shared between the client and the server. Used for //! deriving the actual keys.
2d40602014-05-16Martin Nilsson string(8bit) master_secret;
33ef431997-03-13Niels Möller 
c41c692014-08-23Martin Nilsson //! Information about the certificate in use by the peer, such as //! issuing authority, and verification status.
f591dd2004-01-29H. William Welliver III mapping cert_data;
68b67e2014-04-05Henrik Grubbström (Grubba) //! Negotiated protocol version. ProtocolVersion version;
9ece162004-01-14H. William Welliver III 
a8a9a02015-04-04Henrik Grubbström (Grubba) //! The peer certificate chain
1ecaa22014-02-03Henrik Grubbström (Grubba) array(string(8bit)) peer_certificate_chain;
45c1e11999-03-19Niels Möller 
a8a9a02015-04-04Henrik Grubbström (Grubba) //! Our certificate chain
1ecaa22014-02-03Henrik Grubbström (Grubba) array(string(8bit)) certificate_chain;
88cfa12005-10-28H. William Welliver III 
57b5952014-01-19Henrik Grubbström (Grubba) //! Our private key.
6222d22014-08-14Henrik Grubbström (Grubba) Crypto.Sign.State private_key;
c51f9c2012-08-30Bill Welliver 
57b5952014-01-19Henrik Grubbström (Grubba) //! The peer's public key (from the certificate).
6222d22014-08-14Henrik Grubbström (Grubba) Crypto.Sign.State peer_public_key;
c51f9c2012-08-30Bill Welliver 
0dd4f82014-03-20Henrik Grubbström (Grubba) //! The max fragment size requested by the client. int max_packet_size = PACKET_MAX_SIZE;
3db50f2014-03-23Henrik Grubbström (Grubba) //! Indicates that the packet HMACs should be truncated
0c4ea52015-08-22Martin Nilsson //! to the first 10 bytes (80 bits). Cf @rfc{3546:3.5@}.
3db50f2014-03-23Henrik Grubbström (Grubba) int(0..1) truncated_hmac;
1b04c72015-02-22Henrik Grubbström (Grubba) //! Indicates that the connection uses the Extended Master Secret method //! of deriving the master secret. //! //! This setting is only relevant for TLS 1.2 and earlier. int(0..1) extended_master_secret;
968d5d2014-11-29Henrik Grubbström (Grubba) protected void create(string(8bit)|void id)
351cf22014-11-25Martin Nilsson {
f0a0212015-04-05Martin Nilsson  identity = id;
351cf22014-11-25Martin Nilsson }
6a0e942014-02-02Henrik Grubbström (Grubba) /* * Extensions provided by the peer. */
0c4ea52015-08-22Martin Nilsson //! @rfc{6066:3.1@} (SNI)
6542d42014-06-09Martin Nilsson string(8bit) server_name;
6a0e942014-02-02Henrik Grubbström (Grubba) 
cec12e2014-07-07Henrik Grubbström (Grubba) //! The set of <hash, signature> combinations supported by the peer.
6a0e942014-02-02Henrik Grubbström (Grubba) //! //! Only used with TLS 1.2 and later. //!
0c4ea52015-08-22Martin Nilsson //! Defaults to the settings from @rfc{5246:7.4.1.4.1@}.
6a0e942014-02-02Henrik Grubbström (Grubba) array(array(int)) signature_algorithms = ({
4232d42014-03-24Henrik Grubbström (Grubba)  // RFC 5246 7.4.1.4.1: // Note: this is a change from TLS 1.1 where there are no explicit // rules, but as a practical matter one can assume that the peer // supports MD5 and SHA-1.
270d242015-11-01Martin Nilsson  ({ HASH_sha1, SIGNATURE_rsa }), ({ HASH_sha1, SIGNATURE_dsa }), ({ HASH_sha1, SIGNATURE_ecdsa }),
6a0e942014-02-02Henrik Grubbström (Grubba) });
14f8162014-12-15Henrik Grubbström (Grubba) //! Supported finite field diffie-hellman groups in order of preference. //! //! @mixed //! @type int(0..0) //! Zero indicates that none have been specified. //! @type array(zero) //! The empty array indicates that none are supported. //! @type array(int) //! List of supported groups, with the most preferred first. //! @endmixed array(int) ffdhe_groups;
6a0e942014-02-02Henrik Grubbström (Grubba) //! Supported elliptical curve cipher curves in order of preference. array(int) ecc_curves = ({}); //! The selected elliptical curve point format. //! //! @note //! May be @expr{-1@} to indicate that there's no supported overlap //! between the server and client. int ecc_point_format = POINT_uncompressed;
0fddf02014-06-29Henrik Grubbström (Grubba) //! Negotiated encrypt-then-mac mode. int encrypt_then_mac = 0;
6a0e942014-02-02Henrik Grubbström (Grubba) /* * End of extensions. */
2285362013-12-31Henrik Grubbström (Grubba) #if constant(Crypto.ECC.Curve)
10333f2014-03-12Henrik Grubbström (Grubba) //! The ECC curve selected by the key exchange. //! //! @int //! @value KE_ecdh_ecdsa //! @value KE_ecdh_rsa //! The curve from the server certificate. //! //! @value KE_ecdhe_ecdsa //! @value KE_ecdhe_rsa //! @value KE_ecdh_anon //! The curve selected for the ECDHE key exchange //! (typically the largest curve supported by both //! the client and the server). //! @endint
2285362013-12-31Henrik Grubbström (Grubba) Crypto.ECC.Curve curve; #endif /* Crypto.ECC.Curve */
4b28272014-03-30Henrik Grubbström (Grubba) //! Heartbeat mode. HeartBeatModeType heartbeat_mode = HEARTBEAT_MODE_disabled;
67cec22013-11-11Martin Nilsson //! Indicates if this session has the required server certificate keys //! set. No means that no or the wrong type of certificate was sent //! from the server. int(0..1) has_required_certificates() {
9310212014-08-01Martin Nilsson  if (!peer_public_key) return (cipher_spec->signature_alg == SIGNATURE_anonymous);
57b5952014-01-19Henrik Grubbström (Grubba)  return 1;
67cec22013-11-11Martin Nilsson }
57df062014-03-08Henrik Grubbström (Grubba) //! Used to filter certificates not supported by the peer. //! //! @param cp //! Candidate @[CertificatePair]. //! //! @param version //! Negotiated version of SSL. //! //! @param ecc_curves //! The set of ecc_curves supported by the peer. protected int(0..1) is_supported_cert(CertificatePair cp,
d77a6e2014-03-14Henrik Grubbström (Grubba)  int ke_mask,
c539db2014-07-19Henrik Grubbström (Grubba)  int h_max,
68b67e2014-04-05Henrik Grubbström (Grubba)  ProtocolVersion version,
57df062014-03-08Henrik Grubbström (Grubba)  array(int) ecc_curves) {
4232d42014-03-24Henrik Grubbström (Grubba)  // Check if the certificate is useful for any of the // key exchange algorithms that the peer supports.
57df062014-03-08Henrik Grubbström (Grubba)  if (version >= PROTOCOL_TLS_1_2) {
4232d42014-03-24Henrik Grubbström (Grubba)  // In TLS 1.2 and later DH_DSS/DH_RSA and ECDH_ECDSA/ECDH_RSA // have been unified, so use the invariant ke_mask. // They have been unified, since the signature_algorithms // extension allows the peer to specify exactly which // combinations it supports, cf below.
d77a6e2014-03-14Henrik Grubbström (Grubba)  if (!(ke_mask & cp->ke_mask_invariant)) return 0;
4232d42014-03-24Henrik Grubbström (Grubba)  // Check that all sign_algs in the cert chain are supported by the peer. foreach(cp->sign_algs, array(int) sign_alg) { int found; foreach(signature_algorithms, array(int) sup_alg) { if (found = equal(sign_alg, sup_alg)) break; } if (!found) return 0; }
0384b52014-09-12Martin Nilsson  } else if (!(ke_mask & cp->ke_mask)) return 0;
57df062014-03-08Henrik Grubbström (Grubba)  #if constant(Crypto.ECC.Curve)
f4ca2a2015-01-25Martin Nilsson  if (cp->key->get_curve) {
57df062014-03-08Henrik Grubbström (Grubba)  // Is the ECC curve supported by the client? Crypto.ECC.Curve c =
f4ca2a2015-01-25Martin Nilsson  ([object(Crypto.ECC.Curve.ECDSA)]cp->key)->get_curve();
fe1d062014-05-16Martin Nilsson  SSL3_DEBUG_MSG("Curve: %O (%O)\n",
57df062014-03-08Henrik Grubbström (Grubba)  c, ECC_NAME_TO_CURVE[c->name()]); return has_value(ecc_curves, ECC_NAME_TO_CURVE[c->name()]); } #endif return 1; } //! Used to filter the set of cipher suites suggested by the peer //! based on our available certificates. //! //! @param suite //! Candidate cipher suite. //!
d77a6e2014-03-14Henrik Grubbström (Grubba) //! @param ke_mask //! The bit mask of the key exchange algorithms supported by //! the set of available certificates.
d156952014-03-22Henrik Grubbström (Grubba) //! //! @param version //! The negotiated version of SSL/TLS.
68b67e2014-04-05Henrik Grubbström (Grubba) int(0..1) is_supported_suite(int suite, int ke_mask, ProtocolVersion version)
57df062014-03-08Henrik Grubbström (Grubba) { array(int) suite_info = [array(int)]CIPHER_SUITES[suite]; if (!suite_info) {
d77a6e2014-03-14Henrik Grubbström (Grubba)  SSL3_DEBUG_MSG("Suite %s is not supported.\n", fmt_cipher_suite(suite));
57df062014-03-08Henrik Grubbström (Grubba)  return 0; }
10333f2014-03-12Henrik Grubbström (Grubba)  KeyExchangeType ke = [int(0..0)|KeyExchangeType]suite_info[0];
d156952014-03-22Henrik Grubbström (Grubba)  if (!(ke_mask & (1<<ke))) return 0;
c539db2014-07-19Henrik Grubbström (Grubba)  if (version < PROTOCOL_TLS_1_2) { if (sizeof(suite_info) >= 4) { // AEAD protocols are not supported prior to TLS 1.2. // Variant cipher-suite dependent prfs are not supported prior to TLS 1.2. return 0; }
8f71842015-11-27Henrik Grubbström (Grubba)  if (suite_info[2] > HASH_sha1) { // Hash algorithms other than md5 and sha1 are not supported // prior to TLS 1.2. return 0; }
c539db2014-07-19Henrik Grubbström (Grubba)  // FIXME: Check hash size >= cert hash size.
d156952014-03-22Henrik Grubbström (Grubba)  }
96eb0e2015-02-23Martin Nilsson  if (version >= PROTOCOL_TLS_1_1) { if (suite == SSL_null_with_null_null) { // This suite is not allowed to be negotiated in TLS 1.1. return 0; } if ( (< CIPHER_rc4_40, CIPHER_rc2_40, CIPHER_des40 >)[suite_info[1]]) { // RFC 4346 A.5: Export suites // TLS 1.1 implementations MUST NOT negotiate // these cipher suites in TLS 1.1 mode. // ... // TLS 1.1 clients MUST check that the server // did not choose one of these cipher suites // during the handshake. return 0; }
d156952014-03-22Henrik Grubbström (Grubba)  } return 1;
57df062014-03-08Henrik Grubbström (Grubba) }
e169ca2015-02-26Martin Nilsson private array(CertificatePair) select_certificates(array(CertificatePair) certs, array(int) cipher_suites, ProtocolVersion version)
1ecaa22014-02-03Henrik Grubbström (Grubba) {
57df062014-03-08Henrik Grubbström (Grubba)  SSL3_DEBUG_MSG("Candidate certificates: %O\n", certs);
c41c692014-08-23Martin Nilsson  // Find the set of key exchange and hash algorithms supported by the // client.
d77a6e2014-03-14Henrik Grubbström (Grubba)  int ke_mask = 0;
c539db2014-07-19Henrik Grubbström (Grubba)  int h_max = 0;
d77a6e2014-03-14Henrik Grubbström (Grubba)  foreach(cipher_suites, int suite) { if (CIPHER_SUITES[suite]) {
6799472015-09-25Martin Nilsson  ke_mask |= 1 << [int(0..22)](CIPHER_SUITES[suite][0]);
7b3a842014-07-20Henrik Grubbström (Grubba)  Crypto.Hash hash = [object(Crypto.Hash)]HASH_lookup[CIPHER_SUITES[suite][2]];
c539db2014-07-19Henrik Grubbström (Grubba)  if (hash && (hash->digest_size() > h_max)) { h_max = hash->digest_size(); }
d77a6e2014-03-14Henrik Grubbström (Grubba)  } }
b551892014-10-15Henrik Grubbström (Grubba) #if constant(Crypto.ECC.Curve)
3151af2015-02-23Martin Nilsson  if (!sizeof(ecc_curves) || ecc_point_format==-1) {
bde0aa2015-02-23Martin Nilsson  // Client and server have no common curves, so remove ECC from KE // mask. This would be caught anyway in the curve check in // is_supported_cert, but this gives the code an earlier out. ke_mask &= ~KE_ecc_mask;
b551892014-10-15Henrik Grubbström (Grubba)  } #endif
57df062014-03-08Henrik Grubbström (Grubba)  // Filter any certs that the client doesn't support. certs = [array(CertificatePair)]
c539db2014-07-19Henrik Grubbström (Grubba)  filter(certs, is_supported_cert, ke_mask, h_max, version, ecc_curves);
57df062014-03-08Henrik Grubbström (Grubba) 
0384b52014-09-12Martin Nilsson  if( version<PROTOCOL_TLS_1_2 && sizeof(certs)>1 ) { // GNU-TLS doesn't like eg SHA being used with SHA256 certs. // FIXME: Can this be made more narrow? array(CertificatePair) c = [array(CertificatePair)] filter(certs, lambda(CertificatePair cp) { Crypto.Hash hash = [object(Crypto.Hash)] HASH_lookup[cp->sign_algs[0][0]]; return hash->digest_size() <= h_max; }); // Don't clear out the entire list though, as that makes all peers // fail. if( sizeof(c) ) certs = c; }
57df062014-03-08Henrik Grubbström (Grubba)  SSL3_DEBUG_MSG("Client supported certificates: %O\n", certs);
e169ca2015-02-26Martin Nilsson  return certs; } //! Selects an apropriate certificate, authentication method //! and cipher suite for the parameters provided by the client. //! //! @param certs //! The list of @[CertificatePair]s that are applicable to the //! @[server_name] of this session. //! //! @param cipher_suites //! The set of cipher suites that the client and server have in //! common. //! //! @param version //! The SSL protocol version to use. //! //! Typical client extensions that also are used: //! @dl //! @item @[signature_algorithms] //! The set of signature algorithm tuples that //! the client claims to support. //! @enddl int select_cipher_suite(array(CertificatePair) certs, array(int) cipher_suites, ProtocolVersion version) { if (!sizeof(cipher_suites)) return 0; if (!certs || !sizeof(certs)) { SSL3_DEBUG_MSG("No certificates.\n"); foreach(cipher_suites, int suite) if (KE_Anonymous[CIPHER_SUITES[suite][0]]) return set_cipher_suite(suite, version, 0, 0); return 0; } certs = select_certificates(certs, cipher_suites, version);
57df062014-03-08Henrik Grubbström (Grubba) 
d77a6e2014-03-14Henrik Grubbström (Grubba)  // Find the set of key exchange algorithms supported by // the remaining certs.
e169ca2015-02-26Martin Nilsson  int ke_mask = (1<<KE_null)|(1<<KE_dh_anon)|(1<<KE_psk)|(1<<KE_dhe_psk)
d77a6e2014-03-14Henrik Grubbström (Grubba) #if constant(Crypto.ECC.Curve)
34b5a12015-04-09Martin Nilsson  |(1<<KE_ecdh_anon)|(1<<KE_ecdhe_psk)
d77a6e2014-03-14Henrik Grubbström (Grubba) #endif ; if (version >= PROTOCOL_TLS_1_2) { ke_mask = `|(ke_mask, @certs->ke_mask_invariant); } else { ke_mask = `|(ke_mask, @certs->ke_mask); }
b551892014-10-15Henrik Grubbström (Grubba) #if constant(Crypto.ECC.Curve)
3151af2015-02-23Martin Nilsson  if (!sizeof(ecc_curves) || ecc_point_format==-1) {
a8a9a02015-04-04Henrik Grubbström (Grubba)  // The client may claim to support ECC, but hasn't sent the // required extension or any curves that we support, so // remove ECC from KE mask.
41fb392015-02-23Martin Nilsson  ke_mask &= ~KE_ecc_mask;
b551892014-10-15Henrik Grubbström (Grubba)  } #endif
14f8162014-12-15Henrik Grubbström (Grubba)  if (!sizeof(ffdhe_groups)) { // The client doesn't support the same set of Finite Field // Diffie-Hellman groups as we do, so filter DHE. ke_mask &= ~((1<<KE_dhe_dss)|(1<<KE_dhe_rsa)| (1<<KE_dh_anon)|(1<<KE_dhe_psk)); }
5308272015-01-17Henrik Grubbström (Grubba)  if (version >= PROTOCOL_TLS_1_3) { // TLS 1.3 and later only support ephemeral keyexchanges. ke_mask &= ((1<<KE_dhe_dss)|(1<<KE_dhe_rsa)|(1<<KE_dh_anon)| (1<<KE_ecdhe_ecdsa)|(1<<KE_ecdhe_rsa)|(1<<KE_ecdh_anon)); }
57df062014-03-08Henrik Grubbström (Grubba)  // Given the set of certs, filter the set of client_suites, // to find the best.
5e09c92015-02-20Martin Nilsson  int suite = -1; foreach(cipher_suites, int s) if( is_supported_suite(s, ke_mask, version) ) { suite = s; break; }
57df062014-03-08Henrik Grubbström (Grubba) 
5e09c92015-02-20Martin Nilsson  if (suite==-1) {
57df062014-03-08Henrik Grubbström (Grubba)  SSL3_DEBUG_MSG("No suites left after certificate filtering.\n");
1ecaa22014-02-03Henrik Grubbström (Grubba)  return 0;
57df062014-03-08Henrik Grubbström (Grubba)  }
1ecaa22014-02-03Henrik Grubbström (Grubba) 
6faad92015-02-23Martin Nilsson  SSL3_DEBUG_MSG("selected suite:\n%s\n", fmt_cipher_suite(suite));
57df062014-03-08Henrik Grubbström (Grubba) 
2b72412014-08-06Martin Nilsson  int ke_method = [int]CIPHER_SUITES[suite][0];
57df062014-03-08Henrik Grubbström (Grubba)  SSL3_DEBUG_MSG("Selecting server key and certificate.\n"); int max_hash_size = 512; // Now we can select the actual cert to use.
b3ff3f2014-04-14Martin Nilsson  if ( !KE_Anonymous[ke_method] ) {
57df062014-03-08Henrik Grubbström (Grubba)  CertificatePair cert;
d77a6e2014-03-14Henrik Grubbström (Grubba)  if (version >= PROTOCOL_TLS_1_2) { foreach(certs, CertificatePair cp) {
d156952014-03-22Henrik Grubbström (Grubba)  if (is_supported_suite(suite, cp->ke_mask_invariant, version)) {
d77a6e2014-03-14Henrik Grubbström (Grubba)  cert = cp; break; } } } else { foreach(certs, CertificatePair cp) {
d156952014-03-22Henrik Grubbström (Grubba)  if (is_supported_suite(suite, cp->ke_mask, version)) {
d77a6e2014-03-14Henrik Grubbström (Grubba)  cert = cp; break; }
57df062014-03-08Henrik Grubbström (Grubba)  } } if (!cert) {
b3ff3f2014-04-14Martin Nilsson  error("No suitable certificate for selected cipher suite: %s.\n", fmt_cipher_suite(suite));
57df062014-03-08Henrik Grubbström (Grubba)  } private_key = cert->key; SSL3_DEBUG_MSG("Selected server key: %O\n", private_key); certificate_chain = cert->certs; #if constant(Crypto.ECC.Curve)
f4ca2a2015-01-25Martin Nilsson  if (private_key->get_curve) { curve = [object(Crypto.ECC.Curve)]private_key->get_curve();
57df062014-03-08Henrik Grubbström (Grubba)  } #endif /* Crypto.ECC.Curve */ if (private_key->block_size) { // FIXME: The maximum allowable hash size depends on the size of the // RSA key when RSA is in use. With a 64 byte (512 bit) key, // the block size is 61 bytes, allow for 23 bytes of overhead. max_hash_size = [int]private_key->block_size() - 23; } } return set_cipher_suite(suite, version, signature_algorithms, max_hash_size);
1ecaa22014-02-03Henrik Grubbström (Grubba) }
e7a27d2003-03-08Martin Nilsson //! Sets the proper authentication method and cipher specification
57b5952014-01-19Henrik Grubbström (Grubba) //! for the given parameters. //!
d036b32014-07-29Martin Nilsson //! @param suite //! The cipher suite to use, selected from the set that the client //! claims to support.
57b5952014-01-19Henrik Grubbström (Grubba) //! //! @param version //! The SSL protocol version to use. //! //! @param signature_algorithms
d036b32014-07-29Martin Nilsson //! The set of signature algorithms tuples that the client claims to //! support. //! //! @param max_hash_size //!
de71092014-08-06Martin Nilsson int set_cipher_suite(int suite, ProtocolVersion version,
57df062014-03-08Henrik Grubbström (Grubba)  array(array(int)) signature_algorithms, int max_hash_size)
33ef431997-03-13Niels Möller {
8e06a32014-09-30Martin Nilsson  this::version = version;
766ad12014-08-05Henrik Grubbström (Grubba) 
a21eea2014-08-06Martin Nilsson  cipher_spec = Cipher.lookup(suite, version, signature_algorithms,
a2d1fd2014-05-15Martin Nilsson  truncated_hmac?512:max_hash_size);
a21eea2014-08-06Martin Nilsson  if (!cipher_spec) return 0;
57df062014-03-08Henrik Grubbström (Grubba) 
a21eea2014-08-06Martin Nilsson  cipher_suite = suite;
12b0142014-08-04Martin Nilsson  SSL3_DEBUG_MSG("SSL.Session: cipher_spec %O\n", mkmapping(indices(cipher_spec), values(cipher_spec)));
cf48b92015-02-18Martin Nilsson  if (encrypt_then_mac) { // Check if enrypt-then-mac is valid for the suite. if (((sizeof(CIPHER_SUITES[suite]) == 3) && ((< CIPHER_rc4, CIPHER_rc4_40 >)[CIPHER_SUITES[suite][1]])) || ((sizeof(CIPHER_SUITES[suite]) == 4) && (CIPHER_SUITES[suite][3] != MODE_cbc))) { // Encrypt-then-MAC not allowed with non-CBC suites. encrypt_then_mac = 0; SSL3_DEBUG_MSG("Encrypt-then-MAC: Disabled (not valid for suite).\n"); } else { SSL3_DEBUG_MSG("Encrypt-then-MAC: Enabled.\n"); } }
e85ce52013-11-26Henrik Grubbström (Grubba)  return 1;
33ef431997-03-13Niels Möller }
3d35302014-08-06Martin Nilsson //! Sets the compression method. Currently only @[COMPRESSION_null] //! and @[COMPRESSION_deflate] are supported.
33ef431997-03-13Niels Möller void set_compression_method(int compr) {
3d35302014-08-06Martin Nilsson  if( !(< COMPRESSION_null, COMPRESSION_deflate >)[ compr ] )
6244142003-01-27Martin Nilsson  error( "Method not supported\n" );
3d35302014-08-06Martin Nilsson 
33ef431997-03-13Niels Möller  compression_algorithm = compr; }
2d40602014-05-16Martin Nilsson protected string(8bit) generate_key_block(string(8bit) client_random, string(8bit) server_random, ProtocolVersion version)
33ef431997-03-13Niels Möller {
ad2ef52013-10-12Henrik Grubbström (Grubba)  int required = 2 * ( cipher_spec->is_exportable ? (5 + cipher_spec->hash_size) : ( cipher_spec->key_material + cipher_spec->hash_size + cipher_spec->iv_size) );
2d40602014-05-16Martin Nilsson  string(8bit) key = "";
aa77d52001-04-18Pär Svensson 
0791b12013-11-24Henrik Grubbström (Grubba)  key = cipher_spec->prf(master_secret, "key expansion", server_random + client_random, required);
e7a27d2003-03-08Martin Nilsson 
12b0142014-08-04Martin Nilsson  SSL3_DEBUG_MSG("key_block: %O\n", key);
33ef431997-03-13Niels Möller  return key; }
aa77d52001-04-18Pär Svensson #ifdef SSL3_DEBUG
800a762017-09-22Chris Angelico protected void printKey(string name, string(8bit) key)
12b0142014-08-04Martin Nilsson {
5977ae2016-08-28Martin Nilsson  werror("%s: len:%d \t\t%x\n", name, sizeof(key), key);
aa77d52001-04-18Pär Svensson } #endif
e7a27d2003-03-08Martin Nilsson //! Generates keys appropriate for the SSL version given in @[version], //! based on the @[client_random] and @[server_random]. //! @returns //! @array //! @elem string 0 //! Client write MAC secret //! @elem string 1 //! Server write MAC secret //! @elem string 2 //! Client write key //! @elem string 3 //! Server write key //! @elem string 4 //! Client write IV //! @elem string 5 //! Server write IV //! @endarray
2d40602014-05-16Martin Nilsson array(string(8bit)) generate_keys(string(8bit) client_random, string(8bit) server_random, ProtocolVersion version)
33ef431997-03-13Niels Möller {
b4aa782014-11-21Martin Nilsson  Stdio.Buffer key_data = Stdio.Buffer(generate_key_block(client_random, server_random, version));
2d40602014-05-16Martin Nilsson  array(string(8bit)) keys = allocate(6);
33ef431997-03-13Niels Möller 
12b0142014-08-04Martin Nilsson  SSL3_DEBUG_MSG("client_random: %s\nserver_random: %s\nversion: %d.%d\n", client_random?String.string2hex(client_random):"NULL", server_random?String.string2hex(server_random):"NULL", version>>8, version & 0xff);
e7a27d2003-03-08Martin Nilsson  // client_write_MAC_secret
b4aa782014-11-21Martin Nilsson  keys[0] = key_data->read(cipher_spec->hash_size);
e7a27d2003-03-08Martin Nilsson  // server_write_MAC_secret
b4aa782014-11-21Martin Nilsson  keys[1] = key_data->read(cipher_spec->hash_size);
33ef431997-03-13Niels Möller 
ad2ef52013-10-12Henrik Grubbström (Grubba)  if (cipher_spec->is_exportable)
33ef431997-03-13Niels Möller  {
ad2ef52013-10-12Henrik Grubbström (Grubba)  // Exportable (ie weak) crypto.
68b67e2014-04-05Henrik Grubbström (Grubba)  if(version == PROTOCOL_SSL_3_0) {
ad2ef52013-10-12Henrik Grubbström (Grubba)  // SSL 3.0
b4aa782014-11-21Martin Nilsson  keys[2] = Crypto.MD5.hash(key_data->read(5) +
0791b12013-11-24Henrik Grubbström (Grubba)  client_random + server_random)
ad2ef52013-10-12Henrik Grubbström (Grubba)  [..cipher_spec->key_material-1];
b4aa782014-11-21Martin Nilsson  keys[3] = Crypto.MD5.hash(key_data->read(5) +
0791b12013-11-24Henrik Grubbström (Grubba)  server_random + client_random)
ad2ef52013-10-12Henrik Grubbström (Grubba)  [..cipher_spec->key_material-1]; if (cipher_spec->iv_size) {
0791b12013-11-24Henrik Grubbström (Grubba)  keys[4] = Crypto.MD5.hash(client_random + server_random)[..cipher_spec->iv_size-1]; keys[5] = Crypto.MD5.hash(server_random + client_random)[..cipher_spec->iv_size-1];
ad2ef52013-10-12Henrik Grubbström (Grubba)  }
68b67e2014-04-05Henrik Grubbström (Grubba)  } else if(version >= PROTOCOL_TLS_1_0) {
ad2ef52013-10-12Henrik Grubbström (Grubba)  // TLS 1.0 or later.
b4aa782014-11-21Martin Nilsson  string(8bit) client_wkey = key_data->read(5); string(8bit) server_wkey = key_data->read(5);
0791b12013-11-24Henrik Grubbström (Grubba)  keys[2] = cipher_spec->prf(client_wkey, "client write key", client_random + server_random, cipher_spec->key_material); keys[3] = cipher_spec->prf(server_wkey, "server write key", client_random + server_random, cipher_spec->key_material);
ad2ef52013-10-12Henrik Grubbström (Grubba)  if(cipher_spec->iv_size) {
2d40602014-05-16Martin Nilsson  string(8bit) iv_block =
0791b12013-11-24Henrik Grubbström (Grubba)  cipher_spec->prf("", "IV block", client_random + server_random, 2 * cipher_spec->iv_size);
ad2ef52013-10-12Henrik Grubbström (Grubba)  keys[4]=iv_block[..cipher_spec->iv_size-1]; keys[5]=iv_block[cipher_spec->iv_size..];
12b0142014-08-04Martin Nilsson  SSL3_DEBUG_MSG("sizeof(keys[4]):%d sizeof(keys[5]):%d\n", sizeof(keys[4]), sizeof(keys[4]));
ad2ef52013-10-12Henrik Grubbström (Grubba)  } }
d67d3e2015-02-27Martin Nilsson 
ad2ef52013-10-12Henrik Grubbström (Grubba)  } else {
b4aa782014-11-21Martin Nilsson  keys[2] = key_data->read(cipher_spec->key_material); keys[3] = key_data->read(cipher_spec->key_material);
ad2ef52013-10-12Henrik Grubbström (Grubba)  if (cipher_spec->iv_size) {
b4aa782014-11-21Martin Nilsson  keys[4] = key_data->read(cipher_spec->iv_size); keys[5] = key_data->read(cipher_spec->iv_size);
ad2ef52013-10-12Henrik Grubbström (Grubba)  }
33ef431997-03-13Niels Möller  }
aa77d52001-04-18Pär Svensson 
1e9ea82001-06-25Pär Svensson #ifdef SSL3_DEBUG
aa77d52001-04-18Pär Svensson  printKey( "client_write_MAC_secret",keys[0]); printKey( "server_write_MAC_secret",keys[1]);
2a28102015-03-10Henrik Grubbström (Grubba)  printKey( "client_write_key", keys[2]); printKey( "server_write_key", keys[3]);
d67d3e2015-02-27Martin Nilsson 
aa77d52001-04-18Pär Svensson  if(cipher_spec->iv_size) {
2a28102015-03-10Henrik Grubbström (Grubba)  printKey( "client_IV", keys[4]); printKey( "server_IV", keys[5]);
aa77d52001-04-18Pär Svensson  } else { werror("No IVs!!\n"); } #endif
d67d3e2015-02-27Martin Nilsson 
f4fcce1997-03-15Niels Möller  return keys;
33ef431997-03-13Niels Möller }
e7a27d2003-03-08Martin Nilsson //! Computes a new set of encryption states, derived from the
f5bb032001-09-17Martin Nilsson //! client_random, server_random and master_secret strings. //! //! @returns //! @array
938d512014-05-16Martin Nilsson //! @elem SSL.State read_state
f5bb032001-09-17Martin Nilsson //! Read state
938d512014-05-16Martin Nilsson //! @elem SSL.State write_state
f5bb032001-09-17Martin Nilsson //! Write state //! @endarray
91f9c72014-05-15Martin Nilsson array(State) new_server_states(.Connection con,
2d40602014-05-16Martin Nilsson  string(8bit) client_random, string(8bit) server_random,
68b67e2014-04-05Henrik Grubbström (Grubba)  ProtocolVersion version)
33ef431997-03-13Niels Möller {
91f9c72014-05-15Martin Nilsson  State write_state = State(con); State read_state = State(con);
68b67e2014-04-05Henrik Grubbström (Grubba)  array(string) keys = generate_keys(client_random, server_random, version);
33ef431997-03-13Niels Möller 
f4fcce1997-03-15Niels Möller  if (cipher_spec->mac_algorithm) {
715a112015-10-31Henrik Grubbström (Grubba)  SSL3_DEBUG_CRYPT_MSG("MAC algorithm: %O\n", cipher_spec->mac_algorithm);
f4fcce1997-03-15Niels Möller  read_state->mac = cipher_spec->mac_algorithm(keys[0]); write_state->mac = cipher_spec->mac_algorithm(keys[1]); } if (cipher_spec->bulk_cipher_algorithm) {
715a112015-10-31Henrik Grubbström (Grubba)  SSL3_DEBUG_CRYPT_MSG("Bulk cipher algorithm: %O\n", cipher_spec->bulk_cipher_algorithm);
f4fcce1997-03-15Niels Möller  read_state->crypt = cipher_spec->bulk_cipher_algorithm(); read_state->crypt->set_decrypt_key(keys[2]); write_state->crypt = cipher_spec->bulk_cipher_algorithm(); write_state->crypt->set_encrypt_key(keys[3]);
0753a92014-04-27Henrik Grubbström (Grubba)  if (cipher_spec->cipher_type == CIPHER_aead) { // AEAD algorithms use other iv methods. read_state->tls_iv = write_state->tls_iv = 0; read_state->salt = keys[4] || ""; write_state->salt = keys[5] || ""; } else if (cipher_spec->iv_size) { if (version >= PROTOCOL_TLS_1_1) { // TLS 1.1 and later have an explicit IV. read_state->tls_iv = write_state->tls_iv = cipher_spec->iv_size;
34289e2010-12-22Henrik Grubbström (Grubba)  }
0753a92014-04-27Henrik Grubbström (Grubba)  read_state->crypt->set_iv(keys[4]); write_state->crypt->set_iv(keys[5]);
34289e2010-12-22Henrik Grubbström (Grubba)  }
f4fcce1997-03-15Niels Möller  }
9b80212014-01-03Henrik Grubbström (Grubba)  switch(compression_algorithm) { case COMPRESSION_deflate:
bd69a72014-05-16Martin Nilsson #if constant(Gz)
66fd2a2015-11-02Henrik Grubbström (Grubba)  read_state->compress = Gz.inflate()->inflate; write_state->compress =
2f0efd2015-11-04Henrik Grubbström (Grubba)  class(function(string(8bit), int:string(8bit)) _deflate) { string(8bit) deflate(string(8bit) s) {
66fd2a2015-11-02Henrik Grubbström (Grubba)  // RFC 3749 2: // All data that was submitted for compression MUST be // included in the compressed output, with no data // retained to be included in a later output payload. // Flushing ensures that each compressed packet payload // can be decompressed completely. return _deflate(s, Gz.SYNC_FLUSH); } }(Gz.deflate()->deflate)->deflate;
bd69a72014-05-16Martin Nilsson #endif
9b80212014-01-03Henrik Grubbström (Grubba)  break; }
f4fcce1997-03-15Niels Möller  return ({ read_state, write_state }); }
33ef431997-03-13Niels Möller 
8a08a62003-10-24Martin Stjernholm //! Computes a new set of encryption states, derived from the
f5bb032001-09-17Martin Nilsson //! client_random, server_random and master_secret strings. //! //! @returns //! @array
938d512014-05-16Martin Nilsson //! @elem SSL.State read_state
f5bb032001-09-17Martin Nilsson //! Read state
938d512014-05-16Martin Nilsson //! @elem SSL.State write_state
f5bb032001-09-17Martin Nilsson //! Write state //! @endarray
91f9c72014-05-15Martin Nilsson array(State) new_client_states(.Connection con,
2d40602014-05-16Martin Nilsson  string(8bit) client_random, string(8bit) server_random,
68b67e2014-04-05Henrik Grubbström (Grubba)  ProtocolVersion version)
f4fcce1997-03-15Niels Möller {
91f9c72014-05-15Martin Nilsson  State write_state = State(con); State read_state = State(con);
68b67e2014-04-05Henrik Grubbström (Grubba)  array(string) keys = generate_keys(client_random, server_random, version);
d67d3e2015-02-27Martin Nilsson 
f4fcce1997-03-15Niels Möller  if (cipher_spec->mac_algorithm) { read_state->mac = cipher_spec->mac_algorithm(keys[1]); write_state->mac = cipher_spec->mac_algorithm(keys[0]); } if (cipher_spec->bulk_cipher_algorithm)
33ef431997-03-13Niels Möller  {
f4fcce1997-03-15Niels Möller  read_state->crypt = cipher_spec->bulk_cipher_algorithm(); read_state->crypt->set_decrypt_key(keys[3]); write_state->crypt = cipher_spec->bulk_cipher_algorithm(); write_state->crypt->set_encrypt_key(keys[2]);
0753a92014-04-27Henrik Grubbström (Grubba)  if (cipher_spec->cipher_type == CIPHER_aead) { // AEAD algorithms use other iv methods. read_state->tls_iv = write_state->tls_iv = 0; read_state->salt = keys[5] || ""; write_state->salt = keys[4] || ""; } else if (cipher_spec->iv_size) { if (version >= PROTOCOL_TLS_1_1) { // TLS 1.1 and later have an explicit IV. read_state->tls_iv = write_state->tls_iv = cipher_spec->iv_size;
34289e2010-12-22Henrik Grubbström (Grubba)  }
0753a92014-04-27Henrik Grubbström (Grubba)  read_state->crypt->set_iv(keys[5]); write_state->crypt->set_iv(keys[4]);
34289e2010-12-22Henrik Grubbström (Grubba)  }
33ef431997-03-13Niels Möller  }
2460622015-12-01Henrik Grubbström (Grubba)  switch(compression_algorithm) { case COMPRESSION_deflate: #if constant(Gz) read_state->compress = Gz.inflate()->inflate; write_state->compress = class(function(string(8bit), int:string(8bit)) _deflate) { string(8bit) deflate(string(8bit) s) { // RFC 3749 2: // All data that was submitted for compression MUST be // included in the compressed output, with no data // retained to be included in a later output payload. // Flushing ensures that each compressed packet payload // can be decompressed completely. return _deflate(s, Gz.SYNC_FLUSH); } }(Gz.deflate()->deflate)->deflate; #endif break; }
33ef431997-03-13Niels Möller  return ({ read_state, write_state }); }
57d9e32014-08-12Martin Nilsson  //! Returns true if this session object can be used in place of the //! session object @[other]. int(0..1) reusable_as(Session other) { // SSL3 5.6.1.2: // If the session_id field is not empty (implying a session // resumption request) this vector [cipher_suites] must // include at least the cipher_suite from that session. // ... // If the session_id field is not empty (implying a session // resumption request) this vector [compression_methods] // must include at least the compression_method from // that session. // We use a *much* stricter test, and only reuse the old session // if it has the same parameters as the new session. return cipher_suite == other->cipher_suite && version == other->version && certificate_chain == other->certificate_chain && compression_algorithm == other->compression_algorithm && max_packet_size == other->max_packet_size && truncated_hmac == other->truncated_hmac && server_name == other->server_name && ecc_point_format == other->ecc_point_format && encrypt_then_mac == other->encrypt_then_mac && equal(signature_algorithms, other->signature_algorithms) &&
fd73662015-02-06Henrik Grubbström (Grubba)  equal(ecc_curves, other->ecc_curves) && equal(ffdhe_groups, other->ffdhe_groups);
57d9e32014-08-12Martin Nilsson }