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 //! //! The initialized @[context] object is then passed to //! @[sslfile()->create()] or used as is embedded in @[sslport]. //! //! @seealso //! @[sslfile], @[sslport], @[Standards.X509]
33ef431997-03-13Niels Möller 
7871142013-08-01Martin Nilsson #ifdef SSL3_DEBUG #define SSL3_DEBUG_MSG(X ...) werror(X) #else /*! SSL3_DEBUG */ #define SSL3_DEBUG_MSG(X ...) #endif /* SSL3_DEBUG */
a2d1fd2014-05-15Martin Nilsson import "."; import Constants;
c65c582014-05-15Martin Nilsson 
f466b62014-04-04Henrik Grubbström (Grubba) //! The minimum supported protocol version. //! //! Defaults to @[PROTOCOL_SSL_3_0]. //! //! @note //! This value should not be greater than @[max_version]. ProtocolVersion min_version = PROTOCOL_SSL_3_0; //! 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;
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) }
c6c12b2012-08-31Bill Welliver //! Should an SSL client include the Server Name extension? //!
625f342013-08-12Martin Nilsson //! If so, then client_server_names should specify the values to send.
c6c12b2012-08-31Bill Welliver int client_use_sni = 0;
625f342013-08-12Martin Nilsson //! Host names to send to the server when using the Server Name //! extension.
0a492d2014-02-03Martin Nilsson array(string(8bit)) client_server_names = ({});
c6c12b2012-08-31Bill Welliver 
625f342013-08-12Martin Nilsson //! Policy for client authentication. One of //! @[SSL.Constants.AUTHLEVEL_none], @[SSL.Constants.AUTHLEVEL_ask] //! and @[SSL.Constants.AUTHLEVEL_require].
da33812004-01-14H. William Welliver III int auth_level; //! Array of authorities that are accepted for client certificates.
625f342013-08-12Martin Nilsson //! 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
470abd2013-08-12Martin Nilsson //! @[MIME.decode_base64] or @[Standards.PEM.Messages] first.
625f342013-08-12Martin Nilsson //! //! 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.
7655672004-01-27H. William Welliver III void set_authorities(array(string) a)
55189a2004-01-27H. William Welliver III { authorities = a; update_authorities(); }
625f342013-08-12Martin Nilsson //! When set, require the chain to be known, even if the root is self //! signed.
526a402004-01-30H. William Welliver III //!
625f342013-08-12Martin Nilsson //! Note that if set, and certificates are set to be verified, trusted //! issuers must be provided, or no connections will be accepted.
f591dd2004-01-29H. William Welliver III int require_trust=0;
55189a2004-01-27H. William Welliver III //! Get the list of allowed authorities. See @[set_authorities]. array(string) get_authorities() { return authorities; }
9eaf1d2008-06-28Martin Nilsson protected array(string) authorities = ({});
0a492d2014-02-03Martin Nilsson array(string(8bit)) authorities_cache = ({});
55189a2004-01-27H. William Welliver III  //! Sets the list of trusted certificate issuers. //! //! @param a //!
625f342013-08-12Martin Nilsson //! 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
470abd2013-08-12Martin Nilsson //! @[Standards.PEM.Messages] first.
55189a2004-01-27H. William Welliver III //!
625f342013-08-12Martin 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.
7655672004-01-27H. William Welliver III void set_trusted_issuers(array(array(string)) i)
55189a2004-01-27H. William Welliver III { trusted_issuers = i; update_trusted_issuers(); } //! Get the list of trusted issuers. See @[set_trusted_issuers].
7655672004-01-27H. William Welliver III array(array(string)) get_trusted_issuers()
55189a2004-01-27H. William Welliver III { return trusted_issuers; }
9eaf1d2008-06-28Martin Nilsson protected array(array(string)) trusted_issuers = ({});
312d4d2014-05-01Martin Nilsson mapping(string:array(Standards.X509.Verifier)) trusted_issuers_cache = ([]);
da33812004-01-14H. William Welliver III 
625f342013-08-12Martin Nilsson //! Determines whether certificates presented by the peer are //! verified, or just accepted as being valid.
526a402004-01-30H. William Welliver III int verify_certificates = 0;
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.
34adca2004-02-03Martin Nilsson Crypto.RSA long_rsa; Crypto.RSA 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 
56220e2014-03-08Henrik Grubbström (Grubba) //! Certificates and their corresponding keys. array(CertificatePair) cert_pairs = ({});
33ef431997-03-13Niels Möller 
cef61a2014-04-14Henrik Grubbström (Grubba) protected int(0..1) cert_pairs_sorted = 0;
dff8ef2014-03-09Henrik Grubbström (Grubba) //! Lookup from SNI (Server Name Indication) (server), or Issuer DER //! (client) to an array of suitable @[CertificatePair]s. //! //! Generated on demand from @[cert_pairs]. mapping(string(8bit):array(CertificatePair)) cert_cache = ([]);
f5bb032001-09-17Martin Nilsson //! For client authentication. Used only if auth_level is AUTH_ask or //! AUTH_require.
33ef431997-03-13Niels Möller array(int) preferred_auth_methods = ({ AUTH_rsa_sign });
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)));
112da62014-04-10Martin Nilsson //! List of advertised protocols using using TLS application level //! protocol negotiation.
0a492d2014-02-03Martin Nilsson array(string(8bit)) advertised_protocols;
27e1172012-04-07Arne Goedeke 
9dfeca2013-11-11Martin Nilsson //! The maximum amount of data that is sent in each SSL packet by //! @[sslfile]. A value between 1 and //! @[SSL.Constants.PACKET_MAX_SIZE].
a2d1fd2014-05-15Martin Nilsson int packet_max_size = PACKET_MAX_SIZE;
9dfeca2013-11-11Martin Nilsson 
cef61a2014-04-14Henrik Grubbström (Grubba) protected int cert_sort_key(CertificatePair cp) { array(HashAlgorithm|SignatureAlgorithm) sign_alg = cp->sign_algs[0]; int bits = cp->key->key_size(); // Adjust the bits to be comparable for the different algorithms. switch(sign_alg[1]) { case SIGNATURE_rsa: // The normative size. break; case SIGNATURE_dsa: // The consensus seems to be that DSA keys are about // the same strength as the corresponding RSA length. break; case SIGNATURE_ecdsa: // ECDSA size: NIST says: Our approximation: // 160 bits ~1024 bits RSA 960 bits RSA // 224 bits ~2048 bits RSA 2240 bits RSA // 256 bits ~4096 bits RSA 3072 bits RSA // 384 bits ~7680 bits RSA 7680 bits RSA // 521 bits ~15360 bits RSA 14881 bits RSA bits = (bits * (bits - 64))>>4; if (bits < 0) bits = 128; break; } // NB: Returns negative to get the largest values sorted first. return -((bits<<16)|(sign_alg[1]<<8)|sign_alg[0]); } //! Order the @[cps] in priority order. protected array(CertificatePair) sort_certs(array(CertificatePair) cps) { if (sizeof(cps) > 1) { sort(map(cps, cert_sort_key), cps); } return cps; }
9eb0d32014-03-27Henrik Grubbström (Grubba) //! Look up a suitable set of certificates for the specified SNI (server) //! or issuer (client).
57df062014-03-08Henrik Grubbström (Grubba) //!
9eb0d32014-03-27Henrik Grubbström (Grubba) //! @param is_issuer //! Indicates whether to @[glob]-match against the common name (server), //! or against the DER for the issuer (client). array(CertificatePair) find_cert(array(string)|void sni_or_issuer, int(0..1)|void is_issuer)
57df062014-03-08Henrik Grubbström (Grubba) {
cef61a2014-04-14Henrik Grubbström (Grubba)  if (!cert_pairs_sorted) { cert_pairs = sort_certs(cert_pairs); cert_pairs_sorted = 1; }
6290382014-04-11Henrik Grubbström (Grubba)  if (!sizeof(sni_or_issuer || ({}))) { // Either no/empty SNI, or empty certificate_authorities list.
cef61a2014-04-14Henrik Grubbström (Grubba)  if (!is_issuer) { // First check if there's a set of default certs. // Note: This doubles as a cache lookup of the // fallback entry set further below. array(CertificatePair) res = find_cert(({ "" }), is_issuer); if (res && sizeof(res)) return res; // Fall back to returning the entire set, since // they are presumably all valid for the server. }
6290382014-04-11Henrik Grubbström (Grubba)  // RFC 4346 7.4.4 // If the certificate_authorities list is empty then the client MAY // send any certificate of the appropriate ClientCertificateType, // unless there is some external arrangement to the contrary.
cef61a2014-04-14Henrik Grubbström (Grubba)  return cert_cache[""] = cert_pairs;
6290382014-04-11Henrik Grubbström (Grubba)  }
dff8ef2014-03-09Henrik Grubbström (Grubba)  mapping(string(8bit):array(CertificatePair)) certs = ([]); array(string(8bit)) maybes = ({});
9eb0d32014-03-27Henrik Grubbström (Grubba)  if (!is_issuer) {
cef61a2014-04-14Henrik Grubbström (Grubba)  sni_or_issuer = [array(string(8bit))]map(sni_or_issuer, lower_case);
9eb0d32014-03-27Henrik Grubbström (Grubba)  }
dff8ef2014-03-09Henrik Grubbström (Grubba) 
9eb0d32014-03-27Henrik Grubbström (Grubba)  foreach(sni_or_issuer, string name) {
dff8ef2014-03-09Henrik Grubbström (Grubba)  array(CertificatePair) res; if (res = cert_cache[name]) { certs[name] = res; continue; } if (zero_type(res)) { // Not known bad. certs[name] = ({}); maybes += ({ name }); } } if (sizeof(maybes)) { // There were some unknown names. Check them.
9eb0d32014-03-27Henrik Grubbström (Grubba)  if (is_issuer) { foreach(cert_pairs, CertificatePair cp) { foreach(maybes, string(8bit) i) { if (has_value(cp->issuers, i)) { certs[i] += ({ cp }); } } } } else { foreach(cert_pairs, CertificatePair cp) { foreach(cp->globs, string(8bit) g) { foreach(glob(g, maybes), string name) { certs[name] += ({ cp }); }
dff8ef2014-03-09Henrik Grubbström (Grubba)  } } } if (sizeof(cert_cache) > (sizeof(cert_pairs) * 10 + 10)) { // It seems the cache has been poisoned. Clean it. cert_cache = ([]); } // Update the cache. foreach(maybes, string name) { cert_cache[name] = certs[name]; } } // No certificate found. if (!sizeof(certs)) return UNDEFINED; if (sizeof(certs) == 1) { // Just a single matching name. return values(certs)[0]; }
cef61a2014-04-14Henrik Grubbström (Grubba)  return sort_certs(values(certs) * ({}));
57df062014-03-08Henrik Grubbström (Grubba) }
2796c52014-03-06Henrik Grubbström (Grubba) //! Add a certificate. //!
9e18402014-04-05Henrik Grubbström (Grubba) //! 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. //!
2796c52014-03-06Henrik Grubbström (Grubba) //! @param key //! Private key matching the first certificate in @[certs]. //!
9e18402014-04-05Henrik Grubbström (Grubba) //! Supported key types are currently: //! @mixed //! @type Crypto.RSA //! Rivest-Shamir-Adelman. //! @type Crypto.DSA //! 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]. //!
2796c52014-03-06Henrik Grubbström (Grubba) //! @param certs
57df062014-03-08Henrik Grubbström (Grubba) //! A chain of X509.v1 or X509.v3 certificates, with the local //! certificate first and root-most certificate last.
2796c52014-03-06Henrik Grubbström (Grubba) //!
57df062014-03-08Henrik Grubbström (Grubba) //! @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{({ "*" })@}.
2796c52014-03-06Henrik Grubbström (Grubba) //!
9e18402014-04-05Henrik Grubbström (Grubba) //! The SNI globs are only relevant for server-side certificates.
57df062014-03-08Henrik Grubbström (Grubba) //!
7bfaf82014-04-06Henrik Grubbström (Grubba) //! @param cp //! An alternative is to send an initialized @[CertificatePair]. //!
57df062014-03-08Henrik Grubbström (Grubba) //! @throws //! The function performs various validation of the @[key] //! and @[certs], and throws errors if the validation fails. //! //! @seealso //! @[find_cert()] void add_cert(Crypto.Sign key, array(string(8bit)) certs, array(string(8bit))|void extra_name_globs)
2796c52014-03-06Henrik Grubbström (Grubba) {
dff8ef2014-03-09Henrik Grubbström (Grubba)  CertificatePair cp = CertificatePair(key, certs, extra_name_globs); cert_pairs += ({ cp });
cef61a2014-04-14Henrik Grubbström (Grubba)  cert_pairs_sorted = 0;
dff8ef2014-03-09Henrik Grubbström (Grubba)  cert_cache = ([]);
2796c52014-03-06Henrik Grubbström (Grubba) }
7bfaf82014-04-06Henrik Grubbström (Grubba) variant void add_cert(CertificatePair cp) { cert_pairs += ({ cp });
cef61a2014-04-14Henrik Grubbström (Grubba)  cert_pairs_sorted = 0;
7bfaf82014-04-06Henrik Grubbström (Grubba)  cert_cache = ([]); }
2796c52014-03-06Henrik Grubbström (Grubba) 
41491c2013-11-30Henrik Grubbström (Grubba) // 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) { array(int) info = [array(int)] (CIPHER_SUITES[suite] || ({ 0, 0, 0 })); int keylength = CIPHER_effective_keylengths[info[1]]; // NB: Currently the hash algorithms are allocated in a suitable order. int hash = info[2];
d1bd752013-12-04Henrik Grubbström (Grubba)  if (sizeof(info) > 3) { hash |= info[3]<<6; }
41491c2013-11-30Henrik Grubbström (Grubba)  // NB: As are the cipher ids if you disregard the keylengths. int cipher = info[1]; // FIXME: I'm not quite sure about the priorities here. int ke_prio = ([ KE_null: 0, KE_dh_anon: 1,
4851ae2014-01-01Henrik Grubbström (Grubba)  KE_ecdh_anon: 2,
41491c2013-11-30Henrik Grubbström (Grubba)  KE_fortezza: 3, KE_dms: 4,
55ce992014-04-17Henrik Grubbström (Grubba)  KE_dh_rsa: 5, KE_dh_dss: 6, KE_rsa: 7, KE_rsa_fips: 8, KE_ecdh_rsa: 9, KE_ecdh_ecdsa: 10, KE_dhe_rsa: 11, KE_dhe_dss: 12, KE_ecdhe_rsa: 13, KE_ecdhe_ecdsa: 14,
41491c2013-11-30Henrik Grubbström (Grubba)  ])[info[0]];
cba3fe2014-03-25Henrik Grubbström (Grubba)  int auth_prio = keylength && ([
4851ae2014-01-01Henrik Grubbström (Grubba)  KE_null: 0, KE_dh_anon: 0, KE_ecdh_anon: 0, KE_fortezza: 1, KE_dms: 2, KE_rsa: 8,
55ce992014-04-17Henrik Grubbström (Grubba)  KE_rsa_fips: 8,
4851ae2014-01-01Henrik Grubbström (Grubba)  KE_dhe_rsa: 8, KE_ecdhe_rsa: 8,
bb1ab92014-03-13Henrik Grubbström (Grubba)  KE_dh_dss: 8, KE_dh_rsa: 8,
4851ae2014-01-01Henrik Grubbström (Grubba)  KE_dhe_dss: 8,
bb1ab92014-03-13Henrik Grubbström (Grubba)  KE_ecdh_rsa: 8,
4851ae2014-01-01Henrik Grubbström (Grubba)  KE_ecdh_ecdsa: 8, KE_ecdhe_ecdsa: 8, ])[info[0]];
24f7a32014-01-02Martin Nilsson  // int not_anonymous = ke_prio >= 3;
4851ae2014-01-01Henrik Grubbström (Grubba)  // Klugde to test GCM. // if (sizeof(info) > 3) keylength += 0x100;
41491c2013-11-30Henrik Grubbström (Grubba)  // NB: 8 bits for cipher. // 8 bits for hash. // 8 bits for key exchange.
4851ae2014-01-01Henrik Grubbström (Grubba)  // 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 //! 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 |= (<
55ce992014-04-17Henrik Grubbström (Grubba)  KE_rsa, 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) 
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 */
9b80212014-01-03Henrik Grubbström (Grubba) //! 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.
33ef431997-03-13Niels Möller array(int) preferred_compressors =
9b80212014-01-03Henrik Grubbström (Grubba)  ({ COMPRESSION_null, COMPRESSION_deflate });
33ef431997-03-13Niels Möller 
bd5c2d2014-04-09Henrik Grubbström (Grubba) //! Non-zero to enable caching of sessions
33ef431997-03-13Niels Möller int use_cache = 1;
f5bb032001-09-17Martin Nilsson  //! 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;
33ef431997-03-13Niels Möller 
27d1f02007-03-08Martin Stjernholm //! Maximum number of sessions to keep in the cache. int max_sessions = 300;
0a492d2014-02-03Martin Nilsson /* Queue of pairs (time, id), in cronological order */ ADT.Queue active_sessions = ADT.Queue();
c65c582014-05-15Martin Nilsson mapping(string:Session) session_cache = ([]);
33ef431997-03-13Niels Möller 
625f342013-08-12Martin Nilsson int session_number; /* Incremented for each session, and used when * constructing the session id */
33ef431997-03-13Niels Möller 
387e7f2003-01-27Martin Nilsson // Remove sessions older than @[session_lifetime] from the session cache.
33ef431997-03-13Niels Möller void forget_old_sessions() { int t = time() - session_lifetime; array pair;
387e7f2003-01-27Martin Nilsson  while ( (pair = [array]active_sessions->peek())
27d1f02007-03-08Martin Stjernholm  && (pair[0] < t)) {
7871142013-08-01Martin Nilsson  SSL3_DEBUG_MSG("SSL.context->forget_old_sessions: " "garbing session %O due to session_lifetime limit\n", pair[1]);
f6e4212007-03-09Martin Stjernholm  m_delete (session_cache, [string]([array]active_sessions->get())[1]);
27d1f02007-03-08Martin Stjernholm  }
33ef431997-03-13Niels Möller }
f5bb032001-09-17Martin Nilsson //! Lookup a session identifier in the cache. Returns the //! corresponding session, or zero if it is not found or caching is //! disabled.
c65c582014-05-15Martin Nilsson Session lookup_session(string id)
33ef431997-03-13Niels Möller { if (use_cache) { return session_cache[id]; } else return 0; }
f5bb032001-09-17Martin Nilsson //! Create a new session.
c65c582014-05-15Martin Nilsson Session new_session()
33ef431997-03-13Niels Möller {
c65c582014-05-15Martin Nilsson  Session s = Session();
ca94982013-12-08Henrik Grubbström (Grubba)  s->identity = (use_cache) ?
0a492d2014-02-03Martin Nilsson  sprintf("%4cPikeSSL3%4c", time(), session_number++) : "";
33ef431997-03-13Niels Möller  return s; }
f5bb032001-09-17Martin Nilsson //! Add a session to the cache (if caching is enabled).
c65c582014-05-15Martin Nilsson void record_session(Session s)
33ef431997-03-13Niels Möller { if (use_cache && s->identity) {
27d1f02007-03-08Martin Stjernholm  while (sizeof (active_sessions) >= max_sessions) { array pair = [array] active_sessions->get();
7871142013-08-01Martin Nilsson  SSL3_DEBUG_MSG("SSL.context->record_session: " "garbing session %O due to max_sessions limit\n", pair[1]);
f6e4212007-03-09Martin Stjernholm  m_delete (session_cache, [string]pair[1]);
27d1f02007-03-08Martin Stjernholm  } forget_old_sessions();
7871142013-08-01Martin Nilsson  SSL3_DEBUG_MSG("SSL.context->record_session: caching session %O\n", s->identity);
0a492d2014-02-03Martin Nilsson  active_sessions->put( ({ time(1), s->identity }) );
33ef431997-03-13Niels Möller  session_cache[s->identity] = s; } }
f5bb032001-09-17Martin Nilsson //! Remove a session from the cache.
c65c582014-05-15Martin Nilsson void purge_session(Session s)
33ef431997-03-13Niels Möller {
7871142013-08-01Martin Nilsson  SSL3_DEBUG_MSG("SSL.context->purge_session: %O\n", s->identity || "");
33ef431997-03-13Niels Möller  if (s->identity)
2c5e462003-10-24Martin Stjernholm  m_delete (session_cache, s->identity);
33ef431997-03-13Niels Möller  /* There's no need to remove the id from the active_sessions queue */ }
0a492d2014-02-03Martin Nilsson protected void create()
33ef431997-03-13Niels Möller {
7871142013-08-01Martin Nilsson  SSL3_DEBUG_MSG("SSL.context->create\n");
ec866d2014-03-18Martin Nilsson 
03af331999-03-09Niels Möller  /* Backwards compatibility */
8cc6c52014-03-22Henrik Grubbström (Grubba)  preferred_suites = get_suites(128, 1);
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  // // --- Compat code below // protected Crypto.RSA compat_rsa; protected array(string(8bit)) compat_certificates; //! The servers default private RSA key. //! //! Compatibility, don't use. //! //! @deprecated find_cert //! //! @seealso //! @[`certificates], @[find_cert()] __deprecated__ Crypto.RSA `rsa() { return compat_rsa; } //! Set the servers default private RSA key. //! //! Compatibility, don't use. //! //! @deprecated add_cert //! //! @seealso //! @[`certificates=], @[add_cert()] __deprecated__ void `rsa=(Crypto.RSA k) { compat_rsa = k; if (k && compat_certificates) { catch { add_cert(k, compat_certificates); }; } } //! The server's certificate, or a chain of X509.v3 certificates, with //! the server's certificate first and root certificate last. //! //! Compatibility, don't use. //! //! @deprecated find_cert //! //! @seealso //! @[`rsa], @[find_cert()] __deprecated__ array(string(8bit)) `certificates() { return compat_certificates; } //! Set the servers certificate, or a chain of X509.v3 certificates, with //! the servers certificate first and root certificate last. //! //! Compatibility, don't use. //! //! @deprecated add_cert //! //! @seealso //! @[`rsa=], @[add_cert()] __deprecated__ void `certificates=(array(string(8bit)) certs) { compat_certificates = certs; if (compat_rsa && certs) { catch { add_cert(compat_rsa, certs); }; } } //! The clients RSA private key. //! //! Compatibility, don't use. //! //! @deprecated find_cert //! //! @seealso //! @[`certificates], @[find_cert()] __deprecated__ Crypto.RSA `client_rsa() { return compat_rsa; } //! Set the clients default private RSA key. //! //! Compatibility, don't use. //! //! @deprecated add_cert //! //! @seealso //! @[`client_certificates=], @[add_cert()] __deprecated__ void `client_rsa=(Crypto.RSA k) { compat_rsa = k; if (k && compat_certificates) { catch { add_cert(k, compat_certificates); }; } } //! The client's certificate, or a chain of X509.v3 certificates, with //! the client's certificate first and root certificate last. //! //! Compatibility, don't use. //! //! @deprecated find_cert //! //! @seealso //! @[`rsa], @[find_cert()] __deprecated__ array(array(string(8bit))) `client_certificates() { return compat_certificates && ({ compat_certificates }); } //! Set the client's certificate, or a chain of X509.v3 certificates, with //! the client's certificate first and root certificate last. //! //! Compatibility, don't use. //! //! @deprecated add_cert //! //! @seealso //! @[`rsa=], @[add_cert()] __deprecated__ void `client_certificates=(array(array(string(8bit))) certs) { compat_certificates = certs && (sizeof(certs)?certs[0]:({})); if (compat_rsa && certs) { foreach(certs, array(string(8bit)) chain) { catch { add_cert(compat_rsa, chain); }; } } } //! A mapping containing certificate chains for use by SNI (Server //! Name Indication). Each entry should consist of a key indicating //! the server hostname and the value containing the certificate chain //! for that hostname. //! //! @deprecated add_cert //! //! @seealso //! @[add_cert()] __deprecated__ void `sni_certificates=(mapping(string:array(string(8bit))) sni) { error("The old SNI API is not supported anymore.\n"); } __deprecated__ mapping(string:array(string(8bit))) `sni_certificates() { return ([]); } #if 0 //! A function which will select an acceptable client certificate for //! presentation to a remote server. This function will receive the //! SSL context, an array of acceptable certificate types, and a list //! of DNs of acceptable certificate authorities. This function should //! return an array of strings containing a certificate chain, with //! the client certificate first, (and the root certificate last, if //! applicable.) function(.context,array(int),array(string(8bit)):array(string(8bit))) client_certificate_selector = internal_select_client_certificate; //! A function which will select an acceptable server certificate for //! presentation to a client. This function will receive the SSL //! context, and an array of server names, if provided by the client. //! This function should return an array of strings containing a //! certificate chain, with the client certificate first, (and the //! root certificate last, if applicable.) //! //! The default implementation will select a certificate chain for a //! given server based on values contained in @[sni_certificates]. function (.context,array(string(8bit)):array(string(8bit))) select_server_certificate_func = internal_select_server_certificate; //! A function which will select an acceptable server key for //! presentation to a client. This function will receive the SSL //! context, and an array of server names, if provided by the client. //! This function should return an object matching the certificate for //! the server hostname. //! //! The default implementation will select the key for a given server //! based on values contained in @[sni_keys]. function (.context,array(string):object(Crypto.Sign)) select_server_key_func = internal_select_server_key; private array(string(8bit)) internal_select_client_certificate(.context context, array(int) acceptable_types, array(string) acceptable_authority_dns) { if( !context->client_certificates || !sizeof(context->client_certificates) ) return ({}); // FIXME: Create a cache for the certificate objects. array(mapping(string:mixed)) c = ({}); foreach(context->client_certificates; int i; array(string) chain) { if(sizeof(chain)) c += ({ (["cert":Standards.X509.decode_certificate(chain[0]), "chain":i ]) }); } string wantedtype; mapping(int:string) cert_types = ([ AUTH_rsa_sign : "rsa", AUTH_dss_sign : "dss", AUTH_ecdsa_sign : "ecdsa", ]); foreach(acceptable_types, int t) { wantedtype = cert_types[t]; foreach(c, mapping(string:mixed) cert) { Standards.X509.TBSCertificate crt = [object(Standards.X509.TBSCertificate)]cert->cert; if(crt->public_key->type == wantedtype) return context->client_certificates[[int]cert->chain]; } } // FIXME: Check acceptable_authority_dns. acceptable_authority_dns; return ({}); } #endif /* 0 */ //! Compatibility.
bd74e82014-04-10Martin Nilsson //! @deprecated find_cert
373a0f2014-04-10Martin Nilsson __deprecated__ Crypto.DSA `dsa() { return UNDEFINED; } //! Compatibility.
bd74e82014-04-10Martin Nilsson //! @deprecated add_cert
373a0f2014-04-10Martin Nilsson __deprecated__ void `dsa=(Crypto.DSA k) { error("The old DSA API is not supported anymore.\n"); } #if 0 //! Parameters for dh keyexchange.
a2d1fd2014-05-15Martin Nilsson Cipher.DHKeyExchange dh_ke;
373a0f2014-04-10Martin Nilsson #endif //! Set @[preferred_suites] to RSA based methods. //! //! @param min_keylength //! Minimum acceptable key length in bits. //! //! @seealso
ab71302014-04-10Henrik Grubbström (Grubba) //! @[dhe_dss_mode()], @[filter_weak_suites()]
373a0f2014-04-10Martin Nilsson //! //! @deprecated get_suites __deprecated__ void rsa_mode(int(0..)|void min_keylength) { SSL3_DEBUG_MSG("SSL.context: rsa_mode()\n"); preferred_suites = get_suites(min_keylength, 1); } //! Set @[preferred_suites] to DSS based methods. //! //! @param min_keylength //! Minimum acceptable key length in bits. //! //! @seealso
ab71302014-04-10Henrik Grubbström (Grubba) //! @[rsa_mode()], @[filter_weak_suites()]
373a0f2014-04-10Martin Nilsson //! //! @deprecated get_suites __deprecated__ void dhe_dss_mode(int(0..)|void min_keylength) { SSL3_DEBUG_MSG("SSL.context: dhe_dss_mode()\n"); preferred_suites = get_suites(min_keylength, 1); }