Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish removing Ring dependency #295

Closed
wants to merge 13 commits into from
4 changes: 3 additions & 1 deletion components/tls/tls-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ tlsn-tls-core = { path = "../tls-core" }

async-trait.workspace = true
log = { workspace = true, optional = true }
ring.workspace = true
sct.workspace = true
webpki = { workspace = true, features = ["alloc", "std"] }
aes-gcm.workspace = true
Expand All @@ -32,6 +31,8 @@ hmac.workspace = true
sha2 = { workspace = true, features = ["compress"] }
digest.workspace = true
futures.workspace = true
subtle = "2.5.0"
sha1 = "0.10.5"

[features]
default = ["logging", "tls12"]
Expand All @@ -45,6 +46,7 @@ env_logger.workspace = true
webpki-roots.workspace = true
rustls-pemfile.workspace = true
rustls = { workspace = true, features = ["tls12"] }
ring.workspace = true
tokio = { workspace = true, features = ["rt", "macros"] }

[[example]]
Expand Down
52 changes: 0 additions & 52 deletions components/tls/tls-client/src/cipher.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::Error;
use async_trait::async_trait;
use ring::{aead, hkdf};
use tls_core::msgs::{
codec,
message::{OpaqueMessage, PlainMessage},
Expand Down Expand Up @@ -39,54 +38,3 @@ impl MessageDecrypter for InvalidMessageDecrypter {
Err(Error::DecryptError)
}
}

/// A write or read IV.
#[derive(Default)]
pub(crate) struct Iv(pub(crate) [u8; ring::aead::NONCE_LEN]);

impl Iv {
#[cfg(feature = "tls12")]
fn new(value: [u8; ring::aead::NONCE_LEN]) -> Self {
Self(value)
}

#[cfg(feature = "tls12")]
pub(crate) fn copy(value: &[u8]) -> Self {
debug_assert_eq!(value.len(), ring::aead::NONCE_LEN);
let mut iv = Self::new(Default::default());
iv.0.copy_from_slice(value);
iv
}

#[cfg(test)]
pub(crate) fn value(&self) -> &[u8; 12] {
&self.0
}
}

pub(crate) struct IvLen;

impl hkdf::KeyType for IvLen {
fn len(&self) -> usize {
aead::NONCE_LEN
}
}

impl From<hkdf::Okm<'_, IvLen>> for Iv {
fn from(okm: hkdf::Okm<IvLen>) -> Self {
let mut r = Self(Default::default());
okm.fill(&mut r.0[..]).unwrap();
r
}
}

pub(crate) fn make_nonce(iv: &Iv, seq: u64) -> ring::aead::Nonce {
let mut nonce = [0u8; ring::aead::NONCE_LEN];
codec::put_u64(seq, &mut nonce[4..]);

nonce.iter_mut().zip(iv.0.iter()).for_each(|(nonce, iv)| {
*nonce ^= *iv;
});

aead::Nonce::assume_unique_for_key(nonce)
}
20 changes: 9 additions & 11 deletions components/tls/tls-client/src/client/tls12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use crate::{
verify,
};
use async_trait::async_trait;
use ring::constant_time;
use std::sync::Arc;
use subtle::ConstantTimeEq;
use tls_core::{
ke::ServerKxDetails,
key::PublicKey,
Expand Down Expand Up @@ -1094,16 +1094,14 @@ impl State<ClientConnectionData> for ExpectFinished {

// Constant-time verification of this is relatively unimportant: they only
// get one chance. But it can't hurt.
let _fin_verified =
match constant_time::verify_slices_are_equal(&expect_verify_data, &finished.0) {
Ok(()) => verify::FinishedMessageVerified::assertion(),
Err(_) => {
cx.common
.send_fatal_alert(AlertDescription::DecryptError)
.await?;
return Err(Error::DecryptError);
}
};
let _fin_verified = if expect_verify_data.ct_eq(&finished.0).into() {
verify::FinishedMessageVerified::assertion()
} else {
cx.common
.send_fatal_alert(AlertDescription::DecryptError)
.await?;
return Err(Error::DecryptError);
};

// Hash this message too.
st.transcript.add_message(&m);
Expand Down
28 changes: 12 additions & 16 deletions components/tls/tls-client/src/client/tls13.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ use crate::{
},
conn::{CommonState, ConnectionRandoms, State},
error::Error,
hash_hs::{HandshakeHash, HandshakeHashBuffer},
hash_hs::HandshakeHash,
msgs::persist,
sign, verify, KeyLog,
};
use p256::elliptic_curve::subtle::ConstantTimeEq;
use tls_core::{
key::PublicKey,
msgs::{
Expand All @@ -34,8 +35,6 @@ use tls_core::{
suites::Tls13CipherSuite,
};

use ring::constant_time;

use crate::sign::{CertifiedKey, Signer};
use async_trait::async_trait;
use std::sync::Arc;
Expand Down Expand Up @@ -628,7 +627,7 @@ impl State<ClientConnectionData> for ExpectCertificateVerify {
// 2. Verify their signature on the handshake.
let handshake_hash = self.transcript.get_current_hash();
let sig_verified = match self.config.verifier.verify_tls13_signature(
&verify::construct_tls13_server_verify_message(&handshake_hash),
&verify::construct_tls13_server_verify_message(handshake_hash.as_ref()),
&self.server_cert.cert_chain()[0],
cert_verify,
) {
Expand Down Expand Up @@ -689,7 +688,8 @@ async fn emit_certverify_tls13(
signer: &dyn Signer,
common: &mut CommonState,
) -> Result<(), Error> {
let message = verify::construct_tls13_client_verify_message(&transcript.get_current_hash());
let message =
verify::construct_tls13_client_verify_message(transcript.get_current_hash().as_ref());

let scheme = signer.scheme();
let sig = signer.sign(&message)?;
Expand Down Expand Up @@ -771,17 +771,13 @@ impl State<ClientConnectionData> for ExpectFinished {
.get_server_finished_vd(handshake_hash.as_ref())
.await?;

let fin = match constant_time::verify_slices_are_equal(
expect_verify_data.as_ref(),
&finished.0,
) {
Ok(()) => verify::FinishedMessageVerified::assertion(),
Err(_) => {
cx.common
.send_fatal_alert(AlertDescription::DecryptError)
.await?;
return Err(Error::DecryptError);
}
let fin = if expect_verify_data.ct_eq(&finished.0).into() {
verify::FinishedMessageVerified::assertion()
} else {
cx.common
.send_fatal_alert(AlertDescription::DecryptError)
.await?;
return Err(Error::DecryptError);
};

st.transcript.add_message(&m);
Expand Down
108 changes: 74 additions & 34 deletions components/tls/tls-client/src/hash_hs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use ring::digest;
use ::digest::Digest as _;
use std::mem;
use tls_core::{
msgs::{
Expand All @@ -9,6 +9,57 @@ use tls_core::{
suites::HashAlgorithm,
};

#[derive(Clone)]
enum Hasher {
Sha1(sha1::Sha1),
Sha256(sha2::Sha256),
Sha384(sha2::Sha384),
Sha512(sha2::Sha512),
Sha512_256(sha2::Sha512_256),
}

impl Hasher {
pub(crate) fn new_from_alg(algorithm: &'static HashAlgorithm) -> Self {
match algorithm {
HashAlgorithm::SHA1 => Self::Sha1(sha1::Sha1::default()),
HashAlgorithm::SHA256 => Self::Sha256(sha2::Sha256::default()),
HashAlgorithm::SHA384 => Self::Sha384(sha2::Sha384::default()),
HashAlgorithm::SHA512 => Self::Sha512(sha2::Sha512::default()),
HashAlgorithm::SHA512_256 => Self::Sha512_256(sha2::Sha512_256::default()),
}
}

pub(crate) fn update(&mut self, data: &[u8]) {
match self {
Self::Sha1(hasher) => hasher.update(data),
Self::Sha256(hasher) => hasher.update(data),
Self::Sha384(hasher) => hasher.update(data),
Self::Sha512(hasher) => hasher.update(data),
Self::Sha512_256(hasher) => hasher.update(data),
}
}

pub(crate) fn finalize(self) -> Vec<u8> {
match self {
Self::Sha1(hasher) => hasher.finalize().to_vec(),
Self::Sha256(hasher) => hasher.finalize().to_vec(),
Self::Sha384(hasher) => hasher.finalize().to_vec(),
Self::Sha512(hasher) => hasher.finalize().to_vec(),
Self::Sha512_256(hasher) => hasher.finalize().to_vec(),
}
}

pub(crate) fn algorithm(&self) -> &'static HashAlgorithm {
match self {
Self::Sha1(_) => &HashAlgorithm::SHA1,
Self::Sha256(_) => &HashAlgorithm::SHA256,
Self::Sha384(_) => &HashAlgorithm::SHA384,
Self::Sha512(_) => &HashAlgorithm::SHA512,
Self::Sha512_256(_) => &HashAlgorithm::SHA512_256,
}
}
}

/// Early stage buffering of handshake payloads.
///
/// Before we know the hash algorithm to use to verify the handshake, we just buffer the messages.
Expand All @@ -19,16 +70,6 @@ pub(crate) struct HandshakeHashBuffer {
client_auth_enabled: bool,
}

fn map_algorithm(algorithm: &'static HashAlgorithm) -> &'static digest::Algorithm {
match algorithm {
HashAlgorithm::SHA1 => &digest::SHA1_FOR_LEGACY_USE_ONLY,
HashAlgorithm::SHA256 => &digest::SHA256,
HashAlgorithm::SHA384 => &digest::SHA384,
HashAlgorithm::SHA512 => &digest::SHA512,
HashAlgorithm::SHA512_256 => &digest::SHA512_256,
}
}

impl HandshakeHashBuffer {
pub(crate) fn new() -> Self {
Self {
Expand Down Expand Up @@ -61,19 +102,19 @@ impl HandshakeHashBuffer {
&self,
hash: &'static HashAlgorithm,
extra: &[u8],
) -> digest::Digest {
let mut ctx = digest::Context::new(map_algorithm(hash));
ctx.update(&self.buffer);
ctx.update(extra);
ctx.finish()
) -> impl AsRef<[u8]> {
let mut hasher = Hasher::new_from_alg(hash);
hasher.update(&self.buffer);
hasher.update(extra);
hasher.finalize()
}

/// We now know what hash function the verify_data will use.
pub(crate) fn start_hash(self, alg: &'static HashAlgorithm) -> HandshakeHash {
let mut ctx = digest::Context::new(map_algorithm(alg));
ctx.update(&self.buffer);
let mut hasher = Hasher::new_from_alg(alg);
hasher.update(&self.buffer);
HandshakeHash {
ctx,
hasher,
client_auth: match self.client_auth_enabled {
true => Some(self.buffer),
false => None,
Expand All @@ -90,8 +131,7 @@ impl HandshakeHashBuffer {
/// For client auth, we also need to buffer all the messages.
/// This is disabled in cases where client auth is not possible.
pub(crate) struct HandshakeHash {
/// None before we know what hash function we're using
ctx: digest::Context,
hasher: Hasher,

/// buffer for client-auth.
client_auth: Option<Vec<u8>>,
Expand All @@ -115,7 +155,7 @@ impl HandshakeHash {

/// Hash or buffer a byte slice.
fn update_raw(&mut self, buf: &[u8]) -> &mut Self {
self.ctx.update(buf);
self.hasher.update(buf);

if let Some(buffer) = &mut self.client_auth {
buffer.extend_from_slice(buf);
Expand All @@ -126,14 +166,14 @@ impl HandshakeHash {

/// Get the hash value if we were to hash `extra` too,
/// using hash function `hash`.
pub(crate) fn get_hash_given(&self, extra: &[u8]) -> digest::Digest {
let mut ctx = self.ctx.clone();
ctx.update(extra);
ctx.finish()
pub(crate) fn get_hash_given(&self, extra: &[u8]) -> impl AsRef<[u8]> {
let mut hasher = self.hasher.clone();
hasher.update(extra);
hasher.finalize()
}

pub(crate) fn into_hrr_buffer(self) -> HandshakeHashBuffer {
let old_hash = self.ctx.finish();
let old_hash = self.hasher.clone().finalize();
let old_handshake_hash_msg =
HandshakeMessagePayload::build_handshake_hash(old_hash.as_ref());

Expand All @@ -147,19 +187,19 @@ impl HandshakeHash {
/// 'handshake_hash' handshake message. Start this hash
/// again, with that message at the front.
pub(crate) fn rollup_for_hrr(&mut self) {
let ctx = &mut self.ctx;
let hasher = &mut self.hasher;

let old_ctx = mem::replace(ctx, digest::Context::new(ctx.algorithm()));
let old_hash = old_ctx.finish();
let old_hasher = mem::replace(hasher, Hasher::new_from_alg(hasher.algorithm()));
let old_hash = old_hasher.finalize();
let old_handshake_hash_msg =
HandshakeMessagePayload::build_handshake_hash(old_hash.as_ref());

self.update_raw(&old_handshake_hash_msg.get_encoding());
}

/// Get the current hash value.
pub(crate) fn get_current_hash(&self) -> digest::Digest {
self.ctx.clone().finish()
pub(crate) fn get_current_hash(&self) -> impl AsRef<[u8]> {
self.hasher.clone().finalize()
}

/// Takes this object's buffer containing all handshake messages
Expand All @@ -171,8 +211,8 @@ impl HandshakeHash {
}

/// The digest algorithm
pub(crate) fn algorithm(&self) -> &'static digest::Algorithm {
self.ctx.algorithm()
pub(crate) fn algorithm(&self) -> &'static HashAlgorithm {
self.hasher.algorithm()
}
}

Expand Down
Loading
Loading