#pike __REAL_VERSION__ |
#pragma strict_types |
#require constant(Crypto.Hash) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "tls.h" |
|
import "."; |
import Constants; |
|
protected void create() |
{ |
SSL3_DEBUG_MSG("SSL.Context->create\n"); |
|
|
multiset(int) blocked = (< CIPHER_rc4 >); |
preferred_suites = get_suites(128, 1, blocked); |
} |
|
|
|
array(ProtocolVersion) supported_versions = ({ |
PROTOCOL_TLS_1_2, |
PROTOCOL_TLS_1_1, |
PROTOCOL_TLS_1_0, |
}); |
|
|
|
array(ProtocolVersion) get_versions(ProtocolVersion client) |
{ |
|
int pos = search(supported_versions, client); |
if(pos!=-1) return supported_versions[pos..]; |
|
|
|
int high = max(@supported_versions); |
if( client==PROTOCOL_TLS_1_2 && high > PROTOCOL_TLS_1_2 ) |
return ({ PROTOCOL_IN_EXTENSION }); |
|
|
return filter(supported_versions, lambda(ProtocolVersion v) |
{ |
return v<client; |
}); |
} |
|
|
|
array(string(8bit)) advertised_protocols; |
|
|
|
|
|
mapping(Standards.ASN1.Types.Identifier:Crypto.Hash) verifier_algorithms |
= filter(Standards.X509.get_algorithms(), |
lambda(object o) { |
return !(< |
#if constant(Crypto.MD2) |
Crypto.MD2, |
#endif |
Crypto.MD5, |
Crypto.SHA1 |
>)[o]; |
}); |
|
|
|
int packet_max_size = PACKET_MAX_SIZE; |
|
|
|
|
|
array(int) preferred_compressors = ({ COMPRESSION_null }); |
|
|
|
|
|
|
|
|
int(0..1) enable_renegotiation = 1; |
|
|
|
|
|
int(0..1) heartbleed_probe = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Alert alert_factory(object con, |
int(1..2) level, int(8bit) description, |
ProtocolVersion version, string|void message) |
{ |
return Alert(level, description, version, message); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
multiset(int) extensions = (< |
EXTENSION_renegotiation_info, |
EXTENSION_max_fragment_length, |
EXTENSION_ec_point_formats, |
EXTENSION_encrypt_then_mac, |
EXTENSION_application_layer_protocol_negotiation, |
EXTENSION_signature_algorithms, |
EXTENSION_elliptic_curves, |
EXTENSION_server_name, |
EXTENSION_session_ticket, |
EXTENSION_next_protocol_negotiation, |
EXTENSION_signed_certificate_timestamp, |
EXTENSION_early_data, |
EXTENSION_padding, |
>); |
|
|
|
|
|
|
|
|
|
function(int(0..):string(8bit)) random = random_string; |
|
|
|
|
|
array(int) preferred_suites; |
|
|
|
|
array(int) ecc_curves = reverse(sort(indices(ECC_CURVES))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
array(int) ffdhe_groups = sort(indices(FFDHE_GROUPS)); |
|
|
|
|
|
|
|
|
|
|
mapping(int(508..511):Crypto.DH.Parameters) private_ffdhe_groups = ([]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
array(int) signature_algorithms = ({ |
#if constant(Crypto.SHA512) |
#if constant(Crypto.ECC.Curve) |
SIGNATURE_ecdsa_secp521r1_sha512, |
#endif |
SIGNATURE_rsa_pkcs1_sha512, |
#endif |
#if constant(Crypto.SHA384) |
#if constant(Crypto.ECC.Curve) |
SIGNATURE_ecdsa_secp384r1_sha384, |
#endif |
SIGNATURE_rsa_pkcs1_sha384, |
#endif |
#if constant(Crypto.ECC.Curve25519) |
SIGNATURE_ed25519_intrinsic, |
#endif |
#if constant(Crypto.ECC.Curve) |
SIGNATURE_ecdsa_secp256r1_sha256, |
#endif |
HASH_sha256 | SIGNATURE_dsa, |
SIGNATURE_rsa_pkcs1_sha256, |
#if constant(Crypto.SHA224) |
#if constant(Crypto.ECC.Curve) |
HASH_sha224 | SIGNATURE_ecdsa, |
#endif |
HASH_sha224 | SIGNATURE_dsa, |
#endif |
#if constant(Crypto.ECC.Curve) |
HASH_sha1 | SIGNATURE_ecdsa, |
#endif |
HASH_sha1 | SIGNATURE_dsa, |
SIGNATURE_rsa_pkcs1_sha1, |
}); |
|
|
|
|
|
array(int) get_signature_algorithms(array(int)|void signature_algorithms) |
{ |
if (!signature_algorithms) { |
signature_algorithms = this_program::signature_algorithms; |
} |
|
#if constant(Crypto.ECC.Curve) && constant(Crypto.SHA512) && \ |
constant(Crypto.SHA384) && constant(Crypto.SHA224) && \ |
constant(Crypto.ECC.Curve25519) |
return signature_algorithms; |
#else |
return [array(int)] |
filter(signature_algorithms, |
lambda(SignatureScheme scheme) { |
#if !constant(Crypto.ECC.Curve) |
if ((scheme & SIGNATURE_MASK) == SIGNATURE_ecdsa) return 0; |
#endif |
if ((< |
#if constant(Crypto.ECC.Curve25519) |
SIGNATURE_ed25519_intrinsic, |
#endif |
>)[scheme]) return 1; |
if ((< |
#if !constant(Crypto.SHA512) |
HASH_sha512, |
#endif |
#if !constant(Crypto.SHA384) |
HASH_sha384, |
#endif |
#if !constant(Crypto.SHA224) |
HASH_sha224, |
#endif |
HASH_intrinsic, |
>)[scheme & HASH_MASK]) return 0; |
return 1; |
}); |
#endif |
} |
|
|
|
|
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]]; |
|
|
|
int hash = info[2] >> 8; |
|
|
if (sizeof(info) > 3) { |
hash |= info[3]<<5; |
if (info[3] == MODE_cbc) { |
|
keylength >>= 1; |
} |
} else { |
|
|
|
keylength >>= 1; |
} |
|
|
int cipher = info[1]; |
|
|
int ke_prio = ([ |
KE_null: 0, |
KE_dh_anon: 1, |
KE_ecdh_anon: 2, |
KE_fortezza: 3, |
KE_dms: 4, |
KE_rsa_export: 5, |
KE_dh_rsa: 6, |
KE_dh_dss: 7, |
KE_rsa: 8, |
KE_rsa_fips: 9, |
KE_ecdh_rsa: 10, |
KE_ecdh_ecdsa: 11, |
KE_dhe_rsa: 12, |
KE_dhe_dss: 13, |
KE_ecdhe_rsa: 14, |
KE_ecdhe_ecdsa: 15, |
])[info[0]]; |
|
int auth_prio = keylength && ([ |
KE_null: 0, |
KE_dh_anon: 0, |
KE_ecdh_anon: 0, |
KE_fortezza: 1, |
KE_dms: 2, |
KE_rsa_export: 4, |
KE_rsa: 8, |
KE_rsa_fips: 8, |
KE_dhe_rsa: 8, |
KE_ecdhe_rsa: 8, |
KE_dh_dss: 8, |
KE_dh_rsa: 8, |
KE_dhe_dss: 8, |
KE_ecdh_rsa: 8, |
KE_ecdh_ecdsa: 8, |
KE_ecdhe_ecdsa: 8, |
])[info[0]]; |
|
|
|
|
|
|
|
|
|
|
|
return cipher | hash << 8 | ke_prio << 16 | keylength << 24 | auth_prio << 36; |
} |
|
|
|
|
|
|
|
|
|
|
array(int) sort_suites(array(int) suites) |
{ |
sort(map(suites, cipher_suite_sort_key), suites); |
return reverse(suites); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
array(int) get_suites(int(-1..)|void min_keylength, |
int(0..2)|void ke_mode, |
multiset(int)|void blacklisted_ciphers, |
multiset(KeyExchangeType)|void blacklisted_kes, |
multiset(HashAlgorithm)|void blacklisted_hashes, |
multiset(CipherModes)|void blacklisted_ciphermodes) |
{ |
if (!min_keylength) min_keylength = 128; |
|
|
multiset(int) kes = (< |
KE_dhe_rsa, KE_dhe_dss, |
KE_ecdhe_rsa, KE_ecdhe_ecdsa, |
>); |
|
if (ke_mode) { |
|
kes |= (< |
KE_rsa, KE_rsa_export, KE_rsa_fips, |
KE_dh_rsa, KE_dh_dss, |
#if constant(Crypto.ECC.Curve) |
KE_ecdh_rsa, |
KE_ecdh_ecdsa, |
#endif |
>); |
if (ke_mode == 2) { |
|
kes |= (< KE_null, KE_dh_anon, |
#if constant(Crypto.ECC.Curve) |
KE_ecdh_anon, |
#endif |
>); |
} |
} |
|
#if constant(Crypto.ECC.Curve) |
if (!sizeof(ecc_curves)) { |
|
kes -= (< |
KE_ecdhe_rsa, KE_ecdhe_ecdsa, |
KE_ecdh_rsa, KE_ecdh_ecdsa, |
KE_ecdh_anon, |
>); |
} |
#endif |
|
if (blacklisted_kes) { |
kes -= blacklisted_kes; |
} |
|
|
array(int) res = |
filter(indices(CIPHER_SUITES), |
lambda(int suite) { |
return kes[CIPHER_SUITES[suite][0]]; |
}); |
|
|
if (min_keylength > 0) { |
res = filter(res, |
lambda(int suite, int min_keylength) { |
return min_keylength <= |
CIPHER_effective_keylengths[CIPHER_SUITES[suite][1]]; |
}, min_keylength); |
} |
|
if( !blacklisted_ciphers || (max_version >= PROTOCOL_TLS_1_3)) |
{ |
|
|
|
|
|
|
if (!blacklisted_ciphers) blacklisted_ciphers = (<>); |
blacklisted_ciphers |= (< CIPHER_rc4, CIPHER_des, CIPHER_rc4_40, |
CIPHER_rc2_40, CIPHER_des40 >); |
} |
if( sizeof(blacklisted_ciphers) ) |
res = filter(res, |
lambda(int suite, multiset(int) blacklisted_hashes) { |
return !blacklisted_hashes[CIPHER_SUITES[suite][1]]; |
}, blacklisted_ciphers); |
|
#if !constant(Crypto.SHA384) |
|
if (!blacklisted_hashes) |
blacklisted_hashes = (< HASH_sha384 >); |
else |
blacklisted_hashes[HASH_sha384] = 1; |
#endif |
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); |
} |
|
switch(min(@supported_versions)) { |
case PROTOCOL_TLS_1_3: |
res = filter(res, |
lambda(int suite) { |
array(int) info = [array(int)]CIPHER_SUITES[suite]; |
|
if (sizeof(info) < 4) return 0; |
if (info[3] == MODE_cbc) return 0; |
return 1; |
}); |
break; |
case PROTOCOL_TLS_1_2: |
res = filter(res, |
lambda(int suite) { |
array(int) info = [array(int)]CIPHER_SUITES[suite]; |
switch(info[1]) { |
|
case 0: |
case CIPHER_rc2_40: |
case CIPHER_rc4_40: |
case CIPHER_des40: |
|
case CIPHER_idea: |
case CIPHER_des: |
return 0; |
} |
return 1; |
}); |
break; |
case PROTOCOL_TLS_1_1: |
res = filter(res, |
lambda(int suite) { |
array(int) info = [array(int)]CIPHER_SUITES[suite]; |
|
switch(info[1]) { |
case 0: |
case CIPHER_rc2_40: |
case CIPHER_rc4_40: |
case CIPHER_des40: |
return 0; |
} |
return 1; |
}); |
break; |
} |
|
switch(max(@supported_versions)) { |
case PROTOCOL_TLS_1_1: |
case PROTOCOL_TLS_1_0: |
case PROTOCOL_SSL_3_0: |
res = filter(res, |
lambda(int suite) { |
array(int) info = [array(int)]CIPHER_SUITES[suite]; |
|
|
|
|
return (sizeof(info) < 4) && (info[2] <= HASH_sha1); |
}); |
break; |
} |
|
return sort_suites(res); |
} |
|
|
|
void filter_weak_suites(int min_keylength) |
{ |
if (!preferred_suites || !min_keylength) return; |
preferred_suites = |
filter(preferred_suites, |
lambda(int suite) { |
array(int) def = [array(int)]CIPHER_SUITES[suite]; |
return def && |
(CIPHER_effective_keylengths[def[1]] >= min_keylength); |
}); |
} |
|
#if constant(Crypto.ECC.Curve) && constant(Crypto.AES.GCM) && constant(Crypto.SHA384) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void configure_suite_b(int(128..)|void min_keylength, |
int(0..)|void strictness_level) |
{ |
if( !min_keylength ) min_keylength = 256; |
if (min_keylength!=256) |
error("Only keylength 256 supported.\n"); |
|
preferred_suites = ({ |
TLS_ecdhe_ecdsa_with_aes_256_gcm_sha384, |
}); |
|
supported_versions = ({ PROTOCOL_TLS_1_2 }); |
|
if (strictness_level < 2) { |
|
|
|
supported_versions = ({ |
PROTOCOL_TLS_1_2, |
PROTOCOL_TLS_1_1, |
PROTOCOL_TLS_1_0, |
}); |
|
|
preferred_suites += ({ |
TLS_ecdhe_ecdsa_with_aes_256_cbc_sha, |
}); |
|
if (strictness_level < 1) { |
|
|
preferred_suites += get_suites(min_keylength) - preferred_suites; |
} |
} |
} |
|
#endif /* Crypto.ECC.Curve && Crypto.AES.GCM && Crypto.SHA384 */ |
|
|
|
|
|
Crypto.RSA get_export_rsa_key() |
{ |
return Crypto.RSA()->generate_key(512); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
optional string(8bit) get_psk_hint(); |
|
|
|
|
|
|
|
|
|
|
optional string(8bit) get_psk_id(string(8bit) hint); |
|
|
|
|
|
optional string(8bit) get_psk(string(8bit) id); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int auth_level = AUTHLEVEL_none; |
|
|
|
|
|
|
|
|
|
|
|
|
|
void set_authorities(array(string) a) |
{ |
authorities = a; |
update_authorities(); |
} |
|
|
array(string) get_authorities() |
{ |
return authorities; |
} |
|
protected array(string) authorities = ({}); |
array(string(8bit)) authorities_cache = ({}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void set_trusted_issuers(array(array(string(8bit))) issuers) |
{ |
trusted_issuers = issuers; |
update_trusted_issuers(); |
} |
|
|
array(array(string(8bit))) get_trusted_issuers() |
{ |
return trusted_issuers; |
} |
|
protected array(array(string(8bit))) trusted_issuers = ({}); |
|
|
|
|
|
|
|
mapping(string(8bit):array(Standards.X509.Verifier)) trusted_issuers_cache = ([]); |
|
|
|
|
array(int) client_auth_methods = ({}); |
|
|
|
protected mapping(string(8bit):array(CertificatePair)) cert_chains_issuer = ([]); |
|
|
|
protected mapping(string(8bit):array(CertificatePair)) cert_chains_domain = ([]); |
|
|
|
|
array(CertificatePair) find_cert_issuer(array(string) ders) |
{ |
|
|
foreach(ders, string der) |
if(cert_chains_issuer[der]) |
return cert_chains_issuer[der]; |
|
|
|
return UNDEFINED; |
} |
|
|
|
|
array(CertificatePair) find_cert_domain(string(8bit) domain) |
{ |
if( domain ) |
{ |
if( cert_chains_domain[domain] ) |
return cert_chains_domain[domain]; |
|
|
foreach(cert_chains_domain; string g; array(CertificatePair) chains) |
if( (g != "*") && glob(g, domain) ) |
return chains; |
} |
|
return cert_chains_domain["*"]; |
} |
|
|
array(CertificatePair) get_certificates() |
{ |
mapping(CertificatePair:int) c = ([]); |
foreach(cert_chains_domain;; array(CertificatePair) chains) |
foreach(chains, CertificatePair p) |
c[p]++; |
return indices(c); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void add_cert(Crypto.Sign.State key, array(string(8bit)) certs, |
array(string(8bit))|void extra_name_globs) |
{ |
CertificatePair cp = CertificatePair(key, certs, extra_name_globs); |
add_cert(cp); |
} |
variant void add_cert(string(8bit) key, array(string(8bit)) certs, |
array(string(8bit))|void extra_name_globs) |
{ |
Crypto.Sign.State _key = Standards.PKCS.RSA.parse_private_key(key) || |
Standards.PKCS.DSA.parse_private_key(key) || |
#if constant(Crypto.ECC.Curve) |
Standards.PKCS.ECDSA.parse_private_key(key) || |
#endif |
0; |
add_cert(_key, certs, extra_name_globs); |
} |
variant void add_cert(CertificatePair cp) |
{ |
void add(string what, mapping(string:array(CertificatePair)) to) |
{ |
if( !to[what] ) |
to[what] = ({cp}); |
else |
to[what] = sort( to[what]+({cp}) ); |
}; |
|
|
|
|
|
|
foreach( cp->globs, string id ) |
add(id, cert_chains_domain); |
|
add(cp->issuers[0], cert_chains_issuer); |
} |
|
|
private void update_authorities() |
{ |
authorities_cache = ({}); |
mapping(int:int) cert_types = ([]); |
foreach(authorities, string a) |
{ |
Standards.X509.TBSCertificate tbs = Standards.X509.decode_certificate(a); |
Standards.ASN1.Types.Identifier id = [object(Standards.ASN1.Types.Identifier)]tbs->algorithm[0]; |
|
|
SignatureScheme sign_alg = |
[object(SignatureScheme)]pkcs_der_to_sign_alg[id->get_der()]; |
if (!sign_alg) error("Unknown signature algorithm.\n"); |
|
int cert_type = ([ |
SIGNATURE_rsa: AUTH_rsa_sign, |
SIGNATURE_dsa: AUTH_dss_sign, |
SIGNATURE_ecdsa: AUTH_ecdsa_sign, |
])[sign_alg & SIGNATURE_MASK]; |
|
|
cert_types[cert_type]++; |
authorities_cache += ({ tbs->subject->get_der() }); |
} |
client_auth_methods = indices(cert_types); |
} |
|
|
private void update_trusted_issuers() |
{ |
trusted_issuers_cache=([]); |
foreach(trusted_issuers, array(string) i) |
{ |
|
mapping result = Standards.X509.verify_certificate_chain(i, ([]), 0); |
|
if(!result->verified) |
error("Broken trusted issuer chain!\n"); |
|
|
|
|
|
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"); |
|
trusted_issuers_cache[cert->subject->get_der()] += ({ cert->public_key }); |
} |
} |
|
|
|
|
|
|
|
int use_cache = 1; |
|
|
|
|
int session_lifetime = 600; |
|
|
int max_sessions = 300; |
|
mapping(string:Session) session_cache = ([]); |
|
|
void forget_old_sessions() |
{ |
int t = time() - session_lifetime; |
foreach(session_cache; string id; Session session) |
{ |
if(session->last_activity < t) |
{ |
SSL3_DEBUG_MSG("SSL.Context->forget_old_sessions: " |
"garbing session %O due to session_lifetime limit\n", |
id); |
m_delete (session_cache, id); |
} |
} |
} |
|
|
|
|
Session lookup_session(string id) |
{ |
if (use_cache) |
return session_cache[id]; |
else |
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
Session decode_ticket(string(8bit) ticket) |
{ |
return lookup_session(ticket); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
array(string(8bit)|int) encode_ticket(Session session) |
{ |
if (!use_cache) return 0; |
string(8bit) ticket = session->ticket; |
if (!sizeof(ticket||"")) { |
do { |
ticket = random(32); |
} while(session_cache[ticket]); |
|
|
session->ticket = ticket; |
session->ticket_expiry_time = time(1) + 3600; |
} |
string(8bit) orig_id = session->identity; |
session->identity = ticket; |
record_session(session); |
session->identity = orig_id; |
|
return ({ ticket, 3600 }); |
} |
|
|
Session new_session() |
{ |
string(8bit) id = ""; |
if(use_cache) |
do { |
id = random(32); |
} while( session_cache[id] ); |
|
Session s = Session(id); |
s->ffdhe_groups = ffdhe_groups; |
|
return s; |
} |
|
|
void record_session(Session s) |
{ |
if (use_cache && sizeof(s->identity||"")) |
{ |
if( sizeof(session_cache) > max_sessions ) |
{ |
forget_old_sessions(); |
int to_delete = sizeof(session_cache)-max_sessions; |
foreach(session_cache; string id;) |
{ |
|
if( to_delete-- < 0 ) break; |
SSL3_DEBUG_MSG("SSL.Context->record_session: " |
"garbing session %O due to max_sessions limit\n", id); |
m_delete (session_cache, id); |
} |
} |
SSL3_DEBUG_MSG("SSL.Context->record_session: caching session %O\n", |
s->identity); |
session_cache[s->identity] = s; |
} |
} |
|
|
void purge_session(Session s) |
{ |
SSL3_DEBUG_MSG("SSL.Context->purge_session: %O\n", s->identity || ""); |
if (s->identity) |
m_delete (session_cache, s->identity); |
|
|
|
|
|
|
s->identity = 0; |
if (s->version > PROTOCOL_TLS_1_2) { |
|
|
|
s->master_secret = 0; |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
__deprecated__ void `verify_certificates=(int i) |
{ |
if(!i) |
auth_level = AUTHLEVEL_none; |
else if(auth_level < AUTHLEVEL_verify) |
auth_level = AUTHLEVEL_verify; |
} |
|
__deprecated__ int `verify_certificates() |
{ |
return auth_level >= AUTHLEVEL_verify; |
} |
|
|
|
|
|
|
|
|
|
|
|
__deprecated__ void `require_trust=(int i) |
{ |
if(i) |
auth_level = AUTHLEVEL_require; |
else if(auth_level > AUTHLEVEL_verify) |
auth_level = AUTHLEVEL_verify; |
} |
|
__deprecated__ int `require_trust() |
{ |
return auth_level >= AUTHLEVEL_require; |
} |
|
|
|
|
|
|
|
__deprecated__ void `encrypt_then_mac=(int(0..1) i) |
{ |
extensions[EXTENSION_encrypt_then_mac] = !!i; |
} |
|
__deprecated__ int(0..1) `encrypt_then_mac() |
{ |
return !!extensions[EXTENSION_encrypt_then_mac]; |
} |
|
|
|
|
|
|
|
|
|
ProtocolVersion `min_version() |
{ |
return min(@supported_versions); |
} |
|
ProtocolVersion `max_version() |
{ |
return max(@supported_versions); |
} |
|
protected void generate_versions(ProtocolVersion min, ProtocolVersion max) |
{ |
supported_versions = [array(int(16bit))]reverse(enumerate([int(16bit)](max-min+1), 1, min)); |
} |
|
void `min_version=(ProtocolVersion version) |
{ |
ProtocolVersion m = max_version; |
if( version > m ) |
supported_versions = ({ version }); |
else |
generate_versions(version, m); |
} |
|
void `max_version=(ProtocolVersion version) |
{ |
ProtocolVersion m = min_version; |
if( version < m ) |
supported_versions = ({ version }); |
else |
generate_versions(m, version); |
} |
|
|