pike.git/lib/modules/SSL.pmod/Cipher.pmod:1:
#pike __REAL_VERSION__
+ #require constant(Crypto.Hash)
- #if constant(Crypto.Hash)
-
+
//! Encryption and MAC algorithms used in SSL.
-
+ #include "tls.h"
+
import .Constants;
- #ifdef SSL3_DEBUG
- #define SSL3_DEBUG_MSG(X ...) werror(X)
- #else /*! SSL3_DEBUG */
- #define SSL3_DEBUG_MSG(X ...)
- #endif /* SSL3_DEBUG */
+ // A mapping from DH p to DH q to effort verification level to
+ // indicate if a DH group with a specific p and q is valid or not. -1
+ // means failed validation.
+ protected mapping(Gmp.mpz:mapping(Gmp.mpz:int)) valid_dh;
+ protected int valid_dh_count;
-
+ protected mapping(Gmp.mpz:mapping(Gmp.mpz:int)) make_valid_dh()
+ {
+ mapping dh = ([]);
+ foreach(values(Crypto.DH), mixed m)
+ {
+ if(!objectp(m)) continue;
+ object o = [object]m;
+ if(m->p && m->q)
+ dh[m->p] = ([ m->q : Int.NATIVE_MAX ]);
+ }
+ return dh;
+ }
+
+ // FIXME: This function ought to check that the selected group
+ // is strong enough for the selected key length.
+ protected bool validate_dh(Crypto.DH.Parameters dh,
+ object session,
+ object context)
+ {
+ if (sizeof(session->ffdhe_groups || ({}))) {
+ // Check if one of the recommended groups was selected,
+ // in which case we're done.
+ foreach(session->ffdhe_groups, int g) {
+ Crypto.DH.Parameters ffdhe =
+ FFDHE_GROUPS[g] || context->private_ffdhe_groups[g];
+ if (!ffdhe) continue;
+ if ((ffdhe->p == dh->p) &&
+ (ffdhe->g == dh->g) &&
+ (ffdhe->q == dh->q)) return 1;
+ }
+ // Also check for the equivalent MODP groups.
+ foreach(session->ffdhe_groups, int g) {
+ Crypto.DH.Parameters ffdhe = MODP_GROUPS[g];
+ if (!ffdhe) continue;
+ if ((ffdhe->p == dh->p) &&
+ (ffdhe->g == dh->g) &&
+ (ffdhe->q == dh->q)) return 1;
+ }
+ }
+
+ if( !valid_dh || valid_dh_count > 1000 )
+ {
+ valid_dh = make_valid_dh();
+ valid_dh_count = 0;
+ }
+
+ // Spend more effort validating q when in anonymous KE. These two
+ // effort values should possibly be part of the context.
+ int effort = 0;
+ if( session->cipher_spec->signature_alg == SIGNATURE_anonymous )
+ effort = 8; // Misses non-prime with 0.0015% probability.
+
+ mapping pmap = valid_dh[dh->p];
+ if( pmap )
+ {
+ if( has_index(pmap, dh->q) )
+ return pmap[dh->q] >= effort;
+ }
+ else
+ valid_dh[dh->p] = ([]);
+
+ if( !dh->validate(effort) )
+ effort = -1;
+
+ valid_dh[dh->p][dh->q] = effort;
+ valid_dh_count++;
+ return effort > -1;
+ }
+
//! Cipher algorithm interface.
class CipherAlgorithm {
this_program set_encrypt_key(string);
this_program set_decrypt_key(string);
//! Set the key used for encryption/decryption, and
//! enter encryption mode.
int(0..) block_size();
//! Return the block size for this crypto.
optional string crypt(string);
- optional string unpad(string);
- optional string pad();
+ optional string unpad(string,int);
+ optional string pad(int);
optional this_program set_iv(string);
}
//! Message Authentication Code interface.
class MACAlgorithm {
-
+
+ //! Generates a header and creates a HMAC hash for the given
+ //! @[packet].
//! @param packet
//! @[Packet] to generate a MAC hash for.
//! @param seq_num
//! Sequence number for the packet in the stream.
-
+ //! @param adjust_len
+ //! Added to @tt{sizeof(packet)@} to get the packet length.
//! @returns
//! Returns the MAC hash for the @[packet].
- string hash(object packet, Gmp.mpz seq_num);
+ string hash_packet(object packet, int seq_num, int|void adjust_len);
- //! Hashes the data with the hash algorithm and retuns it as a raw
- //! binary string.
+ //! Creates a HMAC hash of the @[data] with the underlying hash
+ //! algorithm.
+ string hash(string data);
+
+ //! Creates a normal hash of the @[data] using the underlying hash
+ //! algorithm.
string hash_raw(string data);
-
+ //! The block size of the underlying hash algorithm.
+ int block_size();
+
//! The length of the header prefixed by @[hash()].
constant hash_header_size = 13;
}
//! Cipher specification.
class CipherSpec {
-
+
+ //! Key exchange factory.
+ program(KeyExchange) ke_factory;
+
//! The algorithm to use for the bulk of the transfered data.
program(CipherAlgorithm) bulk_cipher_algorithm;
int cipher_type;
//! The Message Authentication Code to use for the packets.
program(MACAlgorithm) mac_algorithm;
//! Indication whether the combination uses strong or weak
//! (aka exportable) crypto.
pike.git/lib/modules/SSL.pmod/Cipher.pmod:64:
//! The number of bytes in the MAC hashes.
int hash_size;
//! The number of bytes of key material used on initialization.
int key_material;
//! The number of bytes of random data needed for initialization vectors.
int iv_size;
//! The number of bytes of explicit data needed for initialization vectors.
- //! This is used by AEAD ciphers, where there's a secret part of the iv
- //! "salt" of length @[iv_size], and an explicit part that is sent in
+ //! This is used by AEAD ciphers in TLS 1.2, where there's a secret part of
+ //! the iv "salt" of length @[iv_size], and an explicit part that is sent in
//! the clear.
-
+ //!
+ //! This is usually @expr{bulk_cipher_algorithm->iv_size() - iv_size@},
+ //! but may be set to zero to just have the sequence number expanded
+ //! to the same size as an implicit iv. This is used by the suites
+ //! with @[Crypto.ChaCha20.POLY1305].
int explicit_iv_size;
//! The effective number of bits in @[key_material].
//!
//! This is typically @expr{key_material * 8@}, but for eg @[DES]
//! this is @expr{key_material * 7@}.
int key_bits;
//! The Pseudo Random Function to use.
//!
//! @seealso
//! @[prf_ssl_3_0()], @[prf_tls_1_0()], @[prf_tls_1_2()]
- function(string(0..255), string(0..255), string(0..255), int:string(0..255)) prf;
+ function(string(8bit), string(8bit), string(8bit), int:string(8bit)) prf;
//! The hash algorithm for signing the handshake.
//!
//! Usually the same hash as is the base for the @[prf].
//!
//! @note
//! Only used in TLS 1.2 and later.
Crypto.Hash hash;
- //! The function used to sign packets.
- function(object,string(0..255),ADT.struct:ADT.struct) sign;
+ //! The hash algorithm used for key exchange signatures.
+ HashAlgorithm signature_hash = HASH_sha1;
- //! The function used to verify the signature for packets.
- function(object,string(0..255),ADT.struct,ADT.struct:int(0..1)) verify;
- }
+ //! The signature algorithm used for key exchange signatures.
+ SignatureAlgorithm signature_alg;
- //! Class used for signing in TLS 1.2 and later.
- class TLSSigner
+ //! The number of bytes that is safe to send before we must renegotiate the keys.
+ int max_bytes;
+
+ //! The function used to sign packets.
+ Stdio.Buffer sign(object session, string(8bit) cookie, Stdio.Buffer struct)
{
- //!
- int hash_id = HASH_sha;
+ if( signature_alg == SIGNATURE_anonymous )
+ return struct;
- //! The TLS 1.2 hash used to sign packets.
- Crypto.Hash hash = Crypto.SHA1;
+ string data = cookie + (string)struct;
- ADT.struct rsa_sign(object context, string cookie, ADT.struct struct)
+ // RFC 5246 4.7
+ if( session->version >= PROTOCOL_TLS_1_2 )
{
- string sign = context->rsa->pkcs_sign(cookie + struct->contents(), hash);
- struct->put_uint(hash_id, 1);
- struct->put_uint(SIGNATURE_rsa, 1);
- struct->put_var_string(sign, 2);
+ string sign =
+ session->private_key->pkcs_sign(data, HASH_lookup[signature_hash]);
+ struct->add_int(signature_hash, 1);
+ struct->add_int(signature_alg, 1);
+ struct->add_hstring(sign, 2);
return struct;
}
- ADT.struct dsa_sign(object context, string cookie, ADT.struct struct)
+ // RFC 4346 7.4.3 (struct Signature)
+ switch( signature_alg )
{
- string sign = context->dsa->pkcs_sign(cookie + struct->contents(), hash);
- struct->put_uint(hash_id, 1);
- struct->put_uint(SIGNATURE_dsa, 1);
- struct->put_var_string(sign, 2);
+ case SIGNATURE_rsa:
+ {
+ string digest = Crypto.MD5->hash(data) + Crypto.SHA1->hash(data);
+ struct->add_hint(session->private_key->raw_sign(digest), 2);
return struct;
}
- int(0..1) verify(object context, string cookie, ADT.struct struct,
- ADT.struct input)
+ case SIGNATURE_dsa:
+ case SIGNATURE_ecdsa:
{
- int hash_id = input->get_uint(1);
- int sign_id = input->get_uint(1);
- string sign = input->get_var_string(2);
+ string sign = session->private_key->pkcs_sign(data, Crypto.SHA1);
+ struct->add_hstring(sign, 2);
+ return struct;
+ }
+ }
-
+ error("Internal error");
+ }
+
+ //! The function used to verify the signature for packets.
+ int(0..1) verify(object session, string data, Stdio.Buffer input)
+ {
+ if( signature_alg == SIGNATURE_anonymous )
+ return 1;
+
+ Crypto.Sign.State pkc = session->peer_public_key;
+ if( !pkc ) return 0;
+
+ // RFC 5246 4.7
+ if( session->version >= PROTOCOL_TLS_1_2 )
+ {
+ int hash_id = input->read_int(1);
+ int sign_id = input->read_int(1);
+ string sign = input->read_hstring(2);
+
+ if( sign_id != signature_alg )
+ {
+ SSL3_DEBUG_MSG("Signature pair <%d,%d> doesn't match "
+ "negotiated <%d,%d>\n", hash_id, sign_id,
+ signature_hash, signature_alg);
+ return 0;
+ }
+
Crypto.Hash hash = HASH_lookup[hash_id];
if (!hash) return 0;
- if ((sign_id == SIGNATURE_rsa) && context->rsa) {
- return context->rsa->pkcs_verify(cookie + struct->contents(),
- hash, sign);
+ return pkc->pkcs_verify(data, hash, sign);
}
- if ((sign_id == SIGNATURE_dsa) && context->dsa) {
- return context->dsa->pkcs_verify(cookie + struct->contents(),
- hash, sign);
+
+ // RFC 4346 7.4.3 (struct Signature)
+ switch( signature_alg )
+ {
+ case SIGNATURE_rsa:
+ {
+ string digest = Crypto.MD5->hash(data) + Crypto.SHA1->hash(data);
+ // FIXME: We could check that the signature is encoded
+ // (padded) to the correct number of bytes
+ // (pkc->private_key->key_size()/8).
+ Gmp.mpz signature = Gmp.mpz(input->read_hint(2));
+ return pkc->raw_verify(digest, signature);
}
- return 0;
+
+ case SIGNATURE_dsa:
+ case SIGNATURE_ecdsa:
+ {
+ return pkc->pkcs_verify(data, Crypto.SHA1, input->read_hstring(2));
}
-
+ }
- protected void create(int hash_id)
+ error("Internal error");
+ }
+
+ void set_hash(int max_hash_size,
+ array(array(int)) signature_algorithms)
{
- hash = HASH_lookup[hash_id];
- if (!hash) {
- error("Unsupported hash algorithm: %d\n", hash_id);
+ // Stay with SHA1 for requests without signature algorithms
+ // extensions (RFC 5246 7.4.1.4.1) and anonymous requests.
+ if( signature_alg == SIGNATURE_anonymous || !signature_algorithms )
+ return;
+
+ int hash_id = -1;
+ SSL3_DEBUG_MSG("Signature algorithms (max hash size %d):\n%s",
+ max_hash_size, fmt_signature_pairs(signature_algorithms));
+ foreach(signature_algorithms, array(int) pair) {
+ if ((pair[1] == signature_alg) && HASH_lookup[pair[0]]) {
+ if (max_hash_size < HASH_lookup[pair[0]]->digest_size()) {
+ // Eg RSA has a maximum block size and the digest is too large.
+ continue;
}
- this_program::hash_id = hash_id;
+ if (pair[0] > hash_id) {
+ hash_id = pair[0];
}
}
-
+ }
-
+ if (signature_hash == -1)
+ error("No acceptable hash algorithm.\n");
+ signature_hash = hash_id;
+
+ SSL3_DEBUG_MSG("Selected <%s, %s>\n",
+ fmt_constant(signature_hash, "HASH"),
+ fmt_constant(signature_alg, "SIGNATURE"));
+ }
+ }
+
//! KeyExchange method base class.
class KeyExchange(object context, object session, object connection,
- array(int) client_version)
+ ProtocolVersion client_version)
{
-
+ // 1. Server calls server_key_exchange_packet()
+ // 1.1 Unless overloaded server_key_params() is called.
+ // 2. Client calls got_server_key_exchange()
+ // 2.1 Unless overloaded parse_server_key_exchange() is called.
+ // 3. Client calls client_key_exchange_packet()
+ // 4. Server calls got_client_key_exchange()
+
//! Indicates whether a certificate isn't required.
int anonymous;
//! Indicates whether the key exchange has failed due to bad MACs.
int message_was_bad;
//! @returns
- //! Returns an @[ADT.struct] with the
+ //! Returns an @[Stdio.Buffer] with the
//! @[HANDSHAKE_server_key_exchange] payload.
- ADT.struct server_key_params();
+ Stdio.Buffer server_key_params();
- //! The default implementation calls @[server_key_params()] to generate
- //! the base payload.
+ //! Initialize for client side use.
//!
//! @returns
- //! Returns the signed payload for a @[HANDSHAKE_server_key_exchange].
- string server_key_exchange_packet(string client_random, string server_random)
+ //! Returns @expr{1@} on success, and @expr{0@} (zero)
+ //! on failure.
+ int(0..1) init_client()
{
- ADT.struct struct = server_key_params();
- if (!struct) return 0;
-
- session->cipher_spec->sign(session, client_random + server_random, struct);
- return struct->pop_data();
+ return 1;
}
- //! Derive the master secret from the premaster_secret
- //! and the random seeds.
+ //! Initialize for server side use.
//!
//! @returns
- //! Returns the master secret.
- string derive_master_secret(string premaster_secret,
- string client_random,
- string server_random,
- array(int) version)
+ //! Returns @expr{1@} on success, and @expr{0@} (zero)
+ //! on failure.
+ int(0..1) init_server()
{
- string res = "";
+ return 1;
+ }
- SSL3_DEBUG_MSG("KeyExchange: in derive_master_secret is version[1]="+version[1]+"\n");
+ //! TLS 1.3 and later.
+ //!
+ //! Generate a key share offer for the configured named group
+ //! (currently only implemented in @[KeyShareECDHE] and @[KeyShareDHE]).
+ optional void make_key_share_offer(Stdio.Buffer offer);
- res = session->cipher_spec->prf(premaster_secret, "master secret",
- client_random + server_random, 48);
+ //! TLS 1.3 and later.
+ //!
+ //! Receive a key share offer key exchange for the configured group
+ //! (currently only implemented in @[KeyShareECDHE] and @[KeyShareDHE]).
+ //!
+ //! @note
+ //! Clears the secret state.
+ //!
+ //! @returns
+ //! Returns the shared pre-master key.
+ optional string(8bit) receive_key_share_offer(string(8bit) offer);
- connection->ke = UNDEFINED;
+ //! TLS 1.3 and later.
+ //!
+ //! Set the group or curve to be used.
+ optional void set_group(int group);
- SSL3_DEBUG_MSG("master: %O\n", res);
- return res;
+ //! The default implementation calls @[server_key_params()] to generate
+ //! the base payload.
+ //!
+ //! @returns
+ //! Returns the signed payload for a @[HANDSHAKE_server_key_exchange].
+ string(8bit) server_key_exchange_packet(string client_random,
+ string server_random)
+ {
+ Stdio.Buffer struct = server_key_params();
+ if (!struct) return 0;
+
+ session->cipher_spec->sign(session, client_random + server_random, struct);
+ return struct->read();
}
//! @returns
- //! Returns the payload for a @[HANDSHAKE_client_key_exchange] packet.
+ //! Returns the premaster secret, and fills in the payload for
+ //! a @[HANDSHAKE_client_key_exchange] packet in the submitted buffer.
+ //!
//! May return @expr{0@} (zero) to generate an @[ALERT_unexpected_message].
- string client_key_exchange_packet(string client_random,
- string server_random,
- array(int) version);
+ string(8bit) client_key_exchange_packet(Stdio.Buffer packet_data,
+ ProtocolVersion version);
//! @param data
//! Payload from a @[HANDSHAKE_client_key_exchange].
//!
//! @returns
- //! Master secret or alert number.
+ //! Premaster secret or alert number.
//!
//! @note
- //! May set @[message_was_bad] and return a fake master secret.
- string(0..255)|int server_derive_master_secret(string(0..255) data,
- string(0..255) client_random,
- string(0..255) server_random,
- array(int) version);
+ //! May set @[message_was_bad] and return a fake premaster secret.
+ string(8bit)|int(8bit) got_client_key_exchange(Stdio.Buffer data,
+ ProtocolVersion version);
//! @param input
- //! @[ADT.struct] with the content of a @[HANDSHAKE_server_key_exchange].
+ //! @[Stdio.Buffer] with the content of a
+ //! @[HANDSHAKE_server_key_exchange].
//!
//! @returns
//! The key exchange information should be extracted from @[input],
//! so that it is positioned at the signature.
//!
- //! Returns a new @[ADT.struct] with the unsigned payload of @[input].
- ADT.struct parse_server_key_exchange(ADT.struct input);
+ //! Returns a new @[Stdio.Buffer] with the unsigned payload of
+ //! @[input].
+ Stdio.Buffer parse_server_key_exchange(Stdio.Buffer input);
//! @param input
- //! @[ADT.struct] with the content of a @[HANDSHAKE_server_key_exchange].
+ //! @[Stdio.Buffer] with the content of a
+ //! @[HANDSHAKE_server_key_exchange].
//!
//! The default implementation calls @[parse_server_key_exchange()],
//! and then verifies the signature.
//!
//! @returns
//! @int
//! @value 0
//! Returns zero on success.
//! @value -1
//! Returns negative on verification failure.
//! @endint
- int server_key_exchange(ADT.struct input,
+ int got_server_key_exchange(Stdio.Buffer input,
string client_random,
string server_random)
{
- SSL3_DEBUG_MSG("SSL.session: SERVER_KEY_EXCHANGE\n");
+ SSL3_DEBUG_MSG("SSL.Session: SERVER_KEY_EXCHANGE\n");
- ADT.struct temp_struct = parse_server_key_exchange(input);
-
+ Stdio.Buffer struct = parse_server_key_exchange(input);
int verification_ok;
-
+
+ if(struct)
+ {
mixed err = catch {
verification_ok = session->cipher_spec->verify(
- session, client_random + server_random, temp_struct, input);
+ session, client_random + server_random + (string)struct, input);
};
#ifdef SSL3_DEBUG
if( err ) {
master()->handle_error(err);
}
#endif
- err = UNDEFINED;
+ }
+
if (!verification_ok)
{
connection->ke = UNDEFINED;
return -1;
}
return 0;
}
}
//! Key exchange for @[KE_null].
//!
//! This is the NULL @[KeyExchange], which is only used for the
//! @[SSL_null_with_null_null] cipher suite, which is usually disabled.
class KeyExchangeNULL
{
inherit KeyExchange;
- ADT.struct server_key_params()
+ Stdio.Buffer server_key_params()
{
- return ADT.struct();
+ return Stdio.Buffer();
}
- string client_key_exchange_packet(string client_random,
- string server_random,
- array(int) version)
+ string(8bit) client_key_exchange_packet(Stdio.Buffer packet_data,
+ ProtocolVersion version)
{
anonymous = 1;
- session->master_secret = "";
+
return "";
}
//! @returns
- //! Master secret or alert number.
- string(0..255)|int server_derive_master_secret(string(0..255) data,
- string(0..255) client_random,
- string(0..255) server_random,
- array(int) version)
+ //! Premaster secret or alert number.
+ string(8bit) got_client_key_exchange(Stdio.Buffer data,
+ ProtocolVersion version)
{
anonymous = 1;
return "";
}
- int server_key_exchange(ADT.struct input,
+ int got_server_key_exchange(Stdio.Buffer input,
string client_random,
string server_random)
{
return 0;
}
}
-
+ //! Key exchange for @[KE_psk], pre shared keys.
+ class KeyExchangePSK
+ {
+ inherit KeyExchange;
+
+ protected string hint;
+
+ Stdio.Buffer server_key_exchange_packet()
+ {
+ Stdio.Buffer ret = Stdio.Buffer();
+ if( context->get_psk_hint )
+ {
+ string str = context->get_psk_hint();
+ if( str )
+ ret->add_hstring(str, 2);
+ }
+ return ret;
+ }
+
+ string(8bit) client_key_exchange_packet(Stdio.Buffer packet_data,
+ ProtocolVersion version)
+ {
+ anonymous = 1;
+
+ string id = context->get_psk_id(hint);
+ if( !id ) return 0;
+ packet_data->add_hstring(id, 2);
+
+ string psk = context->get_psk(id);
+ return sprintf("%2H%2H", "\0"*sizeof(psk), psk);
+ }
+
+ string(8bit)|int(8bit) got_client_key_exchange(Stdio.Buffer data,
+ ProtocolVersion version)
+ {
+ anonymous = 1;
+
+ string psk = context->get_psk( data->read_hstring(2) );
+ if( sizeof(data) )
+ return ALERT_unexpected_message;
+ if( !psk )
+ return ALERT_unknown_psk_identity;
+
+ return sprintf("%2H%2H", "\0"*sizeof(psk), psk);
+ }
+
+ int got_server_key_exchange(Stdio.Buffer input,
+ string client_random,
+ string server_random)
+ {
+ if( sizeof(input) )
+ hint = input->read_hstring(2);
+ if( sizeof(input) )
+ return -1;
+
+ return 0;
+ }
+ }
+
//! Key exchange for @[KE_rsa].
//!
//! @[KeyExchange] that uses the Rivest Shamir Adelman algorithm.
class KeyExchangeRSA
{
inherit KeyExchange;
- Crypto.RSA temp_key; /* Key used for session key exchange (if not the same
- * as the server's certified key) */
+ Crypto.RSA rsa; /* Key used for session key exchange. Typically the
+ * server's certified key, but may get overridden
+ * in KeyExchangeExportRSA.
+ */
- ADT.struct server_key_params()
+ int(0..1) init_client()
{
- ADT.struct struct;
+ rsa = session->peer_public_key;
+ return 1;
+ }
- SSL3_DEBUG_MSG("KE_RSA\n");
- temp_key = (session->cipher_spec->is_exportable
- ? context->short_rsa
- : context->long_rsa);
- if (temp_key)
+ int(0..1) init_server()
{
- /* Send a ServerKeyExchange message. */
-
- SSL3_DEBUG_MSG("Sending a server key exchange-message, "
- "with a %d-bits key.\n", temp_key->key_size());
- struct = ADT.struct();
- struct->put_bignum(temp_key->get_n());
- struct->put_bignum(temp_key->get_e());
+ rsa = session->private_key;
+ return 1;
}
- else
- return 0;
+
- return struct;
+ Stdio.Buffer server_key_params()
+ {
+ SSL3_DEBUG_MSG("KE_RSA\n");
+ return 0;
}
- string client_key_exchange_packet(string client_random,
- string server_random,
- array(int) version)
+ string(8bit) client_key_exchange_packet(Stdio.Buffer packet_data,
+ ProtocolVersion version)
{
- SSL3_DEBUG_MSG("client_key_exchange_packet(%O, %O, %d.%d)\n",
- client_random, server_random, version[0], version[1]);
- ADT.struct struct = ADT.struct();
- string data;
- string premaster_secret;
-
+ SSL3_DEBUG_MSG("client_key_exchange_packet(%O, %d.%d)\n",
+ packet_data, version>>8, version & 0xff);
SSL3_DEBUG_MSG("KE_RSA\n");
-
+
// NOTE: To protect against version roll-back attacks,
// the version sent here MUST be the same as the
// one in the initial handshake!
- struct->put_uint(client_version[0], 1);
- struct->put_uint(client_version[1], 1);
- string random = context->random(46);
- struct->put_fix_string(random);
- premaster_secret = struct->pop_data();
+ Stdio.Buffer struct = Stdio.Buffer();
+ struct->add_int(client_version, 2);
+ struct->add( context->random(46) );
+ string premaster_secret = struct->read();
- SSL3_DEBUG_MSG("temp_key: %O\n"
- "session->rsa: %O\n", temp_key, session->rsa);
- data = (temp_key || session->rsa)->encrypt(premaster_secret);
+ SSL3_DEBUG_MSG("rsa: %O\n", rsa);
+ string(8bit) data = rsa->encrypt(premaster_secret);
- if(version[1] >= PROTOCOL_TLS_1_0)
- data=sprintf("%2H", [string(0..255)]data);
+ if(version >= PROTOCOL_TLS_1_0) {
+ packet_data->add_hstring(data, 2);
+ } else {
+ packet_data->add(data);
+ }
- session->master_secret = derive_master_secret(premaster_secret,
- client_random,
- server_random,
- version);
- return data;
+ return premaster_secret;
}
//! @returns
- //! Master secret or alert number.
- string(0..255)|int server_derive_master_secret(string(0..255) data,
- string(0..255) client_random,
- string(0..255) server_random,
- array(int) version)
+ //! Premaster secret or alert number.
+ string(8bit)|int(8bit) got_client_key_exchange(Stdio.Buffer input,
+ ProtocolVersion version)
{
string premaster_secret;
- SSL3_DEBUG_MSG("server_derive_master_secret: ke_method %d\n",
+ SSL3_DEBUG_MSG("got_client_key_exchange: ke_method %d\n",
session->ke_method);
SSL3_DEBUG_MSG("KE_RSA\n");
- /* Decrypt the premaster_secret */
- SSL3_DEBUG_MSG("encrypted premaster_secret: %O\n", data);
- SSL3_DEBUG_MSG("temp_key: %O\n"
- "session->rsa: %O\n", temp_key, session->rsa);
- if(version[1] >= PROTOCOL_TLS_1_0) {
- if(sizeof(data)-2 == data[0]*256+data[1]) {
- premaster_secret = (temp_key || session->rsa)->decrypt(data[2..]);
- }
- } else {
- premaster_secret = (temp_key || session->rsa)->decrypt(data);
- }
+
+ string data;
+ if(version >= PROTOCOL_TLS_1_0)
+ data = input->read_hstring(2);
+ else
+ data = input->read();
+
+ // Decrypt, even when we know data is incorrect, for time invariance.
+ premaster_secret = rsa->decrypt(data) || "xx";
+
SSL3_DEBUG_MSG("premaster_secret: %O\n", premaster_secret);
- if (!premaster_secret
- || (sizeof(premaster_secret) != 48)
- || (premaster_secret[0] != 3)
- || (premaster_secret[1] != client_version[1]))
+
+ // We want both branches to execute in equal time (ignoring
+ // SSL3_DEBUG in the hope it is never on in production).
+ // Workaround documented in RFC 2246.
+ if ( `+( (sizeof(premaster_secret) != 48),
+ (premaster_secret[0] != 3),
+ (premaster_secret[1] != (client_version & 0xff)) ))
{
/* To avoid the chosen ciphertext attack discovered by Daniel
* Bleichenbacher, it is essential not to send any error
* messages back to the client until after the client's
* Finished-message (or some other invalid message) has been
* received.
*/
/* Also checks for version roll-back attacks.
*/
#ifdef SSL3_DEBUG
- werror("SSL.handshake: Invalid premaster_secret! "
+ werror("SSL.ServerConnection: Invalid premaster_secret! "
"A chosen ciphertext attack?\n");
if (premaster_secret && sizeof(premaster_secret) > 2) {
- werror("SSL.handshake: Strange version (%d.%d) detected in "
+ werror("SSL.ServerConnection: Strange version (%d.%d) detected in "
"key exchange message (expected %d.%d).\n",
premaster_secret[0], premaster_secret[1],
- client_version[0], client_version[1]);
+ client_version>>8, client_version & 0xff);
}
#endif
premaster_secret = context->random(48);
message_was_bad = 1;
connection->ke = UNDEFINED;
} else {
-
+ string timing_attack_mitigation = context->random(48);
+ message_was_bad = 0;
+ connection->ke = this;
}
- return derive_master_secret(premaster_secret, client_random, server_random,
- version);
+ return premaster_secret;
}
-
+ }
- ADT.struct parse_server_key_exchange(ADT.struct input)
+ //! Key exchange for @[KE_rsa_export].
+ //!
+ //! @[KeyExchange] that uses the Rivest Shamir Adelman algorithm,
+ //! but limited to 512 bits for encryption and decryption.
+ class KeyExchangeExportRSA
{
- ADT.struct temp_struct = ADT.struct();
+ inherit KeyExchangeRSA;
-
+ Stdio.Buffer server_key_params()
+ {
+ SSL3_DEBUG_MSG("KE_EXPORT_RSA\n");
+
+ rsa = context->get_export_rsa_key();
+ SSL3_DEBUG_MSG("Sending a server key exchange-message, "
+ "with a %d-bits key.\n",
+ rsa->key_size());
+ Stdio.Buffer output = Stdio.Buffer();
+ output->add_hint(rsa->get_n(),2);
+ output->add_hint(rsa->get_e(),2);
+ return output;
+ }
+
+ Stdio.Buffer parse_server_key_exchange(Stdio.Buffer input)
+ {
SSL3_DEBUG_MSG("KE_RSA\n");
- Gmp.mpz n = input->get_bignum();
- Gmp.mpz e = input->get_bignum();
- temp_struct->put_bignum(n);
- temp_struct->put_bignum(e);
- Crypto.RSA rsa = Crypto.RSA();
- rsa->set_public_key(n, e);
- context->long_rsa = session->rsa;
- context->short_rsa = rsa;
- if (session->cipher_spec->is_exportable) {
- temp_key = rsa;
+
+ string n = input->read_hstring(2);
+ string e = input->read_hstring(2);
+
+ rsa = Crypto.RSA()->set_public_key(Gmp.mpz(n,256), Gmp.mpz(e,256));
+
+ Stdio.Buffer output = Stdio.Buffer();
+ output->add_hstring(n, 2);
+ output->add_hstring(e, 2);
+ return output;
}
-
+ }
- return temp_struct;
+ //! Key exchange for @[KE_rsa_psk].
+ class KeyExchangeRSAPSK
+ {
+ inherit KeyExchangePSK;
+
+ string(8bit) client_key_exchange_packet(Stdio.Buffer packet_data,
+ ProtocolVersion version)
+ {
+ string id = context->get_psk_id(hint);
+ if( !id ) return 0;
+ packet_data->add_hstring(id, 2);
+
+ // PreMasterSecret/EncryptedPreMasterSecret from TLS 1.0.
+ Stdio.Buffer struct = Stdio.Buffer();
+ struct->add_int(client_version, 2);
+ struct->add( context->random(46) );
+ string premaster_secret = struct->read();
+ packet_data->add( session->peer_public_key->encrypt(premaster_secret) );
+
+ string psk = context->get_psk(id);
+ Stdio.Buffer master_secret = Stdio.Buffer();
+ master_secret->add_hstring(premaster_secret, 2);
+ master_secret->add_hstring(psk, 2);
+ return master_secret->read();
}
-
+
+ string(8bit)|int(8bit) got_client_key_exchange(Stdio.Buffer data,
+ ProtocolVersion version)
+ {
+ string psk = context->get_psk( data->read_hstring(2) );
+ if( !psk )
+ return ALERT_unknown_psk_identity;
+
+ string premaster_secret = session->private_key->decrypt( data->read() ) ||
+ "xx";
+
+ if ( `+( (sizeof(premaster_secret) != 48),
+ (premaster_secret[0] != 3),
+ (premaster_secret[1] != (client_version & 0xff)) ))
+ {
+ premaster_secret = context->random(48);
+ message_was_bad = 1;
+ connection->ke = UNDEFINED;
+ } else {
+ string timing_attack_mitigation = context->random(48);
+ message_was_bad = 0;
+ connection->ke = this;
}
- //! Key exchange for @[KE_dh_anon].
+ Stdio.Buffer master_secret = Stdio.Buffer();
+ master_secret->add_hstring(premaster_secret, 2);
+ master_secret->add_hstring(psk, 2);
+ return master_secret->read();
+ }
+ }
+
+ //! KeyExchange for @[KE_dhe_rsa], @[KE_dhe_dss] and @[KE_dh_anon].
//!
- //! @[KeyExchange] that uses anonymous Diffie-Hellman.
- class KeyExchangeDH
+ //! KeyExchange that uses Diffie-Hellman to generate an Ephemeral key.
+ class KeyExchangeDHE
{
inherit KeyExchange;
- .Cipher.DHKeyExchange dh_state; /* For diffie-hellman key exchange */
+ //! Finite field Diffie-Hellman parameters.
+ Crypto.DH.Parameters parameters;
- ADT.struct server_key_params()
+ Gmp.mpz our; /* Our value */
+ private Gmp.smpz other; /* Other party's value */
+ Gmp.mpz secret; /* our = g ^ secret mod p */
+
+ protected void new_secret()
{
- ADT.struct struct;
+ [our, secret] = parameters->generate_keypair(context->random);
+ }
- SSL3_DEBUG_MSG("KE_DH\n");
+ protected Gmp.mpz get_shared()
+ {
+ Gmp.mpz shared = other->powm(secret, parameters->p);
+ secret = 0;
+ return shared;
+ }
+
+ //! Set the value received from the peer.
+ //!
+ //! @returns
+ //! Returns @expr{1@} if @[o] is valid for the set @[parameters].
+ //!
+ //! Otherwise returns @[UNDEFINED].
+ protected int(0..1) set_other(Gmp.smpz o)
+ {
+ if ((o <= 1) || (o >= (parameters->p - 1))) {
+ // Negotiated FF DHE Parameters Draft 4 3:
+ // If the selected group matches an offered FFDHE group exactly, the
+ // the client MUST verify that dh_Ys is in the range 1 < dh_Ys < dh_p
+ // - 1. If dh_Ys is not in this range, the client MUST terminate the
+ // connection with a fatal handshake_failure(40) alert.
+ //
+ // Negotiated FF DHE Parameters Draft 4 4:
+ // When a compatible server selects an FFDHE group from among a
+ // client's Supported Groups, and the client sends a ClientKeyExchange,
+ // the server MUST verify that 1 < dh_Yc < dh_p - 1. If it is out of
+ // range, the server MUST terminate the connection with fatal
+ // handshake_failure(40) alert.
+ return UNDEFINED;
+ }
+ other = o;
+ return 1;
+ }
+
+ Stdio.Buffer server_key_params()
+ {
+ SSL3_DEBUG_MSG("KE_DHE\n");
// anonymous, not used on the server, but here for completeness.
anonymous = 1;
- struct = ADT.struct();
+
- dh_state = context->dh_ke = .Cipher.DHKeyExchange(.Cipher.DHParameters());
- dh_state->new_secret(context->random);
+ // NIST SP800-57 5.6.1
+ // { symmetric key length, p limit, q limit }
+ constant nist_strength = ({
+ ({ 80, 1024, 160 }),
+ ({ 112, 2048, 224 }),
+ ({ 128, 3072, 256 }),
+ ({ 192, 7680, 384 }),
+ ({ 256, 15360, 511 }),
+ });
+ int key_strength = CIPHER_effective_keylengths
+ [ CIPHER_SUITES[ session->cipher_suite ][1] ];
+ int target_p, target_q;
+ foreach(nist_strength, [int key, target_p, target_q])
+ if( key_strength <= key ) break;
- struct->put_bignum(dh_state->parameters->p);
- struct->put_bignum(dh_state->parameters->g);
- struct->put_bignum(dh_state->our);
+ Crypto.DH.Parameters p;
+ foreach( context->ffdhe_groups, int g )
+ {
+ Crypto.DH.Parameters o =
+ FFDHE_GROUPS[g] || context->private_ffdhe_groups[g];
+ if (!o) continue; // Paranoia.
+ if( !p || o->p->size()>p->p->size() ||
+ (o->p->size()==p->p->size() && o->q->size()>p->q->size()) )
+ p = o;
+ if( p->p->size() >= target_p && p->q->size() >= target_q )
+ break;
+ }
- return struct;
+ // FIXME: Fall back to just selecting a group and pretend
+ // not to support the FFDHE extension?
+ if(!p) error("No suitable DH group in Context.\n");
+ parameters = p;
+ new_secret();
+
+ Stdio.Buffer output = Stdio.Buffer();
+ output->add_hint(parameters->p, 2);
+ output->add_hint(parameters->g, 2);
+ output->add_hint(our, 2);
+ return output;
}
- string client_key_exchange_packet(string client_random,
- string server_random,
- array(int) version)
+ string(8bit) client_key_exchange_packet(Stdio.Buffer packet_data,
+ ProtocolVersion version)
{
- SSL3_DEBUG_MSG("client_key_exchange_packet(%O, %O, %d.%d)\n",
- client_random, server_random, version[0], version[1]);
- ADT.struct struct = ADT.struct();
- string data;
- string premaster_secret;
+ SSL3_DEBUG_MSG("client_key_exchange_packet(%O, %d.%d)\n",
+ packet_data, version>>8, version & 0xff);
- SSL3_DEBUG_MSG("KE_DHE\n");
+ SSL3_DEBUG_MSG("KE_DH/KE_DHE\n");
anonymous = 1;
- context->dh_ke->new_secret(context->random);
- struct->put_bignum(context->dh_ke->our);
- data = struct->pop_data();
- premaster_secret = context->dh_ke->get_shared()->digits(256);
+ if (!parameters) {
+ SSL3_DEBUG_MSG("Invalid DH exchange.\n");
+ return 0;
+ }
+ new_secret();
- session->master_secret =
- derive_master_secret(premaster_secret, client_random, server_random,
- version);
- return data;
+ string premaster_secret = get_shared()->digits(256);
+
+ packet_data->add_hint(our, 2);
+ return premaster_secret;
}
//! @returns
- //! Master secret or alert number.
- string(0..255)|int server_derive_master_secret(string(0..255) data,
- string(0..255) client_random,
- string(0..255) server_random,
- array(int) version)
+ //! Premaster secret or alert number.
+ string(8bit)|int(8bit) got_client_key_exchange(Stdio.Buffer input,
+ ProtocolVersion version)
{
string premaster_secret;
- SSL3_DEBUG_MSG("server_derive_master_secret: ke_method %d\n",
+ SSL3_DEBUG_MSG("got_client_key_exchange: ke_method %d\n",
session->ke_method);
- SSL3_DEBUG_MSG("KE_DH\n");
+ SSL3_DEBUG_MSG("KE_DH/KE_DHE\n");
anonymous = 1;
- /* Explicit encoding */
- ADT.struct struct = ADT.struct(data);
+ if (!sizeof(input))
+ {
+ /* Implicit encoding; Should never happen unless we have
+ * requested and received a client certificate of type
+ * rsa_fixed_dh or dss_fixed_dh. Not supported. */
+ SSL3_DEBUG_MSG("SSL.ServerConnection: Client uses implicit encoding if its DH-value.\n"
+ " Hanging up.\n");
+ connection->ke = UNDEFINED;
+ return ALERT_certificate_unknown;
+ }
- if (catch
+ if (!set_other(Gmp.smpz(input->read_hint(2)))) {
+ connection->ke = UNDEFINED;
+ return ALERT_handshake_failure;
+ }
+
+ if(sizeof(input))
{
- dh_state->set_other(struct->get_bignum());
- } || !struct->is_empty())
- {
+
connection->ke = UNDEFINED;
- return ALERT_unexpected_message;
+ return ALERT_handshake_failure;
}
- premaster_secret = dh_state->get_shared()->digits(256);
- dh_state = 0;
+ premaster_secret = get_shared()->digits(256);
+ parameters = 0;
- return derive_master_secret(premaster_secret, client_random, server_random,
- version);
+ return premaster_secret;
}
- ADT.struct parse_server_key_exchange(ADT.struct input)
+ Stdio.Buffer parse_server_key_exchange(Stdio.Buffer input)
{
- ADT.struct temp_struct = ADT.struct();
+ SSL3_DEBUG_MSG("KE_DHE\n");
+ string p = input->read_hstring(2);
+ string g = input->read_hstring(2);
+ string o = input->read_hstring(2);
- SSL3_DEBUG_MSG("KE_DH\n");
- Gmp.mpz p = input->get_bignum();
- Gmp.mpz g = input->get_bignum();
- Gmp.mpz order = [object(Gmp.mpz)]((p-1)/2); // FIXME: Is this correct?
- temp_struct->put_bignum(p);
- temp_struct->put_bignum(g);
- context->dh_ke =
- .Cipher.DHKeyExchange(.Cipher.DHParameters(p, g, order));
- context->dh_ke->set_other(input->get_bignum());
- temp_struct->put_bignum(context->dh_ke->other);
+ Crypto.DH.Parameters params = Crypto.DH.Parameters(Gmp.mpz(p,256),
+ Gmp.mpz(g,256));
+ if( !validate_dh(params, session, context) )
+ {
+ SSL3_DEBUG_MSG("DH parameters not correct or not secure.\n");
+ return 0;
+ }
- return temp_struct;
+ parameters = params;
+ if (!set_other(Gmp.smpz(o,256))) {
+ SSL3_DEBUG_MSG("DH Ys not valid for set parameters.\n");
+ parameters = 0;
+ return 0;
}
-
+
+ Stdio.Buffer output = Stdio.Buffer();
+ output->add_hstring(p, 2);
+ output->add_hstring(g, 2);
+ output->add_hstring(o, 2);
+ return output;
}
-
+ }
- //! KeyExchange for @[KE_dhe_rsa] and @[KE_dhe_dss].
- //!
- //! KeyExchange that uses Diffie-Hellman to generate an Ephemeral key.
- class KeyExchangeDHE
+ //! Key exchange for @[KE_dhe_psk].
+ class KeyExchangeDHEPSK
{
- inherit KeyExchangeDH;
+ inherit KeyExchangePSK : PSK;
+ inherit KeyExchangeDHE : DHE;
- //! @returns
- //! Master secret or alert number.
- string(0..255)|int server_derive_master_secret(string(0..255) data,
- string(0..255) client_random,
- string(0..255) server_random,
- array(int) version)
+ protected void create(object context, object session, object connection,
+ ProtocolVersion client_version)
{
- SSL3_DEBUG_MSG("server_derive_master_secret: ke_method %d\n",
- session->ke_method);
+ PSK::create(context, session, connection, client_version);
+ DHE::create(context, session, connection, client_version);
+ }
- SSL3_DEBUG_MSG("KE_DHE\n");
+ Stdio.Buffer server_key_exchange_packet()
+ {
+ Stdio.Buffer psk = PSK::server_key_exchange_packet();
+ if( !sizeof(psk) )
+ psk->add_int(0, 2);
+ Stdio.Buffer dhe = DHE::server_key_params();
+ return psk->add(dhe);
+ }
- if (!sizeof(data))
+ string(8bit) client_key_exchange_packet(Stdio.Buffer packet_data,
+ ProtocolVersion version)
{
- /* Implicit encoding; Should never happen unless we have
- * requested and received a client certificate of type
- * rsa_fixed_dh or dss_fixed_dh. Not supported. */
- SSL3_DEBUG_MSG("SSL.handshake: Client uses implicit encoding if its DH-value.\n"
- " Hanging up.\n");
- connection->ke = UNDEFINED;
- return ALERT_certificate_unknown;
+ string(8bit) id = context->get_psk_id(hint);
+ if( !id ) return 0;
+ packet_data->add_hstring(id, 2);
+
+ string(8bit) s = DHE::client_key_exchange_packet(packet_data, version);
+ if( !s ) return 0;
+
+ string(8bit) psk = context->get_psk(id);
+ return s + sprintf("%2H", psk);
}
- return ::server_derive_master_secret(data, client_random, server_random,
- version);
+ string(8bit)|int(8bit) got_client_key_exchange(Stdio.Buffer data,
+ ProtocolVersion version)
+ {
+ string(8bit) psk = context->get_psk( data->read_hstring(2) );
+ if( !psk )
+ return ALERT_unknown_psk_identity;
+
+ string(8bit)|int(8bit) s = DHE::got_client_key_exchange(data, version);
+ if( intp(s) ) return s;
+
+ return [string(8bit)]s + sprintf("%2H", psk);
}
-
+
+ int got_server_key_exchange(Stdio.Buffer input,
+ string client_random,
+ string server_random)
+ {
+ hint = input->read_hstring(2);
+ DHE::parse_server_key_exchange(input);
+ return 0;
}
-
+ }
- #if constant(Crypto.ECC.Curve)
- //! KeyExchange for @[KE_ecdhe_rsa] and @[KE_ecdhe_ecdsa].
+ //! Key exchange for @[KE_dh_dss] and @[KE_dh_dss].
//!
- //! KeyExchange that uses Elliptic Curve Diffie-Hellman to
- //! generate an Ephemeral key.
- class KeyExchangeECDHE
+ //! @[KeyExchange] that uses Diffie-Hellman with a key from
+ //! a DSS certificate.
+ class KeyExchangeDH
{
- inherit KeyExchange;
+ inherit KeyExchangeDHE;
- protected Gmp.mpz secret;
- protected Gmp.mpz pubx;
- protected Gmp.mpz puby;
+ int(0..1) init_server()
+ {
+ parameters = Crypto.DH.Parameters(session->private_key);
+ secret = session->private_key->get_x();
+ return ::init_server();
+ }
- string(8bit) encode_point(Gmp.mpz x, Gmp.mpz y)
+ int(0..1) init_client()
{
- // ANSI x9.62 4.3.6.
- // Format #4 is uncompressed.
- return sprintf("%c%*c%*c",
- 4,
- (session->curve->size() + 7)>>3, x,
- (session->curve->size() + 7)>>3, y);
+ Crypto.DH.Parameters p = Crypto.DH.Parameters(session->peer_public_key);
+ if( !validate_dh(p, session, context) )
+ {
+ SSL3_DEBUG_MSG("DH parameters not correct or not secure.\n");
+ return 0;
}
-
+ parameters = p;
+ if (!set_other(Gmp.smpz(session->peer_public_key->get_y()))) {
+ SSL3_DEBUG_MSG("DH Ys not valid for set parameters.\n");
+ parameters = 0;
+ return 0;
+ }
+ return ::init_client();
+ }
- array(Gmp.mpz) decode_point(string(8bit) data)
+ Stdio.Buffer server_key_params()
{
- ADT.struct struct = ADT.struct(data);
+ SSL3_DEBUG_MSG("KE_DH\n");
+ // RFC 4346 7.4.3:
+ // It is not legal to send the server key exchange message for the
+ // following key exchange methods:
+ //
+ // RSA
+ // DH_DSS
+ // DH_RSA
+ return 0;
+ }
- Gmp.mpz x;
- Gmp.mpz y;
- switch(struct->get_uint(1)) {
- case 4:
- string rest = struct->get_rest();
- if (sizeof(rest) & 1) {
- connection->ke = UNDEFINED;
- error("Invalid size in point format.\n");
+ Stdio.Buffer parse_server_key_exchange(Stdio.Buffer input)
+ {
+ SSL3_DEBUG_MSG("KE_DH\n");
+ // RFC 4346 7.4.3:
+ // It is not legal to send the server key exchange message for the
+ // following key exchange methods:
+ //
+ // RSA
+ // DH_DSS
+ // DH_RSA
+ error("Invalid message.\n");
}
- [x, y] = map(rest/(sizeof(rest)/2), Gmp.mpz, 256);
- break;
- default:
- // Compressed points not supported yet.
- connection->ke = UNDEFINED;
- error("Unsupported point format.\n");
- break;
+
}
- return ({ x, y });
+
+ class KeyShareDHE
+ {
+ inherit KeyExchangeDHE;
+
+ int group;
+
+ void make_key_share_offer(Stdio.Buffer offer)
+ {
+ offer->add_int(group, 2);
+ offer->add_hint(our, 2);
}
- ADT.struct server_key_params()
+ string(8bit) receive_key_share_offer(string(8bit) offer)
{
- ADT.struct struct;
+ set_other(Gmp.smpz(offer, 256));
-
+ string(8bit) premaster_secret = get_shared()->digits(256);
+
+ parameters = UNDEFINED;
+
+ return premaster_secret;
+ }
+
+ void set_group(int g)
+ {
+ group = g;
+ parameters = FFDHE_GROUPS[g] || context->private_ffdhe_groups[g];
+ if (!parameters) error("Unsupported FF-DHE group.\n");
+ new_secret();
+ }
+ }
+
+ #if constant(Crypto.ECC.Curve)
+ //! KeyExchange for @[KE_ecdhe_rsa] and @[KE_ecdhe_ecdsa].
+ //!
+ //! KeyExchange that uses Elliptic Curve Diffie-Hellman to
+ //! generate an Ephemeral key.
+ class KeyExchangeECDHE
+ {
+ inherit KeyExchange;
+
+ protected Gmp.mpz|string(8bit) secret;
+ protected Crypto.ECC.Curve.Point point;
+
+ int(0..1) init_client()
+ {
+ session->curve =
+ ([object(Crypto.ECC.Curve.ECDSA)]session->peer_public_key)->
+ get_curve();
+ return ::init_client();
+ }
+
+ Stdio.Buffer server_key_params()
+ {
SSL3_DEBUG_MSG("KE_ECDHE\n");
// anonymous, not used on the server, but here for completeness.
anonymous = 1;
- struct = ADT.struct();
+
// Select a suitable curve.
- int c = connection->ecc_curves[0];
+ int c;
+ switch(session->cipher_spec->key_bits) {
+ case 257..:
+ c = GROUP_secp521r1;
+ break;
+ case 129..256:
+ // Suite B requires SECP384r1
+ c = GROUP_secp384r1;
+ break;
+ case ..128:
+ c = GROUP_secp256r1;
+ break;
+ }
+
+ if (!has_value(session->ecc_curves, c)) {
+ // Preferred curve not available -- Select the strongest available.
+ c = session->ecc_curves[0];
+ }
session->curve = ECC_CURVES[c];
- SSL3_DEBUG_MSG("Curve: %d: %O\n", c, session->curve);
+ SSL3_DEBUG_MSG("Curve: %s: %O\n", fmt_constant(c, "GROUP"), session->curve);
secret = session->curve->new_scalar(context->random);
- [Gmp.mpz x, Gmp.mpz y] = session->curve * secret;
+ Crypto.ECC.Curve.Point p = session->curve * secret;
SSL3_DEBUG_MSG("secret: %O\n", secret);
- SSL3_DEBUG_MSG("x: %O\n", x);
- SSL3_DEBUG_MSG("y: %O\n", y);
+ SSL3_DEBUG_MSG("x: %O\n", p->get_x());
+ SSL3_DEBUG_MSG("y: %O\n", p->get_y());
- struct->put_uint(CURVETYPE_named_curve, 1);
- struct->put_uint(c, 2);
-
- struct->put_var_string(encode_point(x, y), 1);
-
+ Stdio.Buffer struct = Stdio.Buffer();
+ struct->add_int(CURVETYPE_named_curve, 1);
+ struct->add_int(c, 2);
+ struct->add_hstring(p->encode(), 1);
return struct;
}
- string client_key_exchange_packet(string client_random,
- string server_random,
- array(int) version)
+ string(8bit) client_key_exchange_packet(Stdio.Buffer packet_data,
+ ProtocolVersion version)
{
- SSL3_DEBUG_MSG("client_key_exchange_packet(%O, %O, %d.%d)\n",
- client_random, server_random, version[0], version[1]);
- ADT.struct struct = ADT.struct();
- string data;
- string premaster_secret;
-
+ SSL3_DEBUG_MSG("client_key_exchange_packet(%O, %d.%d)\n",
+ packet_data, version>>8, version & 0xff);
SSL3_DEBUG_MSG("KE_ECDHE\n");
- anonymous = 1;
+
- secret = session->curve->new_scalar(context->random);
- [Gmp.mpz x, Gmp.mpz y] = session->curve * secret;
+ object(Gmp.mpz)|string(8bit) secret =
+ session->curve->new_scalar(context->random);
+ Crypto.ECC.Curve.Point p = session->curve * secret;
- ADT.struct point = ADT.struct();
-
- struct->put_var_string(encode_point(x, y), 1);
-
- data = struct->pop_data();
+
// RFC 4492 5.10:
// Note that this octet string (Z in IEEE 1363 terminology) as
// output by FE2OSP, the Field Element to Octet String
// Conversion Primitive, has constant length for any given
// field; leading zeros found in this octet string MUST NOT be
// truncated.
- premaster_secret =
- sprintf("%*c",
- (session->curve->size() + 7)>>3,
- session->curve->point_mul(pubx, puby, secret)[0]);
-
+ string premaster_secret = (point*secret)->get_x_str();
secret = 0;
- session->master_secret =
- derive_master_secret(premaster_secret, client_random, server_random,
- version);
- return data;
+ packet_data->add_hstring(p->encode(), 1);
+ return premaster_secret;
}
//! @returns
- //! Master secret or alert number.
- string(0..255)|int server_derive_master_secret(string(0..255) data,
- string(0..255) client_random,
- string(0..255) server_random,
- array(int) version)
+ //! Premaster secret or alert number.
+ string(8bit)|int(8bit) got_client_key_exchange(Stdio.Buffer data,
+ ProtocolVersion version)
{
- SSL3_DEBUG_MSG("server_derive_master_secret: ke_method %d\n",
+ SSL3_DEBUG_MSG("got_client_key_exchange: ke_method %d\n",
session->ke_method);
SSL3_DEBUG_MSG("KE_ECDHE\n");
if (!sizeof(data))
{
/* Implicit encoding; Should never happen unless we have
* requested and received a client certificate of type
* rsa_fixed_dh or dss_fixed_dh. Not supported. */
- SSL3_DEBUG_MSG("SSL.handshake: Client uses implicit encoding if its DH-value.\n"
+ SSL3_DEBUG_MSG("SSL.ServerConnection: Client uses implicit encoding if its DH-value.\n"
" Hanging up.\n");
connection->ke = UNDEFINED;
return ALERT_certificate_unknown;
}
string premaster_secret;
- anonymous = 1;
+
- /* Explicit encoding */
- ADT.struct struct = ADT.struct(data);
+ Crypto.ECC.Curve.Point point;
+ catch {
+ point = session->curve->Point(data->read_hbuffer(1));
+ };
+ if (!point)
+ return ALERT_decode_error;
- if (catch
- {
- [ Gmp.mpz x, Gmp.mpz y ] = decode_point(struct->get_var_string(1));
+
// RFC 4492 5.10:
// Note that this octet string (Z in IEEE 1363 terminology) as
// output by FE2OSP, the Field Element to Octet String
// Conversion Primitive, has constant length for any given
// field; leading zeros found in this octet string MUST NOT be
// truncated.
- premaster_secret =
- sprintf("%*c",
- (session->curve->size() + 7)>>3,
- session->curve->point_mul(x, y, secret)[0]);
- } || !struct->is_empty())
- {
- connection->ke = UNDEFINED;
- return ALERT_unexpected_message;
- }
+ premaster_secret = (point*secret)->get_x_str();
- secret = 0;
-
- return derive_master_secret(premaster_secret, client_random, server_random,
- version);
+ return premaster_secret;
}
- ADT.struct parse_server_key_exchange(ADT.struct input)
+ Stdio.Buffer parse_server_key_exchange(Stdio.Buffer input)
{
SSL3_DEBUG_MSG("KE_ECDHE\n");
- ADT.struct temp_struct = ADT.struct();
+ Stdio.Buffer.RewindKey key = input->rewind_key();
+ int len = sizeof(input);
// First the curve.
- switch(input->get_uint(1)) {
+ switch(input->read_int(1)) {
case CURVETYPE_named_curve:
- temp_struct->put_uint(CURVETYPE_named_curve, 1);
- int c = input->get_uint(2);
- temp_struct->put_uint(c, 2);
+ int c = input->read_int(2);
+ if (has_value(context->ecc_curves, c)) {
+ // Only look up curves that we are configured to support.
session->curve = ECC_CURVES[c];
-
+ }
if (!session->curve) {
connection->ke = UNDEFINED;
- error("Unsupported curve.\n");
+ error("Unsupported curve: %s.\n", fmt_constant(c, "GROUP"));
}
- SSL3_DEBUG_MSG("Curve: %d: %O\n", c, session->curve);
+ SSL3_DEBUG_MSG("Curve: %O (%O: %s)\n",
+ session->curve, c, fmt_constant(c, "GROUP"));
break;
default:
connection->ke = UNDEFINED;
error("Invalid curve encoding.\n");
break;
}
// Then the point.
- string raw;
- [ pubx, puby ] = decode_point(raw = input->get_var_string(1));
- temp_struct->put_var_string(raw, 1);
+ catch {
+ point = session->curve->Point(input->read_hbuffer(1));
+ };
+ if (!point)
+ return 0;
- return temp_struct;
+ len = len - sizeof(input);
+ key->rewind();
+ return input->read_buffer(len);
}
}
-
+ //! Key exchange for @[KE_ecdhe_psk].
+ class KeyExchangeECDHEPSK
+ {
+ inherit KeyExchangePSK : PSK;
+ inherit KeyExchangeECDHE : ECDHE;
+
+ protected void create(object context, object session, object connection,
+ ProtocolVersion client_version)
+ {
+ PSK::create(context, session, connection, client_version);
+ ECDHE::create(context, session, connection, client_version);
+ }
+
+ Stdio.Buffer server_key_exchange_packet()
+ {
+ Stdio.Buffer psk = PSK::server_key_exchange_packet();
+ if( !sizeof(psk) )
+ psk->add_int(0, 2);
+ Stdio.Buffer ecdhe = ECDHE::server_key_params();
+ return psk->add(ecdhe);
+ }
+
+ string(8bit) client_key_exchange_packet(Stdio.Buffer packet_data,
+ ProtocolVersion version)
+ {
+ string(8bit) id = context->get_psk_id(hint);
+ if( !id ) return 0;
+ packet_data->add_hstring(id, 2);
+
+ string(8bit) z = ECDHE::client_key_exchange_packet(packet_data, version);
+ if( !z ) return 0;
+
+ string(8bit) psk = context->get_psk(id);
+ return sprintf("%2H%2H", z, psk);
+ }
+
+ string(8bit)|int(8bit) got_client_key_exchange(Stdio.Buffer data,
+ ProtocolVersion version)
+ {
+ string(8bit) psk = context->get_psk( data->read_hstring(2) );
+ if( !psk )
+ return ALERT_unknown_psk_identity;
+
+ string(8bit)|int(8bit) z = ECDHE::got_client_key_exchange(data, version);
+ if( intp(z) ) return z;
+
+ return sprintf("%2H%2H", [string(8bit)]z, psk);
+ }
+
+ int got_server_key_exchange(Stdio.Buffer input,
+ string client_random,
+ string server_random)
+ {
+ hint = input->read_hstring(2);
+ ECDHE::parse_server_key_exchange(input);
+ return 0;
+ }
+ }
+
+ //! KeyExchange for @[KE_ecdh_rsa] and @[KE_ecdh_ecdsa].
+ //!
+ //! NB: The only difference between the two is whether the certificate
+ //! is signed with RSA or ECDSA.
+ //!
+ //! This KeyExchange uses the Elliptic Curve parameters from
+ //! the ECDSA certificate on the server side, and ephemeral
+ //! parameters on the client side.
+ class KeyExchangeECDH
+ {
+ inherit KeyExchangeECDHE;
+
+ int(0..1) init_server()
+ {
+ secret = session->private_key->get_private_key();
+ return ::init_server();
+ }
+
+ int(0..1) init_client()
+ {
+ point = session->peer_public_key->get_point();
+ return ::init_client();
+ }
+
+ Stdio.Buffer server_key_params()
+ {
+ SSL3_DEBUG_MSG("KE_ECDH\n");
+ // RFC 4492 2.1:
+ // A ServerKeyExchange MUST NOT be sent (the server's certificate
+ // contains all the necessary keying information required by the client
+ // to arrive at the premaster secret).
+ return 0;
+ }
+
+ Stdio.Buffer parse_server_key_exchange(Stdio.Buffer input)
+ {
+ SSL3_DEBUG_MSG("KE_ECDH\n");
+ // RFC 4492 2.1:
+ // A ServerKeyExchange MUST NOT be sent (the server's certificate
+ // contains all the necessary keying information required by the client
+ // to arrive at the premaster secret).
+ error("Invalid message.\n");
+ }
+ }
+
+ class KeyShareECDHE
+ {
+ inherit KeyExchangeECDHE;
+
+ int group;
+ Crypto.ECC.Curve curve;
+
+ void make_key_share_offer(Stdio.Buffer offer)
+ {
+ Crypto.ECC.Curve.Point p = curve * secret;
+
+ SSL3_DEBUG_MSG("secret: %O\n", secret);
+ SSL3_DEBUG_MSG("x: %O\n", p->get_x());
+ SSL3_DEBUG_MSG("y: %O\n", p->get_y());
+
+ offer->add_int(group, 2);
+ offer->add_hstring(p->encode(), 2);
+ }
+
+ string(8bit) receive_key_share_offer(string(8bit) offer)
+ {
+ catch {
+ point = curve->Point(Stdio.Buffer(offer));
+ };
+ if (!point)
+ return 0;
+
+ // RFC 4492 5.10:
+ // Note that this octet string (Z in IEEE 1363 terminology) as
+ // output by FE2OSP, the Field Element to Octet String
+ // Conversion Primitive, has constant length for any given
+ // field; leading zeros found in this octet string MUST NOT be
+ // truncated.
+ string premaster_secret =
+ sprintf("%*c", (curve->size() + 7)>>3, (point*secret)->get_x());
+ secret = 0;
+
+ return premaster_secret;
+ }
+
+ void set_group(int c)
+ {
+ group = c;
+ curve = ECC_CURVES[c];
+ if (!curve) error("Unsupported curve.\n");
+ secret = curve->new_scalar(context->random);
+ }
+ }
+
#endif /* Crypto.ECC.Curve */
- #if 0
- class mac_none
+ #if constant(GSSAPI)
+
+ //! Key exchange for @[KE_krb].
+ //!
+ //! @[KeyExchange] that uses Kerberos (@rfc{2712@}).
+ class KeyExchangeKRB
{
- /* Dummy MAC algorithm */
- string hash(string data, Gmp.mpz seq_num) { return ""; }
+ inherit KeyExchange;
+
+ GSSAPI.Context gss_context;
+
+ Stdio.Buffer server_key_params()
+ {
+ SSL3_DEBUG_MSG("KE_KRB\n");
+
+ // RFC 2712 3:
+ //
+ // The server's certificate, the client CertificateRequest, and
+ // the ServerKeyExchange shown in Figure 1 will be omitted since
+ // authentication and the establishment of a master secret will be
+ // done using the client's Kerberos credentials for the TLS server.
+
+ return 0;
}
-
+
+ string(8bit) client_key_exchange_packet(Stdio.Buffer packet_data,
+ ProtocolVersion version)
+ {
+ SSL3_DEBUG_MSG("client_key_exchange_packet(%O, %d.%d)\n",
+ packet_data, version>>8, version & 0xff);
+
+ SSL3_DEBUG_MSG("KE_KRB\n");
+
+ // FIXME: The second argument to InitContext is required,
+ // and should be host/MachineName@Realm.
+ gss_context = GSSAPI.InitContext();
+
+ string(8bit) token = gss_context->init();
+
+ Stdio.Buffer struct = Stdio.Buffer();
+
+ // NOTE: To protect against version roll-back attacks,
+ // the version sent here MUST be the same as the
+ // one in the initial handshake!
+ struct->add_int(client_version, 2);
+ struct->add(context->random(46));
+ string(8bit) premaster_secret = struct->read();
+
+ string(8bit) encrypted_premaster_secret =
+ gss_context->wrap(premaster_secret, 1);
+
+ packet_data->add_hstring(token, 2);
+ packet_data->add_hstring("", 2); // Authenticator.
+ packet_data->add_hstring(encrypted_premaster_secret, 2);
+ return premaster_secret;
+ }
+
+ //! @returns
+ //! Premaster secret or alert number.
+ string(0..255)|int got_client_key_exchange(Stdio.Buffer input,
+ ProtocolVersion version)
+ {
+ SSL3_DEBUG_MSG("got_client_key_exchange: ke_method %d\n",
+ session->ke_method);
+
+ SSL3_DEBUG_MSG("KE_KRB\n");
+
+ string ticket = input->read_hstring(2);
+ string authenticator = input->read_hstring(2);
+ string encrypted_premaster_secret = input->read_hstring(2);
+
+ gss_context = GSSAPI.AcceptContext();
+ gss_context->accept(ticket);
+
+ /* Decrypt the premaster_secret */
+ SSL3_DEBUG_MSG("encrypted premaster_secret: %O\n",
+ encrypted_premaster_secret);
+
+ string(8bit) premaster_secret =
+ gss_context->unwrap(encrypted_premaster_secret, 1);
+
+ SSL3_DEBUG_MSG("premaster_secret: %O\n", premaster_secret);
+
+ // We want both branches to execute in equal time (ignoring
+ // SSL3_DEBUG in the hope it is never on in production).
+ // Workaround documented in RFC 2246.
+ if ( `+( !premaster_secret,
+ (sizeof(premaster_secret) != 48),
+ (premaster_secret[0] != 3),
+ (premaster_secret[1] != (client_version & 0xff)) ))
+ {
+ /* To avoid the chosen ciphertext attack discovered by Daniel
+ * Bleichenbacher, it is essential not to send any error
+ * messages back to the client until after the client's
+ * Finished-message (or some other invalid message) has been
+ * received.
+ */
+ /* Also checks for version roll-back attacks.
+ */
+ #ifdef SSL3_DEBUG
+ werror("SSL.handshake: Invalid premaster_secret! "
+ "A chosen ciphertext attack?\n");
+ if (premaster_secret && sizeof(premaster_secret) > 2) {
+ werror("SSL.handshake: Strange version (%d.%d) detected in "
+ "key exchange message (expected %d.%d).\n",
+ premaster_secret[0], premaster_secret[1],
+ client_version>>8, client_version & 0xff);
+ }
#endif
-
+ premaster_secret = context->random(48);
+ message_was_bad = 1;
+ connection->ke = UNDEFINED;
+
+ } else {
+ string timing_attack_mitigation = context->random(48);
+ message_was_bad = 0;
+ connection->ke = this;
+ }
+
+ return premaster_secret;
+ }
+
+ Stdio.Buffer parse_server_key_exchange(Stdio.Buffer input)
+ {
+ SSL3_DEBUG_MSG("KE_KRB\n");
+ error("Invalid message.\n");
+ }
+ }
+ #endif /* GSSAPI */
+
//! MAC using SHA.
//!
//! @note
//! Note: This uses the algorithm from the SSL 3.0 draft.
class MACsha
{
inherit MACAlgorithm;
protected constant pad_1 = "6" * 40;
protected constant pad_2 = "\\" * 40;
protected Crypto.Hash algorithm = Crypto.SHA1;
protected string secret;
- //! The length of the header prefixed by @[hash()].
+
constant hash_header_size = 11;
- string(0..255) hash_raw(string(0..255) data)
+ string(8bit) hash_raw(string(8bit) data)
{
return algorithm->hash(data);
}
- //!
- string(0..255) hash(object packet, Gmp.mpz seq_num)
+ string(8bit) hash_packet(object packet, int seq_num, int|void adjust_len)
{
- string s = sprintf("%~8s%c%2c%s",
- "\0\0\0\0\0\0\0\0", seq_num->digits(256),
- packet->content_type, sizeof(packet->fragment),
- packet->fragment);
- return hash_raw(secret + pad_2 +
- hash_raw(secret + pad_1 + s));
+ string s = sprintf("%8c%c%2c", seq_num,
+ packet->content_type,
+ sizeof(packet->fragment) + adjust_len);
+ Crypto.Hash.State h = algorithm();
+ h->update(secret);
+ h->update(pad_1);
+ h->update(s);
+ h->update(packet->fragment);
+ return hash_raw(secret + pad_2 + h->digest());
}
- //!
- string(0..255) hash_master(string(0..255) data)
+ string(8bit) hash(string(8bit) data)
{
return hash_raw(secret + pad_2 +
hash_raw(data + secret + pad_1));
}
- //!
+ int(1..) block_size()
+ {
+ return algorithm->block_size();
+ }
+
protected void create (string|void s)
{
secret = s || "";
}
}
//! MAC using MD5.
//!
//! @note
//! Note: This uses the algorithm from the SSL 3.0 draft.
pike.git/lib/modules/SSL.pmod/Cipher.pmod:887:
protected Crypto.Hash algorithm = Crypto.MD5;
}
//! HMAC using SHA.
//!
//! This is the MAC algorithm used by TLS 1.0 and later.
class MAChmac_sha {
inherit MACAlgorithm;
- protected Crypto.Hash.HMAC hmac;
+ protected Crypto.Hash algorithm = Crypto.SHA1;
+ protected Crypto.MAC.State hmac;
- //! The length of the header prefixed by @[hash()].
+
constant hash_header_size = 13;
string hash_raw(string data)
{
-
+ return algorithm->hash(data);
+ }
+
+ string hash(string data)
+ {
return hmac(data);
}
- //!
- string hash(object packet, Gmp.mpz seq_num) {
-
- string s = sprintf("%~8s%c%c%c%2H",
- "\0\0\0\0\0\0\0\0", seq_num->digits(256),
+ string hash_packet(object packet, int seq_num, int|void adjust_len)
+ {
+ SSL3_DEBUG_CRYPT_MSG("HMAC header: %x\n",
+ sprintf("%8c%c%2c%2c", seq_num,
packet->content_type,
- packet->protocol_version[0],packet->protocol_version[1],
- packet->fragment);
+ packet->protocol_version,
+ sizeof(packet->fragment) +
+ adjust_len));
+ hmac->update( sprintf("%8c%c%2c%2c", seq_num,
+ packet->content_type,
+ packet->protocol_version,
+ sizeof(packet->fragment) + adjust_len));
+ SSL3_DEBUG_CRYPT_MSG("HMAC data: %x\n", packet->fragment);
+ hmac->update( packet->fragment );
+ return hmac->digest();
+ }
- return hmac(s);
+ int(1..) block_size()
+ {
+ return algorithm->block_size();
}
//!
protected void create(string|void s) {
- hmac = Crypto.SHA1.HMAC( s||"" );
+ hmac = algorithm->HMAC( s||"" );
}
}
//! HMAC using MD5.
//!
//! This is the MAC algorithm used by TLS 1.0 and later.
class MAChmac_md5 {
inherit MAChmac_sha;
-
- //!
- protected void create(string|void s) {
- hmac=Crypto.MD5.HMAC( s||"" );
+ protected Crypto.Hash algorithm = Crypto.MD5;
}
- }
+
//! HMAC using SHA256.
//!
//! This is the MAC algorithm used by some cipher suites in TLS 1.2 and later.
class MAChmac_sha256 {
inherit MAChmac_sha;
-
- //!
- protected void create(string|void s) {
- hmac=Crypto.SHA256.HMAC( s||"" );
+ protected Crypto.Hash algorithm = Crypto.SHA256;
}
- }
+
#if constant(Crypto.SHA384)
//! HMAC using SHA384.
//!
//! This is a MAC algorithm used by some cipher suites in TLS 1.2 and later.
class MAChmac_sha384 {
inherit MAChmac_sha;
-
- //!
- protected void create(string|void s) {
- hmac=Crypto.SHA384.HMAC( s||"" );
+ protected Crypto.Hash algorithm = Crypto.SHA384;
}
- }
+
#endif
#if constant(Crypto.SHA512)
//! HMAC using SHA512.
//!
//! This is a MAC algorithm used by some cipher suites in TLS 1.2 and later.
class MAChmac_sha512 {
inherit MAChmac_sha;
-
- //!
- protected void create(string|void s) {
- hmac=Crypto.SHA512.HMAC( s||"" );
+ protected Crypto.Hash algorithm = Crypto.SHA512;
}
- }
+
#endif
//! Hashfn is either a @[Crypto.MD5], @[Crypto.SHA] or @[Crypto.SHA256].
- protected string(0..255) P_hash(Crypto.Hash hashfn,
- string(0..255) secret,
- string(0..255) seed, int len) {
-
- Crypto.Hash.HMAC hmac=hashfn->HMAC(secret);
+ protected string(8bit) P_hash(Crypto.Hash hashfn,
+ string(8bit) secret,
+ string(8bit) seed, int len)
+ {
+ Crypto.MAC.State hmac=hashfn->HMAC(secret);
string temp=seed;
string res="";
while( sizeof(res)<len )
{
temp=hmac(temp);
res+=hmac(temp+seed);
}
return res[..(len-1)];
}
//! This Pseudo Random Function is used to derive secret keys in SSL 3.0.
//!
//! @note
//! The argument @[label] is ignored.
- string(0..255) prf_ssl_3_0(string(0..255) secret,
- string(0..255) label,
- string(0..255) seed,
+ string(8bit) prf_ssl_3_0(string(8bit) secret,
+ string(8bit) label,
+ string(8bit) seed,
int len)
{
string res = "";
for (int i = 1; sizeof(res) < len; i++) {
string cookie = (string)allocate(i, i + 64);
res += Crypto.MD5.hash(secret +
Crypto.SHA1.hash(cookie + secret + seed));
}
return res[..len-1];
}
//! This Pseudo Random Function is used to derive secret keys
//! in TLS 1.0 and 1.1.
- string(0..255) prf_tls_1_0(string(0..255) secret,
- string(0..255) label,
- string(0..255) seed,
+ string(8bit) prf_tls_1_0(string(8bit) secret,
+ string(8bit) label,
+ string(8bit) seed,
int len)
{
string s1=secret[..(int)(ceil(sizeof(secret)/2.0)-1)];
string s2=secret[(int)(floor(sizeof(secret)/2.0))..];
string a=P_hash(Crypto.MD5, s1, label+seed, len);
string b=P_hash(Crypto.SHA1, s2, label+seed, len);
return a ^ b;
}
//! This Pseudo Random Function is used to derive secret keys in TLS 1.2.
- string(0..255) prf_tls_1_2(string(0..255) secret,
- string(0..255) label,
- string(0..255) seed,
+ string(8bit) prf_tls_1_2(string(8bit) secret,
+ string(8bit) label,
+ string(8bit) seed,
int len)
{
return P_hash(Crypto.SHA256, secret, label + seed, len);
}
#if constant(Crypto.SHA384)
//! This Pseudo Random Function is used to derive secret keys
//! for some ciphers suites defined after TLS 1.2.
- string(0..255) prf_sha384(string(0..255) secret,
- string(0..255) label,
- string(0..255) seed,
+ string(8bit) prf_sha384(string(8bit) secret,
+ string(8bit) label,
+ string(8bit) seed,
int len)
{
return P_hash(Crypto.SHA384, secret, label + seed, len);
}
#endif
#if constant(Crypto.SHA512)
//! This Pseudo Random Function could be used to derive secret keys
//! for some ciphers suites defined after TLS 1.2.
- string(0..255) prf_sha512(string(0..255) secret,
- string(0..255) label,
- string(0..255) seed,
+ string(8bit) prf_sha512(string(8bit) secret,
+ string(8bit) label,
+ string(8bit) seed,
int len)
{
return P_hash(Crypto.SHA512, secret, label + seed, len);
}
#endif
//!
class DES
{
- inherit Crypto.CBC;
+ inherit Crypto.DES.CBC.Buffer.State;
- protected void create() { ::create(Crypto.DES()); }
-
+
this_program set_encrypt_key(string k)
{
- ::set_encrypt_key(Crypto.DES->fix_parity(k));
+ ::set_encrypt_key(Crypto.DES.fix_parity(k));
return this;
}
this_program set_decrypt_key(string k)
{
- ::set_decrypt_key(Crypto.DES->fix_parity(k));
+ ::set_decrypt_key(Crypto.DES.fix_parity(k));
return this;
}
}
//!
class DES3
{
- inherit Crypto.CBC;
+ inherit Crypto.DES3.CBC.Buffer.State;
- protected void create() {
- ::create(Crypto.DES3());
- }
-
+
this_program set_encrypt_key(string k)
{
- ::set_encrypt_key(Crypto.DES3->fix_parity(k));
+ ::set_encrypt_key(Crypto.DES3.fix_parity(k));
return this;
}
this_program set_decrypt_key(string k)
{
- ::set_decrypt_key(Crypto.DES3->fix_parity(k));
+ ::set_decrypt_key(Crypto.DES3.fix_parity(k));
return this;
}
}
-
+ #if constant(Crypto.Arctwo)
//!
class RC2
{
- inherit Crypto.CBC;
- protected void create() { ::create(Crypto.Arctwo()); }
+ inherit Crypto.Arctwo.CBC.Buffer.State;
this_program set_encrypt_key(string k)
{
::set_encrypt_key(k, 128);
return this;
}
this_program set_decrypt_key(string k)
{
::set_decrypt_key(k, 128);
return this;
}
}
-
+ #endif /* Crypto.Arctwo */
- //!
- class IDEA
- {
- inherit Crypto.CBC;
- protected void create() { ::create(Crypto.IDEA()); }
- }
-
- //!
- class AES
- {
- inherit Crypto.CBC;
- protected void create() { ::create(Crypto.AES()); }
- }
-
- #if constant(Crypto.Camellia)
- //!
- class Camellia
- {
- inherit Crypto.CBC;
- protected void create() { ::create(Crypto.Camellia()); }
- }
- #endif
-
- #if constant(Crypto.GCM)
- //!
- class AES_GCM
- {
- inherit Crypto.GCM.State;
- protected void create() { ::create(Crypto.AES()); }
- }
-
- #if constant(Crypto.Camellia)
- //!
- class Camellia_GCM
- {
- inherit Crypto.GCM.State;
- protected void create() { ::create(Crypto.Camellia()); }
- }
- #endif
- #endif
-
- //! Signing using RSA.
- ADT.struct rsa_sign(object context, string cookie, ADT.struct struct)
- {
- /* Exactly how is the signature process defined? */
-
- string params = cookie + struct->contents();
- string digest = Crypto.MD5->hash(params) + Crypto.SHA1->hash(params);
-
- object s = context->rsa->raw_sign(digest);
-
- struct->put_bignum(s);
- return struct;
- }
-
- //! Verify an RSA signature.
- int(0..1) rsa_verify(object context, string cookie, ADT.struct struct,
- ADT.struct input)
- {
- /* Exactly how is the signature process defined? */
-
- string params = cookie + struct->contents();
- string digest = Crypto.MD5->hash(params) + Crypto.SHA1->hash(params);
-
- Gmp.mpz signature = input->get_bignum();
-
- return context->rsa->raw_verify(digest, signature);
- }
-
- //! Signing using DSA.
- ADT.struct dsa_sign(object context, string cookie, ADT.struct struct)
- {
- /* NOTE: The details are not described in the SSL 3 spec. */
- string s = context->dsa->pkcs_sign(cookie + struct->contents(), Crypto.SHA1);
- struct->put_var_string(s, 2);
- return struct;
- }
-
- //! Verify a DSA signature.
- int(0..1) dsa_verify(object context, string cookie, ADT.struct struct,
- ADT.struct input)
- {
- /* NOTE: The details are not described in the SSL 3 spec. */
- return context->dsa->pkcs_verify(cookie + struct->contents(),
- Crypto.SHA1, input->get_var_string(2));
- }
-
- //! The NULL signing method.
- ADT.struct anon_sign(object context, string cookie, ADT.struct struct)
- {
- return struct;
- }
-
- //! The NULL verifier.
- int(0..1) anon_verify(object context, string cookie, ADT.struct struct,
- ADT.struct input)
- {
- return 1;
- }
-
- //! Diffie-Hellman parameters.
- class DHParameters
- {
- Gmp.mpz p, g, order;
- //!
-
- /* Default prime and generator, taken from the ssh2 spec:
- *
- * "This group was taken from the ISAKMP/Oakley specification, and was
- * originally generated by Richard Schroeppel at the University of Arizona.
- * Properties of this prime are described in [Orm96].
- *...
- * [Orm96] Orman, H., "The Oakley Key Determination Protocol", version 1,
- * TR97-92, Department of Computer Science Technical Report, University of
- * Arizona."
- */
-
- /* p = 2^1024 - 2^960 - 1 + 2^64 * floor( 2^894 Pi + 129093 ) */
-
- protected Gmp.mpz orm96() {
- p = Gmp.mpz("FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1"
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD"
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245"
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED"
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381"
- "FFFFFFFF FFFFFFFF", 16);
- order = (p-1) / 2;
-
- g = Gmp.mpz(2);
-
- return this;
- }
-
- //!
- protected void create(object ... args) {
- switch (sizeof(args))
- {
- case 0:
- orm96();
- break;
- case 3:
- [p, g, order] = args;
- break;
- default:
- error( "Wrong number of arguments.\n" );
- }
- }
- }
-
- //! Implements Diffie-Hellman key-exchange.
- //!
- //! The following key exchange methods are implemented here:
- //! @[KE_dhe_dss], @[KE_dhe_rsa] and @[KE_dh_anon].
- class DHKeyExchange
- {
- /* Public parameters */
- DHParameters parameters;
-
- Gmp.mpz our; /* Our value */
- Gmp.mpz other; /* Other party's value */
- Gmp.mpz secret; /* our = g ^ secret mod p */
-
- //!
- protected void create(DHParameters p) {
- parameters = p;
- }
-
- this_program new_secret(function random)
- {
- secret = Gmp.mpz(random( (parameters->order->size() + 10 / 8)), 256)
- % (parameters->order - 1) + 1;
-
- our = parameters->g->powm(secret, parameters->p);
- return this;
- }
-
- this_program set_other(Gmp.mpz o) {
- other = o;
- return this;
- }
-
- Gmp.mpz get_shared() {
- return other->powm(secret, parameters->p);
- }
- }
-
+
//! Lookup the crypto parameters for a cipher suite.
//!
//! @param suite
//! Cipher suite to lookup.
//!
//! @param version
- //! Minor version of the SSL protocol to support.
+ //! Version of the SSL/TLS protocol to support.
//!
//! @param signature_algorithms
//! The set of <hash, signature> combinations that
//! are supported by the other end.
//!
//! @param max_hash_size
//! The maximum hash size supported for the signature algorithm.
//!
//! @returns
- //! Returns @expr{0@} (zero) for unsupported combinations.
- //! Otherwise returns an array with the following fields:
- //! @array
- //! @elem KeyExchangeType 0
- //! Key exchange method.
- //! @elem CipherSpec 1
- //! Initialized @[CipherSpec] for the @[suite].
- //! @endarray
- array lookup(int suite, ProtocolVersion|int version,
+ //! Returns @expr{0@} (zero) for unsupported combinations, otherwise
+ //! returns an initialized @[CipherSpec] for the @[suite].
+ CipherSpec lookup(int suite, ProtocolVersion|int version,
array(array(int)) signature_algorithms,
int max_hash_size)
{
CipherSpec res = CipherSpec();
- int ke_method;
+
array algorithms = CIPHER_SUITES[suite];
if (!algorithms)
return 0;
- ke_method = algorithms[0];
+ int ke_method = algorithms[0];
- if (version < PROTOCOL_TLS_1_2) {
- switch(ke_method)
- {
- case KE_rsa:
- case KE_dhe_rsa:
- case KE_ecdh_rsa:
- case KE_ecdhe_rsa:
- res->sign = rsa_sign;
- res->verify = rsa_verify;
- break;
- case KE_dhe_dss:
- res->sign = dsa_sign;
- res->verify = dsa_verify;
- break;
- case KE_null:
- case KE_dh_anon:
- case KE_ecdh_anon:
- res->sign = anon_sign;
- res->verify = anon_verify;
- break;
- case KE_ecdh_ecdsa:
- case KE_ecdhe_ecdsa:
- // FIXME: Not implemented yet.
- default:
- error( "Internal error.\n" );
- }
- } else {
- int sign_id;
- switch(ke_method) {
- case KE_rsa:
- case KE_dhe_rsa:
- case KE_ecdh_rsa:
- case KE_ecdhe_rsa:
- sign_id = SIGNATURE_rsa;
- break;
- case KE_dhe_dss:
- sign_id = SIGNATURE_dsa;
- break;
- case KE_ecdh_ecdsa:
- case KE_ecdhe_ecdsa:
- sign_id = SIGNATURE_ecdsa;
- break;
- case KE_null:
- case KE_dh_anon:
- case KE_ecdh_anon:
- sign_id = SIGNATURE_anonymous;
- break;
- default:
- error( "Internal error.\n" );
- }
-
- // Select a suitable hash.
- //
- // Fortunately the hash identifiers have a nice order property.
- int hash_id = HASH_sha;
- SSL3_DEBUG_MSG("Signature algorithms: %O, max: %d\n",
- signature_algorithms, max_hash_size);
- foreach(signature_algorithms || ({}), array(int) pair) {
- if ((pair[1] == sign_id) && (pair[0] > hash_id) &&
- HASH_lookup[pair[0]]) {
- if (max_hash_size < HASH_lookup[pair[0]]->digest_size()) {
- // Eg RSA has a maximum block size and the digest is too large.
- continue;
- }
- hash_id = pair[0];
- }
- }
- SSL3_DEBUG_MSG("Selected <Hash: %d, Signature: %d>\n", hash_id, sign_id);
- TLSSigner signer = TLSSigner(hash_id);
- res->verify = signer->verify;
-
- switch(sign_id)
- {
- case SIGNATURE_rsa:
- res->sign = signer->rsa_sign;
- break;
- case SIGNATURE_dsa:
- res->sign = signer->dsa_sign;
- break;
- case SIGNATURE_anonymous:
- res->sign = anon_sign;
- res->verify = anon_verify;
- break;
- case SIGNATURE_ecdsa:
- // FIXME: Not implemented yet.
- default:
- error( "Internal error.\n" );
- }
- }
-
+
switch(algorithms[1])
{
-
+ #if constant(Crypto.Arctwo)
case CIPHER_rc2_40:
res->bulk_cipher_algorithm = RC2;
res->cipher_type = CIPHER_block;
res->is_exportable = 1;
res->key_material = 16;
res->iv_size = 8;
res->key_bits = 40;
break;
-
+ #endif
case CIPHER_rc4_40:
res->bulk_cipher_algorithm = Crypto.Arcfour.State;
res->cipher_type = CIPHER_stream;
res->is_exportable = 1;
res->key_material = 16;
res->iv_size = 0;
res->key_bits = 40;
break;
case CIPHER_des40:
res->bulk_cipher_algorithm = DES;
pike.git/lib/modules/SSL.pmod/Cipher.pmod:1483:
res->key_bits = 56;
break;
case CIPHER_3des:
res->bulk_cipher_algorithm = DES3;
res->cipher_type = CIPHER_block;
res->is_exportable = 0;
res->key_material = 24;
res->iv_size = 8;
res->key_bits = 168;
break;
+ #if constant(Crypto.IDEA)
case CIPHER_idea:
- res->bulk_cipher_algorithm = IDEA;
+ res->bulk_cipher_algorithm = Crypto.IDEA.CBC.Buffer.State;
res->cipher_type = CIPHER_block;
res->is_exportable = 0;
res->key_material = 16;
res->iv_size = 8;
res->key_bits = 128;
break;
-
+ #endif
case CIPHER_aes:
- res->bulk_cipher_algorithm = AES;
+ res->bulk_cipher_algorithm = Crypto.AES.CBC.Buffer.State;
res->cipher_type = CIPHER_block;
res->is_exportable = 0;
res->key_material = 16;
res->iv_size = 16;
res->key_bits = 128;
break;
case CIPHER_aes256:
- res->bulk_cipher_algorithm = AES;
+ res->bulk_cipher_algorithm = Crypto.AES.CBC.Buffer.State;
res->cipher_type = CIPHER_block;
res->is_exportable = 0;
res->key_material = 32;
res->iv_size = 16;
res->key_bits = 256;
break;
#if constant(Crypto.Camellia)
case CIPHER_camellia128:
- res->bulk_cipher_algorithm = Camellia;
+ res->bulk_cipher_algorithm = Crypto.Camellia.CBC.Buffer.State;
res->cipher_type = CIPHER_block;
res->is_exportable = 0;
res->key_material = 16;
res->iv_size = 16;
res->key_bits = 128;
break;
case CIPHER_camellia256:
- res->bulk_cipher_algorithm = Camellia;
+ res->bulk_cipher_algorithm = Crypto.Camellia.CBC.Buffer.State;
res->cipher_type = CIPHER_block;
res->is_exportable = 0;
res->key_material = 32;
res->iv_size = 16;
res->key_bits = 256;
break;
#endif
-
+ #if constant(Crypto.ChaCha20.POLY1305)
+ case CIPHER_chacha20:
+ if ((sizeof(algorithms) <= 3) || (algorithms[3] != MODE_poly1305)) {
+ // Unsupported.
+ return 0;
+ }
+ res->bulk_cipher_algorithm = Crypto.ChaCha20.POLY1305.State;
+ res->cipher_type = CIPHER_aead;
+ res->is_exportable = 0;
+ res->key_material = 32;
+ res->key_bits = 256;
+ res->iv_size = 0; // Length of the salt.
+ res->explicit_iv_size = 0; // Length of the explicit nonce/iv.
+ res->hash_size = 0; // No need for MAC keys.
+ res->mac_algorithm = 0; // MACs are not used with AEAD.
+
+ break;
+ #endif
default:
return 0;
}
switch(algorithms[2])
{
#if constant(Crypto.SHA512)
case HASH_sha512:
res->mac_algorithm = MAChmac_sha512;
res->hash_size = 64;
pike.git/lib/modules/SSL.pmod/Cipher.pmod:1547: Inside #if constant(Crypto.SHA384)
#if constant(Crypto.SHA384)
case HASH_sha384:
res->mac_algorithm = MAChmac_sha384;
res->hash_size = 48;
break;
#endif
case HASH_sha256:
res->mac_algorithm = MAChmac_sha256;
res->hash_size = 32;
break;
- case HASH_sha:
+ case HASH_sha1:
if(version >= PROTOCOL_TLS_1_0)
res->mac_algorithm = MAChmac_sha;
else
res->mac_algorithm = MACsha;
res->hash_size = 20;
break;
case HASH_md5:
if(version >= PROTOCOL_TLS_1_0)
res->mac_algorithm = MAChmac_md5;
else
pike.git/lib/modules/SSL.pmod/Cipher.pmod:1569:
res->hash_size = 16;
break;
case 0:
res->mac_algorithm = 0;
res->hash_size = 0;
break;
default:
return 0;
}
- if (version == PROTOCOL_SSL_3_0) {
+ if ((version == PROTOCOL_SSL_3_0) && (ke_method != KE_rsa_fips)) {
res->prf = prf_ssl_3_0;
} else if (version <= PROTOCOL_TLS_1_1) {
res->prf = prf_tls_1_0;
} else {
// The PRF is really part of the cipher suite in TLS 1.2.
//
// In all existing post TLS 1.2 cases the hash for the prf is the same
// as the hash for the suite.
switch(algorithms[2]) {
case HASH_none:
break;
case HASH_md5:
- case HASH_sha:
+ case HASH_sha1:
case HASH_sha224:
// These old suites are all upgraded to using SHA256.
case HASH_sha256:
res->prf = prf_tls_1_2;
res->hash = Crypto.SHA256;
break;
#if constant(Crypto.SHA384)
case HASH_sha384:
res->prf = prf_sha384;
res->hash = Crypto.SHA384;
pike.git/lib/modules/SSL.pmod/Cipher.pmod:1610:
#endif
default:
return 0;
}
}
if (sizeof(algorithms) > 3) {
switch(algorithms[3]) {
case MODE_cbc:
break;
- #if constant(Crypto.GCM)
+ case MODE_ccm:
+ if (res->bulk_cipher_algorithm == Crypto.AES.CBC.Buffer.State) {
+ res->bulk_cipher_algorithm = Crypto.AES.CCM.State;
+ } else {
+ // Unsupported.
+ return 0;
+ }
+ res->cipher_type = CIPHER_aead;
+ res->iv_size = 4; // Length of the salt.
+ res->explicit_iv_size = 8; // Length of the explicit nonce/iv.
+ res->hash_size = 0; // No need for MAC keys.
+ res->mac_algorithm = 0; // MACs are not used with AEAD.
+
+ break;
+ case MODE_ccm_8:
+ if (res->bulk_cipher_algorithm == Crypto.AES.CBC.Buffer.State) {
+ res->bulk_cipher_algorithm = Crypto.AES.CCM8.State;
+ } else {
+ // Unsupported.
+ return 0;
+ }
+ res->cipher_type = CIPHER_aead;
+ res->iv_size = 4; // Length of the salt.
+ res->explicit_iv_size = 8; // Length of the explicit nonce/iv.
+ res->hash_size = 0; // No need for MAC keys.
+ res->mac_algorithm = 0; // MACs are not used with AEAD.
+
+ break;
+ #if constant(Crypto.AES.GCM)
case MODE_gcm:
- if (res->bulk_cipher_algorithm == AES) {
- res->bulk_cipher_algorithm = AES_GCM;
- #if constant(Crypto.Camellia)
- } else if (res->bulk_cipher_algorithm == Camellia) {
- res->bulk_cipher_algorithm = Camellia_GCM;
+ if (res->bulk_cipher_algorithm == Crypto.AES.CBC.Buffer.State) {
+ res->bulk_cipher_algorithm = Crypto.AES.GCM.State;
+ #if constant(Crypto.Camellia.GCM)
+ } else if (res->bulk_cipher_algorithm ==
+ Crypto.Camellia.CBC.Buffer.State) {
+ res->bulk_cipher_algorithm = Crypto.Camellia.GCM.State;
#endif
} else {
// Unsupported.
return 0;
}
res->cipher_type = CIPHER_aead;
res->iv_size = 4; // Length of the salt.
res->explicit_iv_size = 8; // Length of the explicit nonce/iv.
res->hash_size = 0; // No need for MAC keys.
res->mac_algorithm = 0; // MACs are not used with AEAD.
break;
#endif
-
+ #if constant(Crypto.ChaCha20.POLY1305)
+ case MODE_poly1305:
+ res->mac_algorithm = 0; // MACs are not used with AEAD.
+ res->hash_size = 0;
+ break;
+ #endif
default:
return 0;
}
}
- if (res->is_exportable && (version >= PROTOCOL_TLS_1_1)) {
+ if (version >= PROTOCOL_TLS_1_3) {
+ // NB: Only DHE and ECDHE are supported in TLS 1.3 and later.
+ switch(ke_method) {
+ case KE_dh_anon:
+ case KE_dhe_rsa:
+ case KE_dhe_dss:
+ res->ke_factory = KeyShareDHE;
+ break;
+ #if constant(Crypto.ECC.Curve)
+ case KE_ecdhe_rsa:
+ case KE_ecdhe_ecdsa:
+ case KE_ecdh_anon:
+ res->ke_factory = KeyShareECDHE;
+ break;
+ #endif
+ default:
+ werror( "%s: Unsupported KE: %s\n",
+ fmt_version(version),
+ fmt_constant(ke_method, "KE") );
+ return 0;
+ }
+ } else {
+ switch(ke_method)
+ {
+ case KE_null:
+ res->ke_factory = KeyExchangeNULL;
+ break;
+ case KE_rsa:
+ case KE_rsa_fips:
+ res->ke_factory = KeyExchangeRSA;
+ break;
+ case KE_rsa_export:
+ res->ke_factory = KeyExchangeExportRSA;
+ break;
+ case KE_dh_dss:
+ case KE_dh_rsa:
+ res->ke_factory = KeyExchangeDH;
+ break;
+ case KE_dh_anon:
+ case KE_dhe_rsa:
+ case KE_dhe_dss:
+ res->ke_factory = KeyExchangeDHE;
+ break;
+ #if constant(Crypto.ECC.Curve)
+ case KE_ecdhe_rsa:
+ case KE_ecdhe_ecdsa:
+ case KE_ecdh_anon:
+ res->ke_factory = KeyExchangeECDHE;
+ break;
+ case KE_ecdh_rsa:
+ case KE_ecdh_ecdsa:
+ res->ke_factory = KeyExchangeECDH;
+ break;
+ case KE_ecdhe_psk:
+ res->ke_factory = KeyExchangeECDHEPSK;
+ break;
+ #endif
+ case KE_psk:
+ res->ke_factory = KeyExchangePSK;
+ break;
+ case KE_dhe_psk:
+ res->ke_factory = KeyExchangeDHEPSK;
+ break;
+ case KE_rsa_psk:
+ res->ke_factory = KeyExchangeRSAPSK;
+ break;
+ default:
+ error( "Internal error.\n" );
+ }
+ }
+
+ switch(ke_method)
+ {
+ case KE_rsa:
+ case KE_rsa_export:
+ case KE_rsa_fips:
+ case KE_dhe_rsa:
+ case KE_ecdhe_rsa:
+ case KE_rsa_psk:
+ res->signature_alg = SIGNATURE_rsa;
+ break;
+ case KE_dh_rsa:
+ case KE_dh_dss:
+ case KE_dhe_dss:
+ res->signature_alg = SIGNATURE_dsa;
+ break;
+ case KE_null:
+ case KE_dh_anon:
+ case KE_ecdh_anon:
+ case KE_psk:
+ case KE_dhe_psk:
+ #if constant(Crypto.ECC.Curve)
+ case KE_ecdhe_psk:
+ #endif
+ res->signature_alg = SIGNATURE_anonymous;
+ break;
+ #if constant(Crypto.ECC.Curve)
+ case KE_ecdh_rsa:
+ case KE_ecdh_ecdsa:
+ case KE_ecdhe_ecdsa:
+ // FIXME: SIGNATURE_ecdsa used for KE_ecdh_rsa. Naming issue?
+ res->signature_alg = SIGNATURE_ecdsa;
+ break;
+ #endif
+ default:
+ error( "Internal error.\n" );
+ }
+
+ if (version >= PROTOCOL_TLS_1_2)
+ {
+ res->set_hash(max_hash_size, signature_algorithms);
+ }
+
+ if (res->is_exportable && res->bulk_cipher_algorithm &&
+ (version >= PROTOCOL_TLS_1_1)) {
// RFC 4346 A.5:
// TLS 1.1 implementations MUST NOT negotiate
// these cipher suites in TLS 1.1 mode.
SSL3_DEBUG_MSG("Suite not supported in TLS 1.1 and later.\n");
return 0;
}
- if (version >= PROTOCOL_TLS_1_2) {
- if ((res->bulk_cipher_algorithm == DES) ||
- (res->bulk_cipher_algorithm == IDEA)) {
+ if (version >= PROTOCOL_TLS_1_3) {
+ if (res->cipher_type != CIPHER_aead) {
+ // TLS1.3 6.1 RecordProtAlgorithm
+ SSL3_DEBUG_MSG("Suite not supported in TLS 1.3 and later.\n");
+ return 0;
+ }
+ }
+ else if (version == PROTOCOL_TLS_1_2) {
+ if (res->bulk_cipher_algorithm == DES) {
// RFC 5246 1.2:
// Removed IDEA and DES cipher suites. They are now deprecated and
// will be documented in a separate document.
SSL3_DEBUG_MSG("Suite not supported in TLS 1.2 and later.\n");
return 0;
}
-
+ #if constant(Crypto.IDEA.CBC)
+ if (res->bulk_cipher_algorithm == Crypto.IDEA.CBC.Buffer.State) {
+ // RFC 5246 1.2:
+ // Removed IDEA and DES cipher suites. They are now deprecated and
+ // will be documented in a separate document.
+ SSL3_DEBUG_MSG("Suite not supported in TLS 1.2 and later.\n");
+ return 0;
+ }
+ #endif
} else if (res->cipher_type == CIPHER_aead) {
// RFC 5822 4:
// These cipher suites make use of the authenticated encryption
// with additional data defined in TLS 1.2 [RFC5246]. They MUST
// NOT be negotiated in older versions of TLS.
SSL3_DEBUG_MSG("Suite not supported prior to TLS 1.2.\n");
return 0;
}
- return ({ ke_method, res });
+ // Calculate a safe value for max_bytes.
+ switch(res->cipher_type) {
+ case CIPHER_block:
+ /* CBC requires the keys to change well before 2^(block_size/2) blocks
+ * have been sent (block_size in bits). cf https://sweet32.info/
+ */
+ object(Crypto.BlockCipher) alg =
+ function_object(res->bulk_cipher_algorithm);
+ if (!alg) {
+ // Special case for the algorithms defined in this file.
+ alg = ([
+ DES: Crypto.DES,
+ DES3: Crypto.DES,
+ #if constant(Crypto.Arctwo)
+ RC2: Crypto.Arctwo,
+ #endif
+ ])[res->bulk_cipher_algorithm];
+ if (!alg) {
+ error("Failed to determine algorithm for %O\n",
+ res->bulk_cipher_algorithm);
}
-
+ }
+ int block_size = alg->block_size();
+ /* The strict limit is thus block_size << block_size * 4 (block_size in bytes).
+ * We want some safety margin and multiply the exponent with 3 instead of 4.
+ */
+ res->max_bytes = block_size << block_size*3;
+ break;
+ case CIPHER_stream:
+ /* Currently RC4 is the only stream cipher.
+ * We set the rekey threshold to the same as for DES/DES3.
+ */
+ res->max_bytes = 0x08000000;
+ break;
+ case CIPHER_aead:
+ // All the AEAD modes should handle 2GB without any problem.
+ res->max_bytes = 0x7fffffff;
+ break;
+ }
+ if (res->is_exportable) res->max_bytes >>= 4;
+ if (res->max_bytes > 0x7fffffff) res->max_bytes = 0x7fffffff;
- #else // constant(Crypto.Hash)
- constant this_program_does_not_exist = 1;
- #endif
+ return res;
+ }