diff --git a/Cargo.toml b/Cargo.toml index c5512265..e54bc2c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ categories = ["network-programming", "cryptography"] [dependencies] base64 = "0.10" log = { version = "0.4.4", optional = true } -ring = "0.16.2" +ring = "0.16.3" sct = "0.6.0" webpki = "0.21.0" diff --git a/src/cipher.rs b/src/cipher.rs index 1de70e6e..15dd904c 100644 --- a/src/cipher.rs +++ b/src/cipher.rs @@ -123,9 +123,8 @@ pub fn new_tls12(scs: &'static SupportedCipherSuite, pub fn new_tls13_read(scs: &'static SupportedCipherSuite, secret: &[u8]) -> Box { - let hash = scs.get_hash(); - let key = derive_traffic_key(hash, secret, scs.enc_key_len); - let iv = derive_traffic_iv(hash, secret); + let key = derive_traffic_key(scs.hkdf_algorithm, secret, scs.enc_key_len); + let iv = derive_traffic_iv(scs.hkdf_algorithm, secret); let aead_alg = scs.get_aead_alg(); Box::new(TLS13MessageDecrypter::new(aead_alg, &key, iv)) @@ -133,9 +132,8 @@ pub fn new_tls13_read(scs: &'static SupportedCipherSuite, pub fn new_tls13_write(scs: &'static SupportedCipherSuite, secret: &[u8]) -> Box { - let hash = scs.get_hash(); - let key = derive_traffic_key(hash, secret, scs.enc_key_len); - let iv = derive_traffic_iv(hash, secret); + let key = derive_traffic_key(scs.hkdf_algorithm, secret, scs.enc_key_len); + let iv = derive_traffic_iv(scs.hkdf_algorithm, secret); let aead_alg = scs.get_aead_alg(); Box::new(TLS13MessageEncrypter::new(aead_alg, &key, iv)) diff --git a/src/client/tls13.rs b/src/client/tls13.rs index 28ec18cc..3c05f25f 100644 --- a/src/client/tls13.rs +++ b/src/client/tls13.rs @@ -125,7 +125,9 @@ pub fn fill_in_psk_binder(sess: &mut ClientSessionImpl, hmp: &mut HandshakeMessagePayload) { // We need to know the hash function of the suite we're trying to resume into. let resuming = handshake.resuming_session.as_ref().unwrap(); - let suite_hash = sess.find_cipher_suite(resuming.cipher_suite).unwrap().get_hash(); + let suite = sess.find_cipher_suite(resuming.cipher_suite).unwrap(); + let hkdf_alg = suite.hkdf_algorithm; + let suite_hash = suite.get_hash(); // The binder is calculated over the clienthello, but doesn't include itself or its // length, or the length of its container. @@ -139,7 +141,7 @@ pub fn fill_in_psk_binder(sess: &mut ClientSessionImpl, // Run a fake key_schedule to simulate what the server will do if it choses // to resume. - let mut key_schedule = KeySchedule::new(suite_hash); + let mut key_schedule = KeySchedule::new(hkdf_alg); key_schedule.input_secret(&resuming.master_secret.0); let base_key = key_schedule.derive(SecretKind::ResumptionPSKBinderKey, &empty_hash); let real_binder = key_schedule.sign_verify_data(&base_key, &handshake_hash); @@ -183,7 +185,7 @@ pub fn start_handshake_traffic(sess: &mut ClientSessionImpl, // Discard the early data key schedule. sess.early_data.rejected(); sess.common.early_traffic = false; - let mut key_schedule = KeySchedule::new(suite.get_hash()); + let mut key_schedule = KeySchedule::new(suite.hkdf_algorithm); key_schedule.input_empty(); sess.common.set_key_schedule(key_schedule); handshake.resuming_session.take(); diff --git a/src/key_schedule.rs b/src/key_schedule.rs index 95c473f5..dbd54a97 100644 --- a/src/key_schedule.rs +++ b/src/key_schedule.rs @@ -1,6 +1,6 @@ /// Key schedule maintenance for TLS1.3 -use ring::{hmac, digest}; +use ring::{hkdf, hmac, digest}; use crate::msgs::codec::Codec; use crate::error::TLSError; use std::convert::TryInto; @@ -20,18 +20,6 @@ pub enum SecretKind { DerivedSecret, } -fn convert_digest_to_hmac_alg(hash: &'static digest::Algorithm) -> hmac::Algorithm { - if hash == &digest::SHA256 { - hmac::HMAC_SHA256 - } else if hash == &digest::SHA384 { - hmac::HMAC_SHA384 - } else if hash == &digest::SHA512 { - hmac::HMAC_SHA512 - } else { - panic!("bad digest for prf"); - } -} - impl SecretKind { fn to_bytes(self) -> &'static [u8] { match self { @@ -84,23 +72,20 @@ fn _hkdf_extract(salt: &hmac::Key, secret: &[u8]) -> hmac::Key { pub struct KeySchedule { current: hmac::Key, need_derive_for_extract: bool, - hash: &'static digest::Algorithm, - hmac_alg: hmac::Algorithm, + algorithm: ring::hkdf::Algorithm, pub current_client_traffic_secret: Vec, pub current_server_traffic_secret: Vec, pub current_exporter_secret: Vec, } impl KeySchedule { - pub fn new(hash: &'static digest::Algorithm) -> KeySchedule { + pub fn new(algorithm: hkdf::Algorithm) -> KeySchedule { let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; - + let zeroes = &zeroes[..algorithm.hmac_algorithm().digest_algorithm().output_len]; KeySchedule { - current: hmac::Key::new(convert_digest_to_hmac_alg(hash), - &zeroes[..hash.output_len]), + current: hmac::Key::new(algorithm.hmac_algorithm(), zeroes), need_derive_for_extract: false, - hash, - hmac_alg: convert_digest_to_hmac_alg(hash), + algorithm, current_server_traffic_secret: Vec::new(), current_client_traffic_secret: Vec::new(), current_exporter_secret: Vec::new(), @@ -110,7 +95,7 @@ impl KeySchedule { /// Input the empty secret. pub fn input_empty(&mut self) { let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; - let hash_len = self.hash.output_len; + let hash_len = self.algorithm.hmac_algorithm().digest_algorithm().output_len; self.input_secret(&zeroes[..hash_len]); } @@ -118,7 +103,7 @@ impl KeySchedule { pub fn input_secret(&mut self, secret: &[u8]) { if self.need_derive_for_extract { let derived = self.derive_for_empty_hash(SecretKind::DerivedSecret); - self.current = hmac::Key::new(self.hmac_alg, + self.current = hmac::Key::new(self.algorithm.hmac_algorithm(), &derived); } self.need_derive_for_extract = true; @@ -128,12 +113,12 @@ impl KeySchedule { /// Derive a secret of given `kind`, using current handshake hash `hs_hash`. pub fn derive(&self, kind: SecretKind, hs_hash: &[u8]) -> Vec { - debug_assert_eq!(hs_hash.len(), self.hash.output_len); + debug_assert_eq!(hs_hash.len(), self.algorithm.hmac_algorithm().digest_algorithm().output_len); _hkdf_expand_label_vec(&self.current, kind.to_bytes(), hs_hash, - self.hash.output_len) + hs_hash.len()) } /// Derive a secret of given `kind` using the hash of the empty string @@ -141,11 +126,9 @@ impl KeySchedule { /// `SecretKind::ResumptionPSKBinderKey` and /// `SecretKind::DerivedSecret`. pub fn derive_for_empty_hash(&self, kind: SecretKind) -> Vec { - let mut empty_hash = [0u8; digest::MAX_OUTPUT_LEN]; - empty_hash[..self.hash.output_len] - .clone_from_slice(digest::digest(self.hash, &[]).as_ref()); - - self.derive(kind, &empty_hash[..self.hash.output_len]) + let digest_alg = self.algorithm.hmac_algorithm().digest_algorithm(); + let empty_hash = digest::digest(digest_alg, &[]); + self.derive(kind, empty_hash.as_ref()) } /// Return the current traffic secret, of given `kind`. @@ -170,14 +153,17 @@ impl KeySchedule { /// Sign the finished message consisting of `hs_hash` using the key material /// `base_key`. pub fn sign_verify_data(&self, base_key: &[u8], hs_hash: &[u8]) -> Vec { - debug_assert_eq!(hs_hash.len(), self.hash.output_len); + let hmac_alg = self.algorithm.hmac_algorithm(); + let digest_alg = hmac_alg.digest_algorithm(); - let hmac_key = _hkdf_expand_label_vec(&hmac::Key::new(self.hmac_alg, base_key), + debug_assert_eq!(hs_hash.len(), digest_alg.output_len); + + let hmac_key = _hkdf_expand_label_vec(&hmac::Key::new(hmac_alg, base_key), b"finished", &[], - self.hash.output_len); + digest_alg.output_len); - hmac::sign(&hmac::Key::new(self.hmac_alg, &hmac_key), hs_hash) + hmac::sign(&hmac::Key::new(hmac_alg, &hmac_key), hs_hash) .as_ref() .to_vec() } @@ -185,20 +171,24 @@ impl KeySchedule { /// Derive the next application traffic secret of given `kind`, returning /// it. pub fn derive_next(&self, kind: SecretKind) -> Vec { + let hmac_alg = self.algorithm.hmac_algorithm(); + let digest_alg = hmac_alg.digest_algorithm(); let base_key = self.current_traffic_secret(kind); - _hkdf_expand_label_vec(&hmac::Key::new(self.hmac_alg, base_key), + _hkdf_expand_label_vec(&hmac::Key::new(hmac_alg, base_key), b"traffic upd", &[], - self.hash.output_len) + digest_alg.output_len) } /// Derive the PSK to use given a resumption_master_secret and /// ticket_nonce. pub fn derive_ticket_psk(&self, rms: &[u8], nonce: &[u8]) -> Vec { - _hkdf_expand_label_vec(&hmac::Key::new(self.hmac_alg, rms), + let hmac_alg = self.algorithm.hmac_algorithm(); + let digest_alg = hmac_alg.digest_algorithm(); + _hkdf_expand_label_vec(&hmac::Key::new(hmac_alg, rms), b"resumption", nonce, - self.hash.output_len) + digest_alg.output_len) } pub fn export_keying_material(&self, out: &mut [u8], @@ -208,32 +198,34 @@ impl KeySchedule { return Err(TLSError::HandshakeNotComplete); } - let h_empty = digest::digest(self.hash, &[]); + let hmac_alg = self.algorithm.hmac_algorithm(); + let digest_alg = hmac_alg.digest_algorithm(); + + let h_empty = digest::digest(digest_alg, &[]); let mut secret = [0u8; digest::MAX_OUTPUT_LEN]; - _hkdf_expand_label(&mut secret[..self.hash.output_len], - &hmac::Key::new(self.hmac_alg, + let secret = &mut secret[..digest_alg.output_len]; + _hkdf_expand_label(secret, + &hmac::Key::new(hmac_alg, &self.current_exporter_secret), label, h_empty.as_ref()); - let mut h_context = [0u8; digest::MAX_OUTPUT_LEN]; - h_context[..self.hash.output_len] - .clone_from_slice(digest::digest(self.hash, - context.unwrap_or(&[])) - .as_ref()); + let h_context = digest::digest(digest_alg, context.unwrap_or(&[])); _hkdf_expand_label(out, - &hmac::Key::new(self.hmac_alg, &secret[..self.hash.output_len]), + &hmac::Key::new(hmac_alg, secret), b"exporter", - &h_context[..self.hash.output_len]); + h_context.as_ref()); Ok(()) } } -fn _hkdf_expand_label_vec(secret: &hmac::Key, - label: &[u8], - context: &[u8], - len: usize) -> Vec { +pub(crate) fn _hkdf_expand_label_vec( + secret: &hmac::Key, + label: &[u8], + context: &[u8], + len: usize) -> Vec +{ let mut v = Vec::new(); v.resize(len, 0u8); _hkdf_expand_label(&mut v, @@ -260,14 +252,12 @@ fn _hkdf_expand_label(output: &mut [u8], _hkdf_expand(secret, &hkdflabel, output) } -pub fn derive_traffic_key(hash: &'static digest::Algorithm, secret: &[u8], len: usize) -> Vec { - let hmac_alg = convert_digest_to_hmac_alg(hash); - _hkdf_expand_label_vec(&hmac::Key::new(hmac_alg, secret), b"key", &[], len) +pub fn derive_traffic_key(algorithm: hkdf::Algorithm, secret: &[u8], len: usize) -> Vec { + _hkdf_expand_label_vec(&hmac::Key::new(algorithm.hmac_algorithm(), secret), b"key", &[], len) } -pub(crate) fn derive_traffic_iv(hash: &'static digest::Algorithm, secret: &[u8]) -> Iv { - let hmac_alg = convert_digest_to_hmac_alg(hash); - let iv = _hkdf_expand_label_vec(&hmac::Key::new(hmac_alg, secret), b"iv", &[], +pub(crate) fn derive_traffic_iv(algorithm: hkdf::Algorithm, secret: &[u8]) -> Iv { + let iv = _hkdf_expand_label_vec(&hmac::Key::new(algorithm.hmac_algorithm(), secret), b"iv", &[], ring::aead::NONCE_LEN); Iv::new(iv[..].try_into().unwrap()) } @@ -275,13 +265,13 @@ pub(crate) fn derive_traffic_iv(hash: &'static digest::Algorithm, secret: &[u8]) #[cfg(test)] mod test { use super::{KeySchedule, SecretKind, derive_traffic_key, derive_traffic_iv}; - use ring::digest; + use ring::hkdf; #[test] fn smoke_test() { let fake_handshake_hash = [0u8; 32]; - let mut ks = KeySchedule::new(&digest::SHA256); + let mut ks = KeySchedule::new(hkdf::HKDF_SHA256); ks.input_empty(); // no PSK ks.derive(SecretKind::ResumptionPSKBinderKey, &fake_handshake_hash); ks.input_secret(&[1u8, 2u8, 3u8, 4u8]); @@ -378,8 +368,8 @@ mod test { 0x0d, 0xb2, 0x8f, 0x98, 0x85, 0x86, 0xa1, 0xb7, 0xe4, 0xd5, 0xc6, 0x9c ]; - let hash = &digest::SHA256; - let mut ks = KeySchedule::new(hash); + let hkdf = hkdf::HKDF_SHA256; + let mut ks = KeySchedule::new(hkdf); ks.input_empty(); ks.input_secret(&ecdhe_secret); @@ -387,17 +377,17 @@ mod test { &hs_start_hash); assert_eq!(got_client_hts, client_hts.to_vec()); - assert_eq!(derive_traffic_key(hash, &got_client_hts, client_hts_key.len()), + assert_eq!(derive_traffic_key(hkdf, &got_client_hts, client_hts_key.len()), client_hts_key.to_vec()); - assert_eq!(derive_traffic_iv(hash, &got_client_hts).value(), &client_hts_iv); + assert_eq!(derive_traffic_iv(hkdf, &got_client_hts).value(), &client_hts_iv); let got_server_hts = ks.derive(SecretKind::ServerHandshakeTrafficSecret, &hs_start_hash); assert_eq!(got_server_hts, server_hts.to_vec()); - assert_eq!(derive_traffic_key(hash, &got_server_hts, server_hts_key.len()), + assert_eq!(derive_traffic_key(hkdf, &got_server_hts, server_hts_key.len()), server_hts_key.to_vec()); - assert_eq!(derive_traffic_iv(hash, &got_server_hts).value(), &server_hts_iv); + assert_eq!(derive_traffic_iv(hkdf, &got_server_hts).value(), &server_hts_iv); ks.input_empty(); @@ -405,17 +395,17 @@ mod test { &hs_full_hash); assert_eq!(got_client_ats, client_ats.to_vec()); - assert_eq!(derive_traffic_key(hash, &got_client_ats, client_ats_key.len()), + assert_eq!(derive_traffic_key(hkdf, &got_client_ats, client_ats_key.len()), client_ats_key.to_vec()); - assert_eq!(derive_traffic_iv(hash, &got_client_ats).value(), &client_ats_iv); + assert_eq!(derive_traffic_iv(hkdf, &got_client_ats).value(), &client_ats_iv); let got_server_ats = ks.derive(SecretKind::ServerApplicationTrafficSecret, &hs_full_hash); assert_eq!(got_server_ats, server_ats.to_vec()); - assert_eq!(derive_traffic_key(hash, &got_server_ats, server_ats_key.len()), + assert_eq!(derive_traffic_key(hkdf, &got_server_ats, server_ats_key.len()), server_ats_key.to_vec()); - assert_eq!(derive_traffic_iv(hash, &got_server_ats).value(), &server_ats_iv); + assert_eq!(derive_traffic_iv(hkdf, &got_server_ats).value(), &server_ats_iv); } } diff --git a/src/quic.rs b/src/quic.rs index a0197d11..acd33371 100644 --- a/src/quic.rs +++ b/src/quic.rs @@ -5,10 +5,11 @@ use crate::msgs::handshake::{ClientExtension, ServerExtension}; use crate::msgs::message::{Message, MessagePayload}; use crate::server::{ServerConfig, ServerSession, ServerSessionImpl}; use crate::error::TLSError; -use crate::key_schedule::{KeySchedule, SecretKind}; +use crate::key_schedule; use crate::session::{SessionCommon, Protocol}; use std::sync::Arc; +use ring::hmac; use webpki; /// Secrets used to encrypt/decrypt traffic @@ -123,14 +124,19 @@ fn write_hs(this: &mut SessionCommon, buf: &mut Vec) -> Option { } fn update_secrets(this: &SessionCommon, client: &[u8], server: &[u8]) -> Secrets { - let suite = this.get_suite_assert(); - // TODO: Don't clone - let mut key_schedule = KeySchedule::new(suite.get_hash()); - key_schedule.current_client_traffic_secret = client.into(); - key_schedule.current_server_traffic_secret = server.into(); + let hmac_alg= this.get_suite_assert().hkdf_algorithm.hmac_algorithm(); + let digest_alg = hmac_alg.digest_algorithm(); Secrets { - client: key_schedule.derive_next(SecretKind::ClientApplicationTrafficSecret), - server: key_schedule.derive_next(SecretKind::ServerApplicationTrafficSecret), + client: key_schedule::_hkdf_expand_label_vec( + &hmac::Key::new(hmac_alg, client), + b"traffic upd", + &[], + digest_alg.output_len), + server: key_schedule::_hkdf_expand_label_vec( + &hmac::Key::new(hmac_alg, server), + b"traffic upd", + &[], + digest_alg.output_len) } } diff --git a/src/server/tls13.rs b/src/server/tls13.rs index 866a8330..266fd3db 100644 --- a/src/server/tls13.rs +++ b/src/server/tls13.rs @@ -68,10 +68,12 @@ impl CompleteClientHelloHandling { _ => unreachable!(), }; - let suite_hash = sess.common.get_suite_assert().get_hash(); + let suite = sess.common.get_suite_assert(); + let hkdf_alg = suite.hkdf_algorithm; + let suite_hash = suite.get_hash(); let handshake_hash = self.handshake.transcript.get_hash_given(suite_hash, &binder_plaintext); - let mut key_schedule = KeySchedule::new(suite_hash); + let mut key_schedule = KeySchedule::new(hkdf_alg); key_schedule.input_secret(psk); let base_key = key_schedule.derive_for_empty_hash(SecretKind::ResumptionPSKBinderKey); let real_binder = key_schedule.sign_verify_data(&base_key, &handshake_hash); @@ -153,7 +155,7 @@ impl CompleteClientHelloHandling { // Start key schedule let suite = sess.common.get_suite_assert(); - let mut key_schedule = KeySchedule::new(suite.get_hash()); + let mut key_schedule = KeySchedule::new(suite.hkdf_algorithm); if let Some(psk) = resuming_psk { key_schedule.input_secret(psk); diff --git a/src/suites.rs b/src/suites.rs index cb7404b6..4963d2bc 100644 --- a/src/suites.rs +++ b/src/suites.rs @@ -156,6 +156,8 @@ pub struct SupportedCipherSuite { /// in a deterministic and safe way. GCM needs this, /// chacha20poly1305 works this way by design. pub explicit_nonce_len: usize, + + pub(crate) hkdf_algorithm: ring::hkdf::Algorithm, } impl PartialEq for SupportedCipherSuite { @@ -167,12 +169,7 @@ impl PartialEq for SupportedCipherSuite { impl SupportedCipherSuite { /// Which hash function to use with this suite. pub fn get_hash(&self) -> &'static ring::digest::Algorithm { - match self.hash { - HashAlgorithm::SHA256 => &ring::digest::SHA256, - HashAlgorithm::SHA384 => &ring::digest::SHA384, - HashAlgorithm::SHA512 => &ring::digest::SHA512, - _ => unreachable!(), - } + self.hkdf_algorithm.hmac_algorithm().digest_algorithm() } /// We have parameters and a verified public key in `kx_params`. @@ -276,6 +273,7 @@ pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = enc_key_len: 32, fixed_iv_len: 12, explicit_nonce_len: 0, + hkdf_algorithm: ring::hkdf::HKDF_SHA256, }; pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = @@ -288,6 +286,7 @@ pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = enc_key_len: 32, fixed_iv_len: 12, explicit_nonce_len: 0, + hkdf_algorithm: ring::hkdf::HKDF_SHA256, }; pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite { @@ -299,6 +298,7 @@ pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = Support enc_key_len: 16, fixed_iv_len: 4, explicit_nonce_len: 8, + hkdf_algorithm: ring::hkdf::HKDF_SHA256, }; pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = SupportedCipherSuite { @@ -310,6 +310,7 @@ pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = Support enc_key_len: 32, fixed_iv_len: 4, explicit_nonce_len: 8, + hkdf_algorithm: ring::hkdf::HKDF_SHA384, }; pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite { @@ -321,6 +322,7 @@ pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = Suppo enc_key_len: 16, fixed_iv_len: 4, explicit_nonce_len: 8, + hkdf_algorithm: ring::hkdf::HKDF_SHA256, }; pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = SupportedCipherSuite { @@ -332,6 +334,7 @@ pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = Suppo enc_key_len: 32, fixed_iv_len: 4, explicit_nonce_len: 8, + hkdf_algorithm: ring::hkdf::HKDF_SHA384, }; pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = SupportedCipherSuite { @@ -343,6 +346,7 @@ pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = SupportedCiphe enc_key_len: 32, fixed_iv_len: 12, explicit_nonce_len: 0, + hkdf_algorithm: ring::hkdf::HKDF_SHA256, }; pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = SupportedCipherSuite { @@ -354,6 +358,7 @@ pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = SupportedCipherSuite enc_key_len: 32, fixed_iv_len: 12, explicit_nonce_len: 0, + hkdf_algorithm: ring::hkdf::HKDF_SHA384, }; pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite { @@ -365,6 +370,7 @@ pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite enc_key_len: 16, fixed_iv_len: 12, explicit_nonce_len: 0, + hkdf_algorithm: ring::hkdf::HKDF_SHA256, }; /// A list of all the cipher suites supported by rustls.