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.
a2d1fd2014-05-15Martin Nilsson import "."; import Constants;
9eaf1d2008-06-28Martin Nilsson protected constant Struct = ADT.struct;
33ef431997-03-13Niels Möller 
1ecaa22014-02-03Henrik Grubbström (Grubba) #ifdef SSL3_DEBUG #define SSL3_DEBUG_MSG(X ...) werror(X) #else /*! SSL3_DEBUG */ #define SSL3_DEBUG_MSG(X ...) #endif /* SSL3_DEBUG */
f5bb032001-09-17Martin Nilsson //! Identifies the session to the server
2d40602014-05-16Martin Nilsson string(8bit) identity;
33ef431997-03-13Niels Möller 
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  //! Key exchange method, also derived from the cipher_suite.
33ef431997-03-13Niels Möller int ke_method;
f5bb032001-09-17Martin Nilsson 
2f77da2013-11-23Henrik Grubbström (Grubba) //! Key exchange factory, derived from @[ke_method].
a2d1fd2014-05-15Martin Nilsson program(Cipher.KeyExchange) ke_factory;
2f77da2013-11-23Henrik Grubbström (Grubba) 
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 
f591dd2004-01-29H. William Welliver III //! information about the certificate in use by the peer, such as issuing authority, and verification status. mapping cert_data;
68b67e2014-04-05Henrik Grubbström (Grubba) //! Negotiated protocol version. ProtocolVersion version;
9ece162004-01-14H. William Welliver III 
88cfa12005-10-28H. William Welliver III //! the peer certificate chain
1ecaa22014-02-03Henrik Grubbström (Grubba) array(string(8bit)) peer_certificate_chain;
45c1e11999-03-19Niels Möller 
88cfa12005-10-28H. William Welliver III //! 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. Crypto.Sign private_key;
c51f9c2012-08-30Bill Welliver 
57b5952014-01-19Henrik Grubbström (Grubba) //! The peer's public key (from the certificate). Crypto.Sign 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 //! to the first 10 bytes (80 bits). Cf RFC 3546 3.5. int(0..1) truncated_hmac;
6a0e942014-02-02Henrik Grubbström (Grubba) /* * Extensions provided by the peer. */
6542d42014-06-09Martin Nilsson //! RFC 6066 3.1 (SNI) 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. //! //! Defaults to the settings from RFC 5246 array(array(int)) signature_algorithms = ({
4232d42014-03-24Henrik Grubbström (Grubba)  // RFC 5246 // 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.
6a0e942014-02-02Henrik Grubbström (Grubba)  ({ HASH_sha, SIGNATURE_rsa }), ({ HASH_sha, SIGNATURE_dsa }), ({ HASH_sha, SIGNATURE_ecdsa }), }); //! 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() {
a2d1fd2014-05-15Martin Nilsson  if (!peer_public_key) return (cipher_spec->sign == Cipher.anon_sign);
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; }
d77a6e2014-03-14Henrik Grubbström (Grubba)  } else { if (!(ke_mask & cp->ke_mask)) return 0;
c539db2014-07-19Henrik Grubbström (Grubba)  // GNU-TLS doesn't like eg SHA being used with SHA256 certs. Crypto.Hash hash = HASH_lookup[cp->sign_algs[0][0]]; if (!hash) return 0; if (hash->digest_size() > h_max) return 0;
57df062014-03-08Henrik Grubbström (Grubba)  } #if constant(Crypto.ECC.Curve) if (cp->key->curve) { // Is the ECC curve supported by the client? Crypto.ECC.Curve c = ([object(Crypto.ECC.SECP_521R1.ECDSA)]cp->key)->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; } // FIXME: Check hash size >= cert hash size.
d156952014-03-22Henrik Grubbström (Grubba)  } if ((version >= PROTOCOL_TLS_1_1) && (< CIPHER_null, 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; } return 1;
57df062014-03-08Henrik Grubbström (Grubba) } //! Selects an apropriate certificate, authentication method //! and cipher suite for the parameters provided by the client. //!
fc5acb2014-07-16Martin Nilsson //! @param certs //! The list of @[CertificatePair]s that are applicable to the //! @[server_name] of this session.
57df062014-03-08Henrik Grubbström (Grubba) //! //! @param client_suites //! The set of cipher suites that the client claims to support. //! //! @param version //! The SSL protocol version to use. //! //! Typical client extensions that also are used:
fa4bd12014-04-01Henrik Grubbström (Grubba) //! @dl //! @item @[signature_algorithms] //! The set of signature algorithm tuples that
57df062014-03-08Henrik Grubbström (Grubba) //! the client claims to support.
fa4bd12014-04-01Henrik Grubbström (Grubba) //! @enddl
fc5acb2014-07-16Martin Nilsson int select_cipher_suite(array(CertificatePair) certs,
1ecaa22014-02-03Henrik Grubbström (Grubba)  array(int) cipher_suites,
68b67e2014-04-05Henrik Grubbström (Grubba)  ProtocolVersion version)
1ecaa22014-02-03Henrik Grubbström (Grubba) {
57df062014-03-08Henrik Grubbström (Grubba)  if (!sizeof(cipher_suites)) return 0; SSL3_DEBUG_MSG("Candidate certificates: %O\n", certs);
c539db2014-07-19Henrik Grubbström (Grubba)  // 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]) { ke_mask |= 1 << [int](CIPHER_SUITES[suite][0]);
c539db2014-07-19Henrik Grubbström (Grubba)  Crypto.Hash hash = HASH_lookup[CIPHER_SUITES[suite][2]]; if (hash && (hash->digest_size() > h_max)) { h_max = hash->digest_size(); }
d77a6e2014-03-14Henrik Grubbström (Grubba)  } }
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)  SSL3_DEBUG_MSG("Client supported certificates: %O\n", certs);
d77a6e2014-03-14Henrik Grubbström (Grubba)  // Find the set of key exchange algorithms supported by // the remaining certs. ke_mask = (1<<KE_null)|(1<<KE_dh_anon) #if constant(Crypto.ECC.Curve) |(1<<KE_ecdh_anon) #endif ; if (version >= PROTOCOL_TLS_1_2) { ke_mask = `|(ke_mask, @certs->ke_mask_invariant); } else { ke_mask = `|(ke_mask, @certs->ke_mask); }
57df062014-03-08Henrik Grubbström (Grubba)  // Given the set of certs, filter the set of client_suites, // to find the best. cipher_suites =
d08a962014-05-04Henrik Grubbström (Grubba)  filter(cipher_suites, is_supported_suite, ke_mask, version);
57df062014-03-08Henrik Grubbström (Grubba)  if (!sizeof(cipher_suites)) { 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) 
57df062014-03-08Henrik Grubbström (Grubba)  SSL3_DEBUG_MSG("intersection:\n%s\n", fmt_cipher_suites(cipher_suites));
1ecaa22014-02-03Henrik Grubbström (Grubba) 
57df062014-03-08Henrik Grubbström (Grubba)  int suite = cipher_suites[0]; ke_method = [int]CIPHER_SUITES[suite][0]; 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) if (private_key->curve) { curve = [object(Crypto.ECC.Curve)]private_key->curve(); } #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; } }
0fddf02014-06-29Henrik Grubbström (Grubba)  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"); } }
57df062014-03-08Henrik Grubbström (Grubba)  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. //! //! @param client_suites //! The set of cipher suites that the client claims to support. //! //! @param version //! The SSL protocol version to use. //! //! @param signature_algorithms //! The set of signature algorithms tuples that the client claims to support.
e85ce52013-11-26Henrik Grubbström (Grubba) int set_cipher_suite(int suite, ProtocolVersion|int version,
57df062014-03-08Henrik Grubbström (Grubba)  array(array(int)) signature_algorithms, int max_hash_size)
33ef431997-03-13Niels Möller {
a2d1fd2014-05-15Martin Nilsson  array res = Cipher.lookup(suite, version, signature_algorithms, truncated_hmac?512:max_hash_size);
e85ce52013-11-26Henrik Grubbström (Grubba)  if (!res) return 0;
33ef431997-03-13Niels Möller  cipher_suite = suite;
c0b44e2003-01-27Martin Nilsson  ke_method = [int]res[0];
8844002013-11-23Henrik Grubbström (Grubba)  switch(ke_method) {
bf52942013-11-24Henrik Grubbström (Grubba)  case KE_null:
a2d1fd2014-05-15Martin Nilsson  ke_factory = Cipher.KeyExchangeNULL;
bf52942013-11-24Henrik Grubbström (Grubba)  break;
8844002013-11-23Henrik Grubbström (Grubba)  case KE_rsa:
55ce992014-04-17Henrik Grubbström (Grubba)  case KE_rsa_fips:
a2d1fd2014-05-15Martin Nilsson  ke_factory = Cipher.KeyExchangeRSA;
8844002013-11-23Henrik Grubbström (Grubba)  break;
bb1ab92014-03-13Henrik Grubbström (Grubba)  case KE_dh_dss: case KE_dh_rsa:
a2d1fd2014-05-15Martin Nilsson  ke_factory = Cipher.KeyExchangeDH;
82ad0e2013-11-23Henrik Grubbström (Grubba)  break;
bb1ab92014-03-13Henrik Grubbström (Grubba)  case KE_dh_anon:
82ad0e2013-11-23Henrik Grubbström (Grubba)  case KE_dhe_rsa: case KE_dhe_dss:
a2d1fd2014-05-15Martin Nilsson  ke_factory = Cipher.KeyExchangeDHE;
82ad0e2013-11-23Henrik Grubbström (Grubba)  break;
b35f742014-01-06Chris Angelico #if constant(SSL.Cipher.KeyExchangeECDHE)
2285362013-12-31Henrik Grubbström (Grubba)  case KE_ecdhe_rsa: case KE_ecdhe_ecdsa:
21df722014-01-02Henrik Grubbström (Grubba)  case KE_ecdh_anon:
a2d1fd2014-05-15Martin Nilsson  ke_factory = Cipher.KeyExchangeECDHE;
2285362013-12-31Henrik Grubbström (Grubba)  break;
10333f2014-03-12Henrik Grubbström (Grubba)  case KE_ecdh_rsa: case KE_ecdh_ecdsa:
a2d1fd2014-05-15Martin Nilsson  ke_factory = Cipher.KeyExchangeECDH;
10333f2014-03-12Henrik Grubbström (Grubba)  break;
b35f742014-01-06Chris Angelico #endif
8844002013-11-23Henrik Grubbström (Grubba)  default:
bf52942013-11-24Henrik Grubbström (Grubba)  error("set_cipher_suite: Unsupported key exchange method: %d\n", ke_method);
8844002013-11-23Henrik Grubbström (Grubba)  break; }
57df062014-03-08Henrik Grubbström (Grubba) 
a2d1fd2014-05-15Martin Nilsson  cipher_spec = [object(Cipher.CipherSpec)]res[1];
8dcd741997-03-15Niels Möller #ifdef SSL3_DEBUG
938d512014-05-16Martin Nilsson  werror("SSL.Session: cipher_spec %O\n",
6244142003-01-27Martin Nilsson  mkmapping(indices(cipher_spec), values(cipher_spec)));
8dcd741997-03-15Niels Möller #endif
e85ce52013-11-26Henrik Grubbström (Grubba)  return 1;
33ef431997-03-13Niels Möller }
e7a27d2003-03-08Martin Nilsson //! Sets the compression method. Currently only @[COMPRESSION_null] is //! supported.
33ef431997-03-13Niels Möller void set_compression_method(int compr) {
9b80212014-01-03Henrik Grubbström (Grubba)  switch(compr) { case COMPRESSION_null: break; case COMPRESSION_deflate: break; default:
6244142003-01-27Martin Nilsson  error( "Method not supported\n" );
9b80212014-01-03Henrik Grubbström (Grubba)  }
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 
8dcd741997-03-15Niels Möller #ifdef SSL3_DEBUG
6244142003-01-27Martin Nilsson  werror("key_block: %O\n", key);
8dcd741997-03-15Niels Möller #endif
33ef431997-03-13Niels Möller  return key; }
aa77d52001-04-18Pär Svensson #ifdef SSL3_DEBUG
9eaf1d2008-06-28Martin Nilsson protected void printKey(string name, string key) {
aa77d52001-04-18Pär Svensson  string res="";
ead9722003-01-20Martin Nilsson  res+=sprintf("%s: len:%d type:%d \t\t",name,sizeof(key),0);
aa77d52001-04-18Pär Svensson  /* return; */
ead9722003-01-20Martin Nilsson  for(int i=0;i<sizeof(key);i++) {
aa77d52001-04-18Pär Svensson  int d=key[i]; res+=sprintf("%02x ",d&0xff); }
6244142003-01-27Martin Nilsson  res+="\n";
aa77d52001-04-18Pär Svensson  werror(res); } #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 {
e7a27d2003-03-08Martin Nilsson  Struct key_data = Struct(generate_key_block(client_random, server_random, version));
2d40602014-05-16Martin Nilsson  array(string(8bit)) keys = allocate(6);
33ef431997-03-13Niels Möller 
8dcd741997-03-15Niels Möller #ifdef SSL3_DEBUG
4a25412013-11-14Martin Nilsson  werror("client_random: %s\nserver_random: %s\nversion: %d.%d\n", client_random?String.string2hex(client_random):"NULL", server_random?String.string2hex(server_random):"NULL",
68b67e2014-04-05Henrik Grubbström (Grubba)  version>>8, version & 0xff);
8dcd741997-03-15Niels Möller #endif
e7a27d2003-03-08Martin Nilsson  // client_write_MAC_secret
f4fcce1997-03-15Niels Möller  keys[0] = key_data->get_fix_string(cipher_spec->hash_size);
e7a27d2003-03-08Martin Nilsson  // server_write_MAC_secret
f4fcce1997-03-15Niels Möller  keys[1] = key_data->get_fix_string(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
0791b12013-11-24Henrik Grubbström (Grubba)  keys[2] = Crypto.MD5.hash(key_data->get_fix_string(5) + client_random + server_random)
ad2ef52013-10-12Henrik Grubbström (Grubba)  [..cipher_spec->key_material-1];
0791b12013-11-24Henrik Grubbström (Grubba)  keys[3] = Crypto.MD5.hash(key_data->get_fix_string(5) + 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.
2d40602014-05-16Martin Nilsson  string(8bit) client_wkey = key_data->get_fix_string(5); string(8bit) server_wkey = key_data->get_fix_string(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..]; #ifdef SSL3_DEBUG werror("sizeof(keys[4]):%d sizeof(keys[5]):%d\n",
ca94982013-12-08Henrik Grubbström (Grubba)  sizeof(keys[4]), sizeof(keys[4]));
ad2ef52013-10-12Henrik Grubbström (Grubba) #endif } } } else { keys[2] = key_data->get_fix_string(cipher_spec->key_material); keys[3] = key_data->get_fix_string(cipher_spec->key_material); if (cipher_spec->iv_size) { keys[4] = key_data->get_fix_string(cipher_spec->iv_size); keys[5] = key_data->get_fix_string(cipher_spec->iv_size); }
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]); printKey( "keys[2]",keys[2]); printKey( "keys[3]",keys[3]);
1e9ea82001-06-25Pär Svensson 
aa77d52001-04-18Pär Svensson  if(cipher_spec->iv_size) { printKey( "keys[4]",keys[4]); printKey( "keys[5]",keys[5]);
1e9ea82001-06-25Pär Svensson 
aa77d52001-04-18Pär Svensson  } else { werror("No IVs!!\n"); } #endif
1e9ea82001-06-25Pär Svensson 
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) { read_state->mac = cipher_spec->mac_algorithm(keys[0]); write_state->mac = cipher_spec->mac_algorithm(keys[1]); } if (cipher_spec->bulk_cipher_algorithm) { 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)
9b80212014-01-03Henrik Grubbström (Grubba)  // FIXME: RFC 5246 6.2.2: // If the decompression function encounters a TLSCompressed.fragment // that would decompress to a length in excess of 2^14 bytes, it MUST // report a fatal decompression failure error. read_state->compress = Gz.inflate()->inflate; write_state->compress = class(function(string, int:string) _deflate) { string deflate(string 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;
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);
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  } return ({ read_state, write_state }); }