Compare commits
2 Commits
d0488892fb
...
3bd54d682a
Author | SHA1 | Date |
---|---|---|
occheung | 3bd54d682a | |
occheung | 5638a660c2 |
|
@ -50,6 +50,11 @@ version = "1.0.1"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = [ "u64_backend" ]
|
features = [ "u64_backend" ]
|
||||||
|
|
||||||
|
[dependencies.x25519-dalek]
|
||||||
|
version = "1.1.0"
|
||||||
|
default-features = false
|
||||||
|
features = [ "u64_backend" ]
|
||||||
|
|
||||||
# Fetch from master, for "no_std" + "alloc" combination
|
# Fetch from master, for "no_std" + "alloc" combination
|
||||||
[dependencies.rsa]
|
[dependencies.rsa]
|
||||||
git = "https://github.com/RustCrypto/RSA.git"
|
git = "https://github.com/RustCrypto/RSA.git"
|
||||||
|
|
|
@ -154,24 +154,7 @@ pub struct AlgorithmIdentifier<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Certificate<'a> {
|
impl<'a> Certificate<'a> {
|
||||||
// Return the public key, if used for RSA
|
|
||||||
pub fn return_rsa_public_key(&self) -> Result<RSAPublicKey, ()> {
|
|
||||||
if self.signature_algorithm.algorithm != SHA1_WITH_RSA_ENCRYPTION {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
let (_, (modulus, exponent)) = parse_asn1_der_rsa_public_key(
|
|
||||||
self.tbs_certificate.subject_public_key_info.subject_public_key
|
|
||||||
).map_err(|_| ())?;
|
|
||||||
|
|
||||||
RSAPublicKey::new(
|
|
||||||
BigUint::from_bytes_be(modulus),
|
|
||||||
BigUint::from_bytes_be(exponent)
|
|
||||||
).map_err(|_| ())
|
|
||||||
}
|
|
||||||
|
|
||||||
// General return public key method
|
// General return public key method
|
||||||
// TODO: Replace return_rsa_public_key() with this method
|
|
||||||
// Things to change: session.rs: client_update_for_wait_cert_cr
|
|
||||||
pub(crate) fn get_cert_public_key(&self) -> Result<CertificatePublicKey, ()> {
|
pub(crate) fn get_cert_public_key(&self) -> Result<CertificatePublicKey, ()> {
|
||||||
let public_key_info = &self.tbs_certificate.subject_public_key_info;
|
let public_key_info = &self.tbs_certificate.subject_public_key_info;
|
||||||
let algorithm_identifier = &public_key_info.algorithm;
|
let algorithm_identifier = &public_key_info.algorithm;
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub(crate) struct Session {
|
||||||
// Hash functions needed
|
// Hash functions needed
|
||||||
hash: Hash,
|
hash: Hash,
|
||||||
// Ephemeral secret for ECDHE key exchange
|
// Ephemeral secret for ECDHE key exchange
|
||||||
ecdhe_secret: Option<EphemeralSecret>,
|
ecdhe_secret: Option<(EphemeralSecret, x25519_dalek::EphemeralSecret)>,
|
||||||
// Block ciphers for client & server
|
// Block ciphers for client & server
|
||||||
client_handshake_cipher: Option<Cipher>,
|
client_handshake_cipher: Option<Cipher>,
|
||||||
server_handshake_cipher: Option<Cipher>,
|
server_handshake_cipher: Option<Cipher>,
|
||||||
|
@ -101,6 +101,7 @@ impl Session {
|
||||||
pub(crate) fn client_update_for_ch(
|
pub(crate) fn client_update_for_ch(
|
||||||
&mut self,
|
&mut self,
|
||||||
ecdhe_secret: EphemeralSecret,
|
ecdhe_secret: EphemeralSecret,
|
||||||
|
x25519_secret: x25519_dalek::EphemeralSecret,
|
||||||
session_id: [u8; 32],
|
session_id: [u8; 32],
|
||||||
ch_slice: &[u8]
|
ch_slice: &[u8]
|
||||||
) {
|
) {
|
||||||
|
@ -108,7 +109,7 @@ impl Session {
|
||||||
if self.state != TlsState::START || self.role != TlsRole::Client {
|
if self.state != TlsState::START || self.role != TlsRole::Client {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
self.ecdhe_secret = Some(ecdhe_secret);
|
self.ecdhe_secret = Some((ecdhe_secret, x25519_secret));
|
||||||
self.session_id = Some(session_id);
|
self.session_id = Some(session_id);
|
||||||
self.hash.update(ch_slice);
|
self.hash.update(ch_slice);
|
||||||
self.state = TlsState::WAIT_SH;
|
self.state = TlsState::WAIT_SH;
|
||||||
|
@ -120,7 +121,8 @@ impl Session {
|
||||||
pub(crate) fn client_update_for_sh(
|
pub(crate) fn client_update_for_sh(
|
||||||
&mut self,
|
&mut self,
|
||||||
cipher_suite: CipherSuite,
|
cipher_suite: CipherSuite,
|
||||||
encoded_point: EncodedPoint,
|
encoded_point: Option<EncodedPoint>,
|
||||||
|
x25519_shared: Option<x25519_dalek::PublicKey>,
|
||||||
sh_slice: &[u8]
|
sh_slice: &[u8]
|
||||||
) {
|
) {
|
||||||
// Handle inappropriate call to move state
|
// Handle inappropriate call to move state
|
||||||
|
@ -129,12 +131,34 @@ impl Session {
|
||||||
}
|
}
|
||||||
// Generate ECDHE shared secret
|
// Generate ECDHE shared secret
|
||||||
// Remove private secret
|
// Remove private secret
|
||||||
let ecdhe_shared_secret =
|
// let ecdhe_shared_secret =
|
||||||
|
// self.ecdhe_secret
|
||||||
|
// .take()
|
||||||
|
// .unwrap()
|
||||||
|
// .diffie_hellman(&encoded_point)
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
|
let mut shared_secret_bytes: [u8; 32] = [0; 32];
|
||||||
|
if encoded_point.is_some() {
|
||||||
|
let p256_shared_secret =
|
||||||
self.ecdhe_secret
|
self.ecdhe_secret
|
||||||
.take()
|
.take()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.diffie_hellman(&encoded_point)
|
.0
|
||||||
|
.diffie_hellman(&encoded_point.unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
shared_secret_bytes.clone_from_slice(p256_shared_secret.as_bytes());
|
||||||
|
} else if x25519_shared.is_some() {
|
||||||
|
let x25519_shared_secret =
|
||||||
|
self.ecdhe_secret
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.diffie_hellman(&x25519_shared.unwrap());
|
||||||
|
shared_secret_bytes.clone_from_slice(x25519_shared_secret.as_bytes());
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
// Generate Handshake secret
|
// Generate Handshake secret
|
||||||
match cipher_suite {
|
match cipher_suite {
|
||||||
|
@ -161,7 +185,7 @@ impl Session {
|
||||||
let (handshake_secret, handshake_secret_hkdf) =
|
let (handshake_secret, handshake_secret_hkdf) =
|
||||||
Hkdf::<Sha256>::extract(
|
Hkdf::<Sha256>::extract(
|
||||||
Some(&derived_secret),
|
Some(&derived_secret),
|
||||||
ecdhe_shared_secret.as_bytes()
|
&shared_secret_bytes
|
||||||
);
|
);
|
||||||
|
|
||||||
// Store the handshake secret
|
// Store the handshake secret
|
||||||
|
@ -349,7 +373,7 @@ impl Session {
|
||||||
let (handshake_secret, handshake_secret_hkdf) =
|
let (handshake_secret, handshake_secret_hkdf) =
|
||||||
Hkdf::<Sha384>::extract(
|
Hkdf::<Sha384>::extract(
|
||||||
Some(&derived_secret),
|
Some(&derived_secret),
|
||||||
ecdhe_shared_secret.as_bytes()
|
&shared_secret_bytes
|
||||||
);
|
);
|
||||||
|
|
||||||
// Store the handshake secret
|
// Store the handshake secret
|
||||||
|
|
45
src/tls.rs
45
src/tls.rs
|
@ -126,12 +126,13 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
// Prepare field that is randomised,
|
// Prepare field that is randomised,
|
||||||
// Supply it to the TLS repr builder.
|
// Supply it to the TLS repr builder.
|
||||||
let ecdh_secret = EphemeralSecret::random(&mut self.rng);
|
let ecdh_secret = EphemeralSecret::random(&mut self.rng);
|
||||||
|
let x25519_secret = x25519_dalek::EphemeralSecret::new(&mut self.rng);
|
||||||
let mut random: [u8; 32] = [0; 32];
|
let mut random: [u8; 32] = [0; 32];
|
||||||
let mut session_id: [u8; 32] = [0; 32];
|
let mut session_id: [u8; 32] = [0; 32];
|
||||||
self.rng.fill_bytes(&mut random);
|
self.rng.fill_bytes(&mut random);
|
||||||
self.rng.fill_bytes(&mut session_id);
|
self.rng.fill_bytes(&mut session_id);
|
||||||
let repr = TlsRepr::new()
|
let repr = TlsRepr::new()
|
||||||
.client_hello(&ecdh_secret, random, session_id.clone());
|
.client_hello(&ecdh_secret, &x25519_secret, random, session_id.clone());
|
||||||
|
|
||||||
// Update hash function with client hello handshake
|
// Update hash function with client hello handshake
|
||||||
let mut array = [0; 512];
|
let mut array = [0; 512];
|
||||||
|
@ -145,6 +146,7 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
// Update TLS session
|
// Update TLS session
|
||||||
self.session.borrow_mut().client_update_for_ch(
|
self.session.borrow_mut().client_update_for_ch(
|
||||||
ecdh_secret,
|
ecdh_secret,
|
||||||
|
x25519_secret,
|
||||||
session_id,
|
session_id,
|
||||||
&slice[5..]
|
&slice[5..]
|
||||||
);
|
);
|
||||||
|
@ -313,7 +315,6 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
if repr.is_server_hello() {
|
if repr.is_server_hello() {
|
||||||
// Check SH content:
|
// Check SH content:
|
||||||
// random: Cannot represent HelloRequestRetry
|
// random: Cannot represent HelloRequestRetry
|
||||||
// (TODO: Support other key shares, e.g. X25519)
|
|
||||||
// session_id_echo: should be same as the one sent by client
|
// session_id_echo: should be same as the one sent by client
|
||||||
// cipher_suite: Store
|
// cipher_suite: Store
|
||||||
// (TODO: Check if such suite was offered)
|
// (TODO: Check if such suite was offered)
|
||||||
|
@ -321,11 +322,11 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
//
|
//
|
||||||
// Check extensions:
|
// Check extensions:
|
||||||
// supported_version: Must be TLS 1.3
|
// supported_version: Must be TLS 1.3
|
||||||
// key_share: Store key, must be in secp256r1
|
// key_share: Store key, must be in secp256r1 or x25519
|
||||||
// (TODO: Support other key shares ^)
|
|
||||||
|
|
||||||
// "Cache" for ECDHE server public info
|
// "Cache" for ECDHE server public info
|
||||||
let mut server_public: Option<EncodedPoint> = None;
|
let mut p256_public: Option<EncodedPoint> = None;
|
||||||
|
let mut x25519_public: Option<x25519_dalek::PublicKey> = None;
|
||||||
let mut selected_cipher: Option<CipherSuite> = None;
|
let mut selected_cipher: Option<CipherSuite> = None;
|
||||||
|
|
||||||
// Process the handshake data within ServerHello
|
// Process the handshake data within ServerHello
|
||||||
|
@ -377,22 +378,25 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
server_share
|
server_share
|
||||||
}
|
}
|
||||||
) = &extension.extension_data {
|
) = &extension.extension_data {
|
||||||
// TODO: Use legitimate checking to ensure the chosen
|
match server_share.group {
|
||||||
// group is indeed acceptable, when allowing more (EC)DHE
|
NamedGroup::secp256r1 => {
|
||||||
// key sharing
|
p256_public.replace(
|
||||||
if server_share.group != NamedGroup::secp256r1 {
|
|
||||||
// Abort for wrong key sharing
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
// Store key
|
|
||||||
// It is surely from secp256r1, no other groups are permitted
|
|
||||||
// Convert untagged bytes into encoded point on p256 eliptic curve
|
|
||||||
// Slice the first byte out of the bytes
|
|
||||||
server_public.replace(
|
|
||||||
EncodedPoint::from_untagged_bytes(
|
EncodedPoint::from_untagged_bytes(
|
||||||
GenericArray::from_slice(&server_share.key_exchange[1..])
|
GenericArray::from_slice(&server_share.key_exchange[1..])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
NamedGroup::x25519 => {
|
||||||
|
let mut x25519_server_key: [u8; 32] = [0; 32];
|
||||||
|
x25519_server_key.clone_from_slice(&server_share.key_exchange);
|
||||||
|
x25519_public.replace(
|
||||||
|
x25519_dalek::PublicKey::from(
|
||||||
|
x25519_server_key
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,8 +406,8 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that both selected_cipher and server_public were received
|
// Check that both selected_cipher and (p256_public XNOR x25519_public) were received
|
||||||
if selected_cipher.is_none() || server_public.is_none() {
|
if selected_cipher.is_none() || (p256_public.is_none() && x25519_public.is_none()) {
|
||||||
// Abort communication
|
// Abort communication
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
@ -412,7 +416,8 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
let mut session = self.session.borrow_mut();
|
let mut session = self.session.borrow_mut();
|
||||||
session.client_update_for_sh(
|
session.client_update_for_sh(
|
||||||
selected_cipher.unwrap(),
|
selected_cipher.unwrap(),
|
||||||
server_public.unwrap(),
|
p256_public,
|
||||||
|
x25519_public,
|
||||||
handshake_slice
|
handshake_slice
|
||||||
);
|
);
|
||||||
// Key exchange occurred, seq_num is set to 0
|
// Key exchange occurred, seq_num is set to 0
|
||||||
|
|
|
@ -59,14 +59,14 @@ impl<'a> TlsRepr<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn client_hello(mut self, secret: &EphemeralSecret, random: [u8; 32], session_id: [u8; 32]) -> Self {
|
pub(crate) fn client_hello(mut self, p256_secret: &EphemeralSecret, x25519_secret: &x25519_dalek::EphemeralSecret, random: [u8; 32], session_id: [u8; 32]) -> Self {
|
||||||
self.content_type = TlsContentType::Handshake;
|
self.content_type = TlsContentType::Handshake;
|
||||||
self.version = TlsVersion::Tls10;
|
self.version = TlsVersion::Tls10;
|
||||||
let handshake_repr = {
|
let handshake_repr = {
|
||||||
let mut repr = HandshakeRepr::new();
|
let mut repr = HandshakeRepr::new();
|
||||||
repr.msg_type = HandshakeType::ClientHello;
|
repr.msg_type = HandshakeType::ClientHello;
|
||||||
repr.handshake_data = HandshakeData::ClientHello({
|
repr.handshake_data = HandshakeData::ClientHello({
|
||||||
ClientHello::new(secret, random, session_id)
|
ClientHello::new(p256_secret, x25519_secret, random, session_id)
|
||||||
});
|
});
|
||||||
repr.length = repr.handshake_data.get_length().try_into().unwrap();
|
repr.length = repr.handshake_data.get_length().try_into().unwrap();
|
||||||
repr
|
repr
|
||||||
|
@ -252,7 +252,7 @@ impl<'a> HandshakeData<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ClientHello<'a> {
|
impl<'a> ClientHello<'a> {
|
||||||
pub(self) fn new(secret: &EphemeralSecret, random: [u8; 32], session_id: [u8; 32]) -> Self {
|
pub(self) fn new(p256_secret: &EphemeralSecret, x25519_secret: &x25519_dalek::EphemeralSecret, random: [u8; 32], session_id: [u8; 32]) -> Self {
|
||||||
let mut client_hello = ClientHello {
|
let mut client_hello = ClientHello {
|
||||||
version: TlsVersion::Tls12,
|
version: TlsVersion::Tls12,
|
||||||
random,
|
random,
|
||||||
|
@ -274,7 +274,7 @@ impl<'a> ClientHello<'a> {
|
||||||
|
|
||||||
client_hello.add_ch_supported_versions()
|
client_hello.add_ch_supported_versions()
|
||||||
.add_sig_algs()
|
.add_sig_algs()
|
||||||
.add_client_groups_with_key_shares(secret)
|
.add_client_groups_with_key_shares(p256_secret, x25519_secret)
|
||||||
.finalise()
|
.finalise()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,9 +354,10 @@ impl<'a> ClientHello<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_client_groups_with_key_shares(mut self, ecdh_secret: &EphemeralSecret) -> Self {
|
pub(crate) fn add_client_groups_with_key_shares(mut self, ecdh_secret: &EphemeralSecret, x25519_secret: &x25519_dalek::EphemeralSecret) -> Self {
|
||||||
// List out all supported groups
|
// List out all supported groups
|
||||||
let mut list = Vec::new();
|
let mut list = Vec::new();
|
||||||
|
list.push(NamedGroup::x25519);
|
||||||
list.push(NamedGroup::secp256r1);
|
list.push(NamedGroup::secp256r1);
|
||||||
|
|
||||||
let length = list.len()*2;
|
let length = list.len()*2;
|
||||||
|
@ -384,6 +385,19 @@ impl<'a> ClientHello<'a> {
|
||||||
key_exchange
|
key_exchange
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NamedGroup::x25519 => {
|
||||||
|
let x25519_public = x25519_dalek::PublicKey::from(x25519_secret);
|
||||||
|
key_exchange.extend_from_slice(x25519_public.as_bytes());
|
||||||
|
|
||||||
|
let key_exchange_length = key_exchange.len();
|
||||||
|
|
||||||
|
KeyShareEntry {
|
||||||
|
group: *named_group,
|
||||||
|
length: key_exchange_length.try_into().unwrap(),
|
||||||
|
key_exchange
|
||||||
|
}
|
||||||
|
}
|
||||||
// TODO: Implement keygen for other named groups
|
// TODO: Implement keygen for other named groups
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue