387e7f2003-01-27Martin Nilsson #pike __REAL_VERSION__ #pragma strict_types
e1fb092014-02-14Martin Nilsson #require constant(Crypto.Hash)
33ef431997-03-13Niels Möller 
11396d2014-04-03Henrik Grubbström (Grubba) //! Keeps the state that is shared by all SSL-connections on a client, //! or for one port on a server. It includes policy configuration, //! the server or client certificate(s), the corresponding private key(s), //! etc. It also includes the session cache. //! //! The defaults are usually suitable for a client, but for a server //! some configuration is necessary. //! //! Typical use is to: //! @ul //! @item //! Call @[add_cert()] with the certificates belonging to the server //! or client. Note that clients often don't have or need any //! certificates, and also that certificate-less server operation is //! possible, albeit discouraged and not enabled by default. //! //! Suitable self-signed certificates can be created with //! @[Standards.X509.make_selfsigned_certificate()]. //! @item //! Optionally call @[get_suites()] to get a set of cipher_suites //! to assign to @[preferred_suites]. This is only needed if the //! default set of suites from @expr{get_suites(128, 1)@} isn't //! satisfactory. //! @endul //!
fc7f092014-06-01Martin Nilsson //! The initialized @[Context] object is then passed to //! @[File()->create()] or used as is embedded in @[Port].
11396d2014-04-03Henrik Grubbström (Grubba) //! //! @seealso
fc7f092014-06-01Martin Nilsson //! @[File], @[Port], @[Standards.X509]
33ef431997-03-13Niels Möller 
3c859d2015-02-25Martin Nilsson #include "tls.h"
7871142013-08-01Martin Nilsson 
a2d1fd2014-05-15Martin Nilsson import "."; import Constants;
c65c582014-05-15Martin Nilsson 
32fdbc2014-07-14Martin Nilsson protected void create() { SSL3_DEBUG_MSG("SSL.Context->create\n"); /* Backwards compatibility */ preferred_suites = get_suites(128, 1); }
f466b62014-04-04Henrik Grubbström (Grubba) //! The minimum supported protocol version. //!
0f307d2014-10-13Martin Nilsson //! Defaults to @[PROTOCOL_TLS_1_0].
f466b62014-04-04Henrik Grubbström (Grubba) //! //! @note //! This value should not be greater than @[max_version].
0f307d2014-10-13Martin Nilsson ProtocolVersion min_version = PROTOCOL_TLS_1_0;
f466b62014-04-04Henrik Grubbström (Grubba)  //! The maximum supported protocol version. //! //! Defaults to @[PROTOCOL_TLS_MAX]. //! //! @note //! This value should not be less than @[min_version]. ProtocolVersion max_version = PROTOCOL_TLS_MAX;
32fdbc2014-07-14Martin Nilsson //! List of advertised protocols using using TLS application level //! protocol negotiation. array(string(8bit)) advertised_protocols; //! The maximum amount of data that is sent in each SSL packet by //! @[File]. A value between 1 and @[Constants.PACKET_MAX_SIZE]. int packet_max_size = PACKET_MAX_SIZE; //! Lists the supported compression algorithms in order of preference. //! //! Defaults to @expr{({ COMPRESSION_null, COMPRESSION_deflate })@} //! (ie avoid compression unless the client requires it) due to //! SSL attacks that target compression. array(int) preferred_compressors = ({ COMPRESSION_null, #if constant(Gz) COMPRESSION_deflate, #endif });
3b3f9e2014-08-06Martin Nilsson //! If set, the other peer will be probed for the heartbleed bug //! during handshake. If heartbleed is found the connection is closed //! with insufficient security fatal error. int(0..1) heartbleed_probe = 0;
a2d1fd2014-05-15Martin Nilsson //! @decl Alert alert_factory(SSL.Connection con, int level, int description, @
3e466b2014-04-12Henrik Grubbström (Grubba) //! ProtocolVersion version, @ //! string|void message, mixed|void trace) //! //! Alert factory. //! //! This function may be overloaded to eg obtain logging of //! generated alerts. //! //! @param con //! Connection which caused the alert. //! //! @param level //! Level of alert. //! //! @param description //! Description code for the alert. //! //! @param message //! Optional log message for the alert. //! //! @note //! Not all alerts are fatal, and some (eg @[ALERT_close_notify]) are used //! during normal operation.
a2d1fd2014-05-15Martin Nilsson Alert alert_factory(object con,
2d40602014-05-16Martin Nilsson  int(1..2) level, int(8bit) description,
ee37502014-05-04Martin Nilsson  ProtocolVersion version, string|void message)
3e466b2014-04-12Henrik Grubbström (Grubba) {
a2d1fd2014-05-15Martin Nilsson  return Alert(level, description, version, message);
3e466b2014-04-12Henrik Grubbström (Grubba) }
55189a2004-01-27H. William Welliver III 
32fdbc2014-07-14Martin Nilsson // // --- Cryptography //
526a402004-01-30H. William Welliver III 
17b6192014-03-23Henrik Grubbström (Grubba) //! Temporary, non-certified, private keys, used for RSA key exchange //! in export mode. They are used as follows:
f5bb032001-09-17Martin Nilsson //!
17b6192014-03-23Henrik Grubbström (Grubba) //! @[short_rsa] is a 512-bit RSA key used for the SSL 3.0 and TLS 1.0 //! export cipher suites.
ad2ef52013-10-12Henrik Grubbström (Grubba) //!
17b6192014-03-23Henrik Grubbström (Grubba) //! @[long_rsa] is a 1024-bit RSA key to be used for the RSA_EXPORT1024 //! suites from draft-ietf-tls-56-bit-ciphersuites-01.txt.
ad2ef52013-10-12Henrik Grubbström (Grubba) //!
17b6192014-03-23Henrik Grubbström (Grubba) //! They have associated counters @[short_rsa_counter] and @[long_rsa_counter], //! which are decremented each time the keys are used. //! //! When the counters reach zero, the corresponding RSA key is cleared, //! and a new generated on demand at which time the counter is reset.
6222d22014-08-14Henrik Grubbström (Grubba) Crypto.RSA.State long_rsa; Crypto.RSA.State short_rsa;
2d07691998-08-26Niels Möller 
17b6192014-03-23Henrik Grubbström (Grubba) //! Counters for export RSA keys. int long_rsa_counter; int short_rsa_counter;
f5bb032001-09-17Martin Nilsson //! Used to generate random cookies for the hello-message. If we use //! the RSA keyexchange method, and this is a server, this random
ff81c72013-10-27Martin Nilsson //! number generator is not used for generating the master_secret. By //! default set to @[Crypto.Random.random_string].
b432312014-04-06Martin Nilsson function(int(0..):string(8bit)) random = Crypto.Random.random_string;
33ef431997-03-13Niels Möller 
32fdbc2014-07-14Martin Nilsson //! Attempt to enable encrypt-then-mac mode. int encrypt_then_mac = 1;
33ef431997-03-13Niels Möller 
625f342013-08-12Martin Nilsson //! Cipher suites we want to support, in order of preference, best //! first.
03af331999-03-09Niels Möller array(int) preferred_suites;
33ef431997-03-13Niels Möller 
6a0e942014-02-02Henrik Grubbström (Grubba) //! Supported elliptical curve cipher curves in order of preference. array(int) ecc_curves = reverse(sort(indices(ECC_CURVES)));
14f8162014-12-15Henrik Grubbström (Grubba) //! Supported FFDHE groups for DHE key exchanges, in order of preference, //! most preferred first. //! //! Defaults to the full set of supported FFDHE groups from the FFDHE //! draft, in order of size with the smallest group (2048 bits) first. //! //! Server-side the first group in the list that satisfies the NIST guide //! lines for key strength (NIST SP800-57 5.6.1) (if any) for the selected //! cipher suite will be selected, and otherwise the largest group. //! //! Client-side the list will be reversed (as a precaution if the server //! actually follows the clients preferences). array(int) ffdhe_groups = sort(indices(FFDHE_GROUPS));
85e8002014-09-01Martin Nilsson 
8ab8f12015-03-07Henrik Grubbström (Grubba) //! DHE parameter lookup for the FFDHE private range. //! //! Add any custom FFDHE-groups here. //! //! Defaults to the empty mapping. //! //! @note //! If you add any groups here, you will also need to update //! @[ffdhe_groups] accordingly. mapping(int(508..511):Crypto.DH.Parameters) private_ffdhe_groups = ([]);
85e8002014-09-01Martin Nilsson 
cec12e2014-07-07Henrik Grubbström (Grubba) //! The set of <hash, signature> combinations to use by us. //! //! Only used with TLS 1.2 and later. //! //! Defaults to all combinations supported by Pike except for MD5. //! //! This list is typically filtered by @[get_signature_algorithms()] //! to get rid of combinations not supported by the runtime. //! //! @note //! According to RFC 5246 7.4.2 all certificates needs to be signed
97b6532014-07-31Martin Nilsson //! by any of the supported signature algorithms. To be forward //! compatible this list needs to be limited to the combinations //! that have existing PKCS identifiers.
cec12e2014-07-07Henrik Grubbström (Grubba) //! //! @seealso //! @[get_signature_algorithms()]
ef87a82014-05-20Martin Nilsson array(array(int)) signature_algorithms = ({
c9ab262014-05-20Martin Nilsson #if constant(Crypto.SHA512) #if constant(Crypto.ECC.Curve)
ef87a82014-05-20Martin Nilsson  ({ HASH_sha512, SIGNATURE_ecdsa }),
c9ab262014-05-20Martin Nilsson #endif
ef87a82014-05-20Martin Nilsson  ({ HASH_sha512, SIGNATURE_rsa }),
c9ab262014-05-20Martin Nilsson #endif #if constant(Crypto.SHA384) #if constant(Crypto.ECC.Curve)
ef87a82014-05-20Martin Nilsson  ({ HASH_sha384, SIGNATURE_ecdsa }),
c9ab262014-05-20Martin Nilsson #endif
ef87a82014-05-20Martin Nilsson  ({ HASH_sha384, SIGNATURE_rsa }),
c9ab262014-05-20Martin Nilsson #endif #if constant(Crypto.ECC.Curve)
ef87a82014-05-20Martin Nilsson  ({ HASH_sha256, SIGNATURE_ecdsa }),
c9ab262014-05-20Martin Nilsson #endif
ef87a82014-05-20Martin Nilsson  ({ HASH_sha256, SIGNATURE_dsa }), ({ HASH_sha256, SIGNATURE_rsa }),
c9ab262014-05-20Martin Nilsson #if constant(Crypto.SHA224) #if constant(Crypto.ECC.Curve)
ef87a82014-05-20Martin Nilsson  ({ HASH_sha224, SIGNATURE_ecdsa }),
c9ab262014-05-20Martin Nilsson #endif
ef87a82014-05-20Martin Nilsson  ({ HASH_sha224, SIGNATURE_dsa }),
c9ab262014-05-20Martin Nilsson #endif #if constant(Crypto.ECC.Curve)
ef87a82014-05-20Martin Nilsson  ({ HASH_sha, SIGNATURE_ecdsa }),
c9ab262014-05-20Martin Nilsson #endif
ef87a82014-05-20Martin Nilsson  ({ HASH_sha, SIGNATURE_dsa }), ({ HASH_sha, SIGNATURE_rsa }), });
cec12e2014-07-07Henrik Grubbström (Grubba) //! Get the (filtered) set of locally supported signature algorithms. //! //! @seealso //! @[signature_algorithms] array(array(int)) get_signature_algorithms(array(array(int))|void signature_algorithms) { if (!signature_algorithms) { signature_algorithms = this_program::signature_algorithms; } #if constant(Crypto.ECC.Curve) && constant(Crypto.SHA512) && \ constant(Crypto.SHA384) && constant(Crypto.SHA224) return signature_algorithms; #else
9f1c702014-08-28Per Hedbor  return [array(array(int))] filter(signature_algorithms,
cec12e2014-07-07Henrik Grubbström (Grubba)  lambda(array(int) pair) { [int hash, int sign] = pair; #if !constant(Crypto.ECC.Curve) if (sign == SIGNATURE_ecdsa) return 0; #endif if ((< #if !constant(Crypto.SHA512) HASH_sha512, #endif #if !constant(Crypto.SHA384) HASH_sha384, #endif #if !constant(Crypto.SHA224) HASH_sha224, #endif >)[hash]) return 0; return 1; }); #endif }
32fdbc2014-07-14Martin Nilsson // Generate a sort key for a cipher suite. // // The larger the value, the stronger the cipher suite. protected int cipher_suite_sort_key(int suite)
cef61a2014-04-14Henrik Grubbström (Grubba) {
32fdbc2014-07-14Martin Nilsson  array(int) info = [array(int)] (CIPHER_SUITES[suite] || ({ 0, 0, 0 }));
cef61a2014-04-14Henrik Grubbström (Grubba) 
32fdbc2014-07-14Martin Nilsson  int keylength = CIPHER_effective_keylengths[info[1]];
cef61a2014-04-14Henrik Grubbström (Grubba) 
32fdbc2014-07-14Martin Nilsson  // NB: Currently the hash algorithms are allocated in a suitable order. int hash = info[2];
cef61a2014-04-14Henrik Grubbström (Grubba) 
32fdbc2014-07-14Martin Nilsson  if (sizeof(info) > 3) { hash |= info[3]<<5;
cef61a2014-04-14Henrik Grubbström (Grubba)  }
32fdbc2014-07-14Martin Nilsson  // NB: As are the cipher ids if you disregard the keylengths. int cipher = info[1];
6290382014-04-11Henrik Grubbström (Grubba) 
32fdbc2014-07-14Martin Nilsson  // FIXME: I'm not quite sure about the priorities here. int ke_prio = ([ KE_null: 0, KE_dh_anon: 1, KE_ecdh_anon: 2, KE_fortezza: 3, KE_dms: 4,
70997d2015-03-04Henrik Grubbström (Grubba)  KE_rsa_export: 5, KE_dh_rsa: 6, KE_dh_dss: 7, KE_rsa: 8, KE_rsa_fips: 9, KE_ecdh_rsa: 10, KE_ecdh_ecdsa: 11, KE_dhe_rsa: 12, KE_dhe_dss: 13, KE_ecdhe_rsa: 14, KE_ecdhe_ecdsa: 15,
32fdbc2014-07-14Martin Nilsson  ])[info[0]];
cef61a2014-04-14Henrik Grubbström (Grubba) 
32fdbc2014-07-14Martin Nilsson  int auth_prio = keylength && ([ KE_null: 0, KE_dh_anon: 0, KE_ecdh_anon: 0, KE_fortezza: 1, KE_dms: 2,
70997d2015-03-04Henrik Grubbström (Grubba)  KE_rsa_export: 4, // cf FREAK-attack.
32fdbc2014-07-14Martin Nilsson  KE_rsa: 8, KE_rsa_fips: 8, KE_dhe_rsa: 8, KE_ecdhe_rsa: 8, KE_dh_dss: 8, KE_dh_rsa: 8, KE_dhe_dss: 8, KE_ecdh_rsa: 8, KE_ecdh_ecdsa: 8, KE_ecdhe_ecdsa: 8, ])[info[0]];
cef61a2014-04-14Henrik Grubbström (Grubba) 
32fdbc2014-07-14Martin Nilsson  // int not_anonymous = ke_prio >= 3;
6290382014-04-11Henrik Grubbström (Grubba) 
32fdbc2014-07-14Martin Nilsson  // Klugde to test GCM. // if (sizeof(info) > 3) keylength += 0x100;
dff8ef2014-03-09Henrik Grubbström (Grubba) 
32fdbc2014-07-14Martin Nilsson  // NB: 8 bits for cipher. // 8 bits for hash + mode. // 8 bits for key exchange. // 12 bits for keylength. // 4 bits for auth. return cipher | hash << 8 | ke_prio << 16 | keylength << 24 | auth_prio << 36; }
41491c2013-11-30Henrik Grubbström (Grubba) 
1601112014-01-19Henrik Grubbström (Grubba) //! Sort a set of cipher suites according to our preferences. //! //! @returns //! Returns the array sorted with the most preferrable (aka "best") //! cipher suite first. //! //! @note //! The original array (@[suites]) is modified destructively, //! but is not the same array as the result. array(int) sort_suites(array(int) suites) { sort(map(suites, cipher_suite_sort_key), suites); return reverse(suites); }
41491c2013-11-30Henrik Grubbström (Grubba) //! Get the prioritized list of supported cipher suites //! that satisfy the requirements. //! //! @param min_keylength
8cc6c52014-03-22Henrik Grubbström (Grubba) //! Minimum supported effective keylength in bits. Defaults to @expr{128@}. //! Specify @expr{-1@} to enable null ciphers. //! //! @param ke_mode //! Level of protection for the key exchange. //! @int //! @value 0 //! Require forward secrecy (ephemeral keys). //! @value 1 //! Also allow certificate based key exchanges. //! @value 2 //! Allow anonymous server key exchange. Note that this //! allows for man in the middle attacks. //! @endint //! //! @param blacklisted_ciphers //! Multiset of ciphers that are NOT to be used. //! //! @param blacklisted_kes //! Multiset of key exchange methods that are NOT to be used. //! //! @param blacklisted_hashes //! Multiset of hash algoriths that are NOT to be used. //! //! @param blacklisted_ciphermodes //! Multiset of cipher modes that are NOT to be used.
41491c2013-11-30Henrik Grubbström (Grubba) //! //! @note
debead2015-02-02Henrik Grubbström (Grubba) //! The list of suites is also filtered on the current settings of //! @[min_version] and @[max_version]. //! //! @note
41491c2013-11-30Henrik Grubbström (Grubba) //! Note that the effective keylength may differ from //! the actual keylength for old ciphers where there //! are known attacks.
8cc6c52014-03-22Henrik Grubbström (Grubba) array(int) get_suites(int(-1..)|void min_keylength, int(0..2)|void ke_flags, multiset(int)|void blacklisted_ciphers, multiset(KeyExchangeType)|void blacklisted_kes, multiset(HashAlgorithm)|void blacklisted_hashes, multiset(CipherModes)|void blacklisted_ciphermodes)
41491c2013-11-30Henrik Grubbström (Grubba) {
8cc6c52014-03-22Henrik Grubbström (Grubba)  if (!min_keylength) min_keylength = 128; // Reasonable default. // Ephemeral key exchange methods. multiset(int) kes = (< KE_dhe_rsa, KE_dhe_dss, KE_ecdhe_rsa, KE_ecdhe_ecdsa, >); if (ke_flags) { // Static certificate based key exchange methods. kes |= (<
70997d2015-03-04Henrik Grubbström (Grubba)  KE_rsa, KE_rsa_export, KE_rsa_fips,
8cc6c52014-03-22Henrik Grubbström (Grubba)  KE_dh_rsa, KE_dh_dss,
ec866d2014-03-18Martin Nilsson #if constant(Crypto.ECC.Curve)
8cc6c52014-03-22Henrik Grubbström (Grubba)  KE_ecdh_rsa, KE_ecdh_ecdsa,
ec866d2014-03-18Martin Nilsson #endif >);
8cc6c52014-03-22Henrik Grubbström (Grubba)  if (ke_flags == 2) { // Unsigned key exchange methods. kes |= (< KE_null, KE_dh_anon,
57df062014-03-08Henrik Grubbström (Grubba) #if constant(Crypto.ECC.Curve)
8cc6c52014-03-22Henrik Grubbström (Grubba)  KE_ecdh_anon,
42de162013-12-31Henrik Grubbström (Grubba) #endif
8cc6c52014-03-22Henrik Grubbström (Grubba)  >); } } if (blacklisted_kes) { kes -= blacklisted_kes;
41491c2013-11-30Henrik Grubbström (Grubba)  } // Filter unsupported key exchange methods. array(int) res = filter(indices(CIPHER_SUITES), lambda(int suite) { return kes[CIPHER_SUITES[suite][0]]; }); // Filter short effective key lengths.
8cc6c52014-03-22Henrik Grubbström (Grubba)  if (min_keylength > 0) {
41491c2013-11-30Henrik Grubbström (Grubba)  res = filter(res, lambda(int suite, int min_keylength) { return min_keylength <= CIPHER_effective_keylengths[CIPHER_SUITES[suite][1]]; }, min_keylength); }
8cc6c52014-03-22Henrik Grubbström (Grubba)  if (blacklisted_ciphers) {
0020e42013-12-22Henrik Grubbström (Grubba)  res = filter(res,
8cc6c52014-03-22Henrik Grubbström (Grubba)  lambda(int suite, multiset(int) blacklisted_hashes) { return !blacklisted_hashes[CIPHER_SUITES[suite][1]]; }, blacklisted_ciphers);
0020e42013-12-22Henrik Grubbström (Grubba)  }
42de162013-12-31Henrik Grubbström (Grubba) #if !constant(Crypto.SHA384) // Filter suites needing SHA384 as our Nettle doesn't support it.
8cc6c52014-03-22Henrik Grubbström (Grubba)  if (!blacklisted_hashes) blacklisted_hashes = (< HASH_sha384 >); else blacklisted_hashes[HASH_sha384] = 1;
42de162013-12-31Henrik Grubbström (Grubba) #endif
8cc6c52014-03-22Henrik Grubbström (Grubba)  if (blacklisted_hashes) { res = filter(res, lambda(int suite, multiset(int) blacklisted_hashes) { return !blacklisted_hashes[CIPHER_SUITES[suite][2]]; }, blacklisted_hashes); } if (blacklisted_ciphermodes) { res = filter(res, lambda(int suite, multiset(int) blacklisted_ciphermodes) { array(int) info = [array(int)]CIPHER_SUITES[suite]; int mode = (sizeof(info) > 3)?info[3]:MODE_cbc; return !blacklisted_ciphermodes[mode]; }, blacklisted_ciphermodes); }
42de162013-12-31Henrik Grubbström (Grubba) 
debead2015-02-02Henrik Grubbström (Grubba)  switch(min_version) { case PROTOCOL_TLS_1_3: res = filter(res, lambda(int suite) { array(int) info = [array(int)]CIPHER_SUITES[suite]; // Non-AEAD suites were obsoleted in TLS 1.3. if (sizeof(info) < 4) return 0; if (info[3] == MODE_cbc) return 0; return 1; }); break; case PROTOCOL_TLS_1_2: res = filter(res, lambda(int suite) { array(int) info = [array(int)]CIPHER_SUITES[suite]; switch(info[1]) { // Export cipher suites were removed in TLS 1.1. case 0: case CIPHER_rc2_40: case CIPHER_rc4_40: case CIPHER_des40: // IDEA and DES suites were removed in TLS 1.2. case CIPHER_idea: case CIPHER_des: return 0; } return 1; }); break; case PROTOCOL_TLS_1_1: res = filter(res, lambda(int suite) { array(int) info = [array(int)]CIPHER_SUITES[suite]; // Export cipher suites were removed in TLS 1.1. switch(info[1]) { case 0: case CIPHER_rc2_40: case CIPHER_rc4_40: case CIPHER_des40: return 0; } return 1; }); break; } switch(max_version) { case PROTOCOL_TLS_1_1: case PROTOCOL_TLS_1_0: case PROTOCOL_SSL_3_0: res = filter(res, lambda(int suite) { array(int) info = [array(int)]CIPHER_SUITES[suite]; // AEAD suites are not supported in TLS versions // prior to TLS 1.2. return (sizeof(info) < 4); }); break; }
1601112014-01-19Henrik Grubbström (Grubba)  // Sort and return. return sort_suites(res);
41491c2013-11-30Henrik Grubbström (Grubba) }
625f342013-08-12Martin Nilsson //! Filter cipher suites from @[preferred_suites] that don't have a //! key with an effective length of at least @[min_keylength] bits.
a9bce32011-12-23Henrik Grubbström (Grubba) void filter_weak_suites(int min_keylength) { if (!preferred_suites || !min_keylength) return; preferred_suites = filter(preferred_suites,
c35dcb2013-08-01Martin Nilsson  lambda(int suite) {
af54a72012-02-17Henrik Grubbström (Grubba)  array(int) def = [array(int)]CIPHER_SUITES[suite];
ee7a0f2013-10-24Henrik Grubbström (Grubba)  return def && (CIPHER_effective_keylengths[def[1]] >= min_keylength);
c35dcb2013-08-01Martin Nilsson  });
a9bce32011-12-23Henrik Grubbström (Grubba) }
ab5db02014-05-04Henrik Grubbström (Grubba) #if constant(Crypto.ECC.Curve) && constant(Crypto.AES.GCM) && constant(Crypto.SHA384) //! Configure the context for Suite B compliant operation. //! //! This restricts the context to the cipher suites //! specified by RFC 6460 in strict mode. //! //! Additional suites may be enabled, but they will only be //! selected if a Suite B suite isn't available. //! //! @param min_keylength //! Minimum supported key length in bits. Either @expr{128@} //! or @expr{192@}. //! //! @param strictness_level //! Allow additional suites. //! @int //! @value 2.. //! Strict mode. //! //! Allow only the Suite B suites from RFC 6460 and TLS 1.2. //! @value 1 //! Transitional mode. //! //! Also allow the transitional suites from RFC 5430 for use //! with TLS 1.0 and 1.1. //! @value 0 //! Permissive mode (default). //! //! Also allow other suites that conform to the minimum key length. //! @endint //! //! @note //! This function is only present when Suite B compliant operation //! is possible (ie both elliptic curves and GCM are available). //! //! @note //! Note also that for Suite B server operation compliant certificates //! need to be added with @[add_cert()]. //! //! @seealso //! @[get_suites()] void configure_suite_b(int(128..)|void min_keylength, int(0..)|void strictness_level) { if (min_keylength < 128) min_keylength = 128; if (min_keylength > 128) { preferred_suites = ({ TLS_ecdhe_ecdsa_with_aes_256_gcm_sha384, }); } else { preferred_suites = ({ TLS_ecdhe_ecdsa_with_aes_128_gcm_sha256, TLS_ecdhe_ecdsa_with_aes_256_gcm_sha384, }); } max_version = PROTOCOL_TLS_MAX; min_version = PROTOCOL_TLS_1_2; if (strictness_level < 2) { // Transitional or permissive mode. // Allow TLS 1.0. min_version = PROTOCOL_TLS_1_0; // First add the transitional suites. if (min_keylength > 128) { // Transitional Suite B Combination 2 preferred_suites += ({ TLS_ecdhe_ecdsa_with_aes_256_cbc_sha, }); } else { // Transitional Suite B Combination 1 preferred_suites += ({ TLS_ecdhe_ecdsa_with_aes_128_cbc_sha, TLS_ecdhe_ecdsa_with_aes_256_cbc_sha, }); } if (strictness_level < 1) { // Permissive mode. Add the remaining suites of // the required strength. preferred_suites += get_suites(min_keylength) - preferred_suites; } } } #endif /* Crypto.ECC.Curve && Crypto.AES.GCM && Crypto.SHA384 */
a1747a2015-02-18Martin Nilsson // --- PSK API
3f08f82015-02-19Martin Nilsson // In addition to implementing get_psk, get_psk_id if you are a client // and optionally get_psk_hint if you are a server, the context object // also needs to ensure the apprioriate PSK cipher suites are in the // preferred_suites array. If the server is only accepting these PSK // connections, simply setting the array to a single member is best. // The client must only inlcude PSK suites when talking to a servers // known to support it, or risk getting MITM attacks. //! A context created for server side PSK use can optionally implement //! get_psk_hint to return a hint string to be sent to the client. If //! not implemented, or returning 0, no PSK hint will be sent.
a1747a2015-02-18Martin Nilsson optional string(8bit) get_psk_hint();
3f08f82015-02-19Martin Nilsson //! A context created for client side PSK use must implement a //! get_psk_id method, which will be called with the server provided
4121232015-02-19Martin Nilsson //! hint, or 0 if no hint was sent. Note that while there is an API //! difference between no hint and a zero length hint, some PSK modes //! are unable to send no hints. //! //! The method should return a key id
2588a92015-02-19Martin Nilsson //! for the PSK, which will be sent to the server. If the hint is not //! valid, 0 should be returned.
3f08f82015-02-19Martin Nilsson optional string(8bit) get_psk_id(string(8bit) hint);
a1747a2015-02-18Martin Nilsson 
3f08f82015-02-19Martin Nilsson //! A context created for PSK use must implement a get_psk method, //! which will be called with the key id, and should return the key to
2588a92015-02-19Martin Nilsson //! be used for the connection. If the id is not valid, 0 should be //! returned.
3f08f82015-02-19Martin Nilsson optional string(8bit) get_psk(string(8bit) id);
0fddf02014-06-29Henrik Grubbström (Grubba) 
32fdbc2014-07-14Martin Nilsson // // --- Certificates and authentication //
f5bb032001-09-17Martin Nilsson 
f4d26b2014-07-16Martin Nilsson // Unless connecting in anonymous mode the server has to have a set of // CertificatePair certificate chains to sign its handshake with. // These are stored in the cert_chains_domain mapping, where they are // retrieved based on domain the client is connecting to. // // If the server sends a certificate request the client has to respond // with a certificate matching the requested issuer der. These are // stored in the cert_chains_issuer mapping. //
ce5f2c2015-01-27Martin Nilsson // FIXME: Currently only one client certificate per der issuer is // supported. If multiple are added a random one will be selected, // which later may fail when verified against supported certificate // types, hash/signature algorithms. //
f4d26b2014-07-16Martin Nilsson // The client/server potentially has a set of trusted issuers // certificate (root certificates) that are used to validate the // server/client sent certificate. These are stored in a cache from // subject der to Verifier object. FIXME: Should use key identifier.
32fdbc2014-07-14Martin Nilsson //! Policy for client authentication. One of //! @[SSL.Constants.AUTHLEVEL_none], @[SSL.Constants.AUTHLEVEL_ask] //! and @[SSL.Constants.AUTHLEVEL_require]. int auth_level;
33ef431997-03-13Niels Möller 
32fdbc2014-07-14Martin Nilsson //! Array of authorities that are accepted for client certificates. //! The server will only accept connections from clients whose //! certificate is signed by one of these authorities. The string is a //! DER-encoded certificate, which typically must be decoded using //! @[MIME.decode_base64] or @[Standards.PEM.Messages] first. //! //! Note that it is presumed that the issuer will also be trusted by //! the server. See @[trusted_issuers] for details on specifying //! trusted issuers. //! //! If empty, the server will accept any client certificate whose //! issuer is trusted by the server. void set_authorities(array(string) a) { authorities = a; update_authorities(); }
27d1f02007-03-08Martin Stjernholm 
32fdbc2014-07-14Martin Nilsson //! When set, require the chain to be known, even if the root is self //! signed.
d67d3e2015-02-27Martin Nilsson //!
32fdbc2014-07-14Martin Nilsson //! Note that if set, and certificates are set to be verified, trusted //! issuers must be provided, or no connections will be accepted. int require_trust=0;
0a492d2014-02-03Martin Nilsson 
d67d3e2015-02-27Martin Nilsson //! Get the list of allowed authorities. See @[set_authorities].
32fdbc2014-07-14Martin Nilsson array(string) get_authorities() { return authorities; }
33ef431997-03-13Niels Möller 
32fdbc2014-07-14Martin Nilsson protected array(string) authorities = ({}); array(string(8bit)) authorities_cache = ({});
33ef431997-03-13Niels Möller 
d67d3e2015-02-27Martin Nilsson //! Sets the list of trusted certificate issuers.
32fdbc2014-07-14Martin Nilsson //! //! @param a //! //! An array of certificate chains whose root is self signed (ie a //! root issuer), and whose final certificate is an issuer that we //! trust. The root of the certificate should be first certificate in //! the chain. The string is a DER-encoded certificate, which //! typically must be decoded using @[MIME.decode_base64] or //! @[Standards.PEM.Messages] first.
d67d3e2015-02-27Martin Nilsson //!
32fdbc2014-07-14Martin Nilsson //! If this array is left empty, and the context is set to verify //! certificates, a certificate chain must have a root that is self //! signed. void set_trusted_issuers(array(array(string)) i) { trusted_issuers = i; update_trusted_issuers();
33ef431997-03-13Niels Möller }
d67d3e2015-02-27Martin Nilsson //! Get the list of trusted issuers. See @[set_trusted_issuers].
32fdbc2014-07-14Martin Nilsson array(array(string)) get_trusted_issuers()
33ef431997-03-13Niels Möller {
32fdbc2014-07-14Martin Nilsson  return trusted_issuers; } protected array(array(string)) trusted_issuers = ({}); mapping(string:array(Standards.X509.Verifier)) trusted_issuers_cache = ([]); //! For client authentication. Used only if auth_level is AUTH_ask or //! AUTH_require. array(int) preferred_auth_methods = ({ AUTH_rsa_sign });
ccf28f2014-07-15Martin Nilsson // Lookup from issuer DER to an array of suitable @[CertificatePair]s, // sorted in order of strength. protected mapping(string(8bit):array(CertificatePair)) cert_chains_issuer = ([]);
32fdbc2014-07-14Martin Nilsson 
ccf28f2014-07-15Martin Nilsson // Lookup from DN/SNI domain name/glob to an array of suitable // @[CertificatePair]s, sorted in order of strength. protected mapping(string(8bit):array(CertificatePair)) cert_chains_domain = ([]);
32fdbc2014-07-14Martin Nilsson 
ccf28f2014-07-15Martin Nilsson //! Look up a suitable set of certificates for the specified issuer. //! @[UNDEFIEND] if no certificate was found. array(CertificatePair) find_cert_issuer(array(string) ders) { // Return the first matching issuer. FIXME: Should we merge if // several matching issuers are found? foreach(ders, string der) if(cert_chains_issuer[der]) return cert_chains_issuer[der]; // We MAY return any certificate here. Let's not reveal any // certificates not specifically requested. return UNDEFINED; }
32fdbc2014-07-14Martin Nilsson 
ccf28f2014-07-15Martin Nilsson //! Look up a suitable set of certificates for the specified domain. //! @[UNDEFINED] if no certificate was found. array(CertificatePair) find_cert_domain(string(8bit) domain) { if( domain ) { if( cert_chains_domain[domain] ) return cert_chains_domain[domain];
32fdbc2014-07-14Martin Nilsson 
ccf28f2014-07-15Martin Nilsson  // Return first matching chain. foreach(cert_chains_domain; string g; array(CertificatePair) chains) if( glob(g, domain) ) return chains;
32fdbc2014-07-14Martin Nilsson  }
ccf28f2014-07-15Martin Nilsson  return cert_chains_domain["*"];
33ef431997-03-13Niels Möller }
c8dde02014-09-05Martin Nilsson //! Returns a list of all server certificates added with @[add_cert]. array(CertificatePair) get_certificates() { mapping(CertificatePair:int) c = ([]); foreach(cert_chains_domain;; array(CertificatePair) chains) foreach(chains, CertificatePair p) c[p]++; return indices(c); }
32fdbc2014-07-14Martin Nilsson //! Add a certificate. //! //! This function is used on both servers and clients to add //! a key and chain of certificates to the set of certificate //! candidates to use in @[find_cert()]. //! //! On a server these are used in the normal initial handshake, //! while on a client they are only used if a server requests //! client certificate authentication. //! //! @param key //! Private key matching the first certificate in @[certs]. //! //! Supported key types are currently: //! @mixed
6222d22014-08-14Henrik Grubbström (Grubba) //! @type Crypto.RSA.State
32fdbc2014-07-14Martin Nilsson //! Rivest-Shamir-Adelman.
6222d22014-08-14Henrik Grubbström (Grubba) //! @type Crypto.DSA.State
32fdbc2014-07-14Martin Nilsson //! Digital Signing Algorithm. //! @type Crypto.ECC.Curve.ECDSA //! Elliptic Curve Digital Signing Algorithm. //! @endmixed //! //! This key MUST match the public key in the first certificate //! in @[certs]. //! //! @param certs //! A chain of X509.v1 or X509.v3 certificates, with the local //! certificate first and root-most certificate last. //! //! @param extra_name_globs //! Further SNI globs (than the ones in the first certificate), that //! this certificate should be selected for. Typically used to set //! the default certificate(s) by specifying @expr{({ "*" })@}. //! //! The SNI globs are only relevant for server-side certificates. //! //! @param cp //! An alternative is to send an initialized @[CertificatePair]. //! //! @throws
ccf28f2014-07-15Martin Nilsson //! The function performs various validations of the @[key]
32fdbc2014-07-14Martin Nilsson //! and @[certs], and throws errors if the validation fails. //! //! @seealso //! @[find_cert()]
6222d22014-08-14Henrik Grubbström (Grubba) void add_cert(Crypto.Sign.State key, array(string(8bit)) certs,
32fdbc2014-07-14Martin Nilsson  array(string(8bit))|void extra_name_globs)
33ef431997-03-13Niels Möller {
32fdbc2014-07-14Martin Nilsson  CertificatePair cp = CertificatePair(key, certs, extra_name_globs);
bd38482014-07-15Martin Nilsson  add_cert(cp);
32fdbc2014-07-14Martin Nilsson }
5f4b8c2014-09-04Martin Nilsson variant void add_cert(string(8bit) key, array(string(8bit)) certs, array(string(8bit))|void extra_name_globs) { Crypto.Sign.State _key = Standards.PKCS.RSA.parse_private_key(key) || Standards.PKCS.DSA.parse_private_key(key) || #if constant(Crypto.ECC.Curve) Standards.PKCS.ECDSA.parse_private_key(key) || #endif 0; add_cert(_key, certs, extra_name_globs); }
32fdbc2014-07-14Martin Nilsson variant void add_cert(CertificatePair cp)
33ef431997-03-13Niels Möller {
ccf28f2014-07-15Martin Nilsson  void add(string what, mapping(string:array(CertificatePair)) to) { if( !to[what] ) to[what] = ({cp}); else to[what] = sort( to[what]+({cp}) ); };
f4d26b2014-07-16Martin Nilsson  // FIXME: Look at leaf flags to determine which mapping to store the // chains in.
ccf28f2014-07-15Martin Nilsson  // Insert cp in cert_chains both under all DN/SNI names/globs and // under issuer DER. Keep lists sorted by strength. foreach( cp->globs, string id ) add(id, cert_chains_domain); add(cp->issuers[0], cert_chains_issuer);
33ef431997-03-13Niels Möller }
55189a2004-01-27H. William Welliver III  // update the cached decoded authorities list private void update_authorities() {
09aa4f2013-12-04Martin Nilsson  authorities_cache = ({});
55189a2004-01-27H. William Welliver III  foreach(authorities, string a)
09aa4f2013-12-04Martin Nilsson  authorities_cache += ({ Standards.X509.decode_certificate(a)-> subject->get_der() });
55189a2004-01-27H. William Welliver III } // update the cached decoded issuers list private void update_trusted_issuers() {
81bef22013-12-04Martin Nilsson  trusted_issuers_cache=([]);
7655672004-01-27H. William Welliver III  foreach(trusted_issuers, array(string) i)
55189a2004-01-27H. William Welliver III  {
f591dd2004-01-29H. William Welliver III  // make sure the chain is valid and intact.
03b9712013-08-16Martin Nilsson  mapping result = Standards.X509.verify_certificate_chain(i, ([]), 0);
f591dd2004-01-29H. William Welliver III  if(!result->verified) error("Broken trusted issuer chain!\n");
55189a2004-01-27H. William Welliver III 
78293d2014-04-28Martin Nilsson  // FIXME: The pathLenConstraint does not survive the cache. // The leaf of the trusted issuer is the root to validate // certificate chains against.
0963782014-04-29Martin Nilsson  Standards.X509.TBSCertificate cert = ([array(object(Standards.X509.TBSCertificate))]result->certificates)[-1]; if( !cert->ext_basicConstraints_cA || !(cert->ext_keyUsage & Standards.X509.KU_keyCertSign) ) error("Trusted issuer not allowed to sign other certificates.\n");
81bef22013-12-04Martin Nilsson 
312d4d2014-05-01Martin Nilsson  trusted_issuers_cache[cert->subject->get_der()] += ({ cert->public_key });
55189a2004-01-27H. William Welliver III  } }
373a0f2014-04-10Martin Nilsson  //
32fdbc2014-07-14Martin Nilsson // --- Sessions // //! Non-zero to enable caching of sessions int use_cache = 1; //! Sessions are removed from the cache when they are older than this //! limit (in seconds). Sessions are also removed from the cache if a //! connection using the session dies unexpectedly. int session_lifetime = 600; //! Maximum number of sessions to keep in the cache. int max_sessions = 300; /* Queue of pairs (time, id), in cronological order */ ADT.Queue active_sessions = ADT.Queue(); mapping(string:Session) session_cache = ([]); // Remove sessions older than @[session_lifetime] from the session cache. void forget_old_sessions() { int t = time() - session_lifetime; array pair; while ( (pair = [array]active_sessions->peek()) && (pair[0] < t)) { SSL3_DEBUG_MSG("SSL.Context->forget_old_sessions: " "garbing session %O due to session_lifetime limit\n", pair[1]); m_delete (session_cache, [string]([array]active_sessions->get())[1]); } } //! Lookup a session identifier in the cache. Returns the //! corresponding session, or zero if it is not found or caching is //! disabled. Session lookup_session(string id) { if (use_cache) return session_cache[id]; else return 0; } //! Create a new session. Session new_session() {
26b6082014-11-25Martin Nilsson  string(8bit) id = ""; if(use_cache) do { id = random(32); } while( session_cache[id] );
14f8162014-12-15Henrik Grubbström (Grubba)  Session s = Session(id); s->ffdhe_groups = ffdhe_groups; return s;
32fdbc2014-07-14Martin Nilsson } //! Add a session to the cache (if caching is enabled). void record_session(Session s) { if (use_cache && s->identity) { while (sizeof (active_sessions) >= max_sessions) { array pair = [array] active_sessions->get(); SSL3_DEBUG_MSG("SSL.Context->record_session: " "garbing session %O due to max_sessions limit\n", pair[1]); m_delete (session_cache, [string]pair[1]); } forget_old_sessions(); SSL3_DEBUG_MSG("SSL.Context->record_session: caching session %O\n", s->identity); active_sessions->put( ({ time(1), s->identity }) ); session_cache[s->identity] = s; } }
ae3b852014-11-24Henrik Grubbström (Grubba) //! Invalidate a session for resumption and remove it from the cache.
32fdbc2014-07-14Martin Nilsson void purge_session(Session s) { SSL3_DEBUG_MSG("SSL.Context->purge_session: %O\n", s->identity || ""); if (s->identity) m_delete (session_cache, s->identity);
ae3b852014-11-24Henrik Grubbström (Grubba)  /* RFC 4346 7.2: * In this case [fatal alert], 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. */ s->identity = 0; s->master_secret = 0;
32fdbc2014-07-14Martin Nilsson  /* There's no need to remove the id from the active_sessions queue */ }
0f11582015-01-19Martin Nilsson  // // --- Compatibility code // //! @decl int verify_certificates //! //! Determines whether certificates presented by the peer are //! verified, or just accepted as being valid. //! //! @deprecated auth_level __deprecated__ void `verify_certificates=(int i) { if(!i) auth_level = AUTHLEVEL_none; else if(auth_level < AUTHLEVEL_ask) auth_level = AUTHLEVEL_ask; } __deprecated__ int `verify_certificates() { return auth_level >= AUTHLEVEL_ask; }