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

refactor: use tls prf from tls-core in rc backend #413

Merged
merged 2 commits into from
Jan 17, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 43 additions & 102 deletions components/tls/tls-client/src/backend/standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ use p256::{ecdh::EphemeralSecret, EncodedPoint, PublicKey as ECDHPublicKey};
use rand::{rngs::OsRng, thread_rng, Rng};

use digest::Digest;
use hmac::{Hmac, Mac};
use sha2::Sha256;
use std::{any::Any, convert::TryInto};
use tls_core::{
cert::ServerCertDetails,
Expand All @@ -22,54 +20,10 @@ use tls_core::{
handshake::Random,
message::{OpaqueMessage, PlainMessage},
},
prf::prf,
suites::{self, SupportedCipherSuite},
};

type HmacSha256 = Hmac<Sha256>;

pub(crate) fn hmac_sha256(key: &[u8], input: &[u8]) -> [u8; 32] {
let mut mac = HmacSha256::new_from_slice(key).unwrap();
mac.update(input);
let out = mac.finalize().into_bytes();
out[..32]
.try_into()
.expect("expected output to be 32 bytes")
}

pub(crate) fn seed_ms(client_random: &[u8; 32], server_random: &[u8; 32]) -> [u8; 77] {
let mut seed = [0u8; 77];
seed[..13].copy_from_slice(b"master secret");
seed[13..45].copy_from_slice(client_random);
seed[45..].copy_from_slice(server_random);
seed
}

pub(crate) fn seed_ke(client_random: &[u8; 32], server_random: &[u8; 32]) -> [u8; 77] {
let mut seed = [0u8; 77];
seed[..13].copy_from_slice(b"key expansion");
seed[13..45].copy_from_slice(server_random);
seed[45..].copy_from_slice(client_random);
seed
}

pub(crate) fn seed_cf(handshake_blob: &[u8]) -> [u8; 47] {
let mut hasher = Sha256::new();
hasher.update(handshake_blob);
let mut seed = [0u8; 47];
seed[..15].copy_from_slice(b"client finished");
seed[15..].copy_from_slice(hasher.finalize().as_slice());
seed
}

pub(crate) fn seed_sf(handshake_blob: &[u8]) -> [u8; 47] {
let mut hasher = Sha256::new();
hasher.update(handshake_blob);
let mut seed = [0u8; 47];
seed[..15].copy_from_slice(b"server finished");
seed[15..].copy_from_slice(hasher.finalize().as_slice());
seed
}

/// Implementation of TLS backend using RustCrypto primitives
pub struct RustCryptoBackend {
client_random: Option<Random>,
Expand Down Expand Up @@ -115,17 +69,18 @@ impl RustCryptoBackend {

/// Expands the handshake hash and master secret into verify_data for
/// the Server_Finished
pub fn verify_data_sf_tls12(&mut self, hs_hash: &[u8], ms: &[u8; 48]) -> [u8; 12] {
let mut seed = [0u8; 47];
seed[..15].copy_from_slice(b"server finished");
seed[15..].copy_from_slice(hs_hash);
let a1 = hmac_sha256(ms, &seed);
let mut a1_seed = [0u8; 79];
a1_seed[..32].copy_from_slice(&a1);
a1_seed[32..].copy_from_slice(&seed);
let mut verify_data = [0u8; 12];
verify_data.copy_from_slice(&hmac_sha256(ms, &a1_seed)[..12]);
verify_data
pub fn verify_data_sf_tls12(&self, hs_hash: &[u8], ms: &[u8; 48]) -> [u8; 12] {
let mut vd = [0u8; 12];
prf(&mut vd, ms, b"server finished", hs_hash).expect("key length is valid");
vd
}

/// Expands the handshake hash and master secret into verify_data for
/// the Client_Finished
pub fn verify_data_cf_tls12(&self, hs_hash: &[u8], ms: &[u8; 48]) -> [u8; 12] {
let mut vd = [0u8; 12];
prf(&mut vd, ms, b"client finished", hs_hash).expect("key length is valid");
vd
}

/// Expands pre-master secret into session key using TLS 1.2 PRF
Expand All @@ -137,53 +92,26 @@ impl RustCryptoBackend {
pms: &[u8],
) -> ([u8; 48], [u8; 40]) {
// first expand pms into ms
let seed = seed_ms(client_random, server_random);
let a1 = hmac_sha256(pms, &seed);
let a2 = hmac_sha256(pms, &a1);
let mut a1_seed = [0u8; 109];
a1_seed[..32].copy_from_slice(&a1);
a1_seed[32..].copy_from_slice(&seed);
let mut a2_seed = [0u8; 109];
a2_seed[..32].copy_from_slice(&a2);
a2_seed[32..].copy_from_slice(&seed);
let p1 = hmac_sha256(pms, &a1_seed);
let p2 = hmac_sha256(pms, &a2_seed);
let mut ms = [0u8; 48];
ms[..32].copy_from_slice(&p1);
ms[32..].copy_from_slice(&p2[..16]);
let ms_out = ms;
prf(
&mut ms,
pms,
b"master secret",
&concat::<64>(client_random, server_random),
)
.expect("key length is valid");

// expand ms into session keys
let seed = seed_ke(client_random, server_random);
let a1 = hmac_sha256(&ms, &seed);
let a2 = hmac_sha256(&ms, &a1);
let mut a1_seed = [0u8; 109];
a1_seed[..32].copy_from_slice(&a1);
a1_seed[32..].copy_from_slice(&seed);
let mut a2_seed = [0u8; 109];
a2_seed[..32].copy_from_slice(&a2);
a2_seed[32..].copy_from_slice(&seed);
let p1 = hmac_sha256(&ms, &a1_seed);
let p2 = hmac_sha256(&ms, &a2_seed);
let mut ek = [0u8; 40];
ek[..32].copy_from_slice(&p1);
ek[32..].copy_from_slice(&p2[..8]);
(ms_out, ek)
}

/// Expands the handshake hash and master secret into verify_data for
/// the Client_Finished
pub fn verify_data_cf_tls12(&mut self, hs_hash: &[u8], ms: &[u8; 48]) -> [u8; 12] {
let mut seed = [0u8; 47];
seed[..15].copy_from_slice(b"client finished");
seed[15..].copy_from_slice(hs_hash);
let a1 = hmac_sha256(ms, &seed);
let mut a1_seed = [0u8; 79];
a1_seed[..32].copy_from_slice(&a1);
a1_seed[32..].copy_from_slice(&seed);
let mut verify_data = [0u8; 12];
verify_data.copy_from_slice(&hmac_sha256(ms, &a1_seed)[..12]);
verify_data
let mut session_keys = [0u8; 40];
prf(
&mut session_keys,
&ms,
b"key expansion",
&concat::<64>(server_random, client_random),
)
.expect("key length is valid");

(ms, session_keys)
}

fn set_encrypter(&mut self) -> Result<(), BackendError> {
Expand Down Expand Up @@ -477,6 +405,19 @@ impl Backend for RustCryptoBackend {
}
}

/// Concatenates two slices into a new array.
///
/// # Panics
///
/// Panics if the size of the output array is not equal to the sum of the sizes of the input slices.
fn concat<const O: usize>(left: &[u8], right: &[u8]) -> [u8; O] {
assert_eq!(left.len() + right.len(), O);
let mut out = [0u8; O];
out[..left.len()].copy_from_slice(left);
out[left.len()..].copy_from_slice(right);
out
}

pub struct Encrypter {
write_key: [u8; 16],
write_iv: [u8; 4],
Expand Down