tls: add client hello processing

master
occheung 2020-11-26 12:30:16 +08:00
parent e6d41dea80
commit 27800091d4
2 changed files with 144 additions and 18 deletions

View File

@ -44,6 +44,10 @@ pub(crate) struct Session<'a> {
hash: Hash,
// Ephemeral secret for ECDHE key exchange
ecdhe_secret: Option<(EphemeralSecret, x25519_dalek::EphemeralSecret)>,
// Public key received from client side when listening
ecdhe_public: Option<DiffieHellmanPublicKey>,
// Server selected cipher_suite, but without enough keying info
server_selected_cipher: Option<CipherSuite>,
// Block ciphers for client & server
client_handshake_cipher: Option<Cipher>,
server_handshake_cipher: Option<Cipher>,
@ -98,6 +102,8 @@ impl<'a> Session<'a> {
latest_secret: None,
hash,
ecdhe_secret: None,
ecdhe_public: None,
server_selected_cipher: None,
client_handshake_cipher: None,
server_handshake_cipher: None,
client_application_cipher: None,
@ -1156,6 +1162,42 @@ impl<'a> Session<'a> {
self.state = TlsState::CLIENT_CONNECTED;
}
pub(crate) fn server_update_for_begin(
&mut self,
cipher_suite: CipherSuite,
client_ecdhe_public_key: DiffieHellmanPublicKey,
session_id: [u8; 32],
server_signature_algorithm: SignatureScheme,
client_hello_slice: &[u8]
)
{
self.ecdhe_public.replace(client_ecdhe_public_key);
self.session_id.replace(session_id);
self.client_cert_verify_sig_alg.replace(server_signature_algorithm);
self.server_selected_cipher.replace(cipher_suite);
// Choose a hash algorithm based on the selected cipher_suite
self.hash = match cipher_suite {
CipherSuite::TLS_AES_128_CCM_SHA256 |
CipherSuite::TLS_CHACHA20_POLY1305_SHA256 |
CipherSuite::TLS_AES_128_GCM_SHA256 => {
Hash::select_sha256(self.hash.clone())
},
CipherSuite::TLS_AES_256_GCM_SHA384 => {
Hash::select_sha384(self.hash.clone())
},
// The remaining CCM_8 is not supported
_ => {
unreachable!()
}
};
// Update hash with the received client hello
self.hash.update(client_hello_slice);
// Update FSM state of TLS
self.state = TlsState::NEGOTIATED;
}
pub(crate) fn verify_session_id_echo(&self, session_id_echo: &[u8]) -> bool {
if let Some(session_id_inner) = self.session_id {
session_id_inner == session_id_echo
@ -1196,6 +1238,16 @@ impl<'a> Session<'a> {
}
}
// Motivation: To know if offered signature algorithms
// can indeed be supported
pub(crate) fn get_certificate_private_key(&self) -> Option<&CertificatePrivateKey> {
if let Some((private_key, _)) = &self.cert_private_key {
Some(private_key)
} else {
None
}
}
pub(crate) fn get_client_certificate_verify_signature<R: rand_core::RngCore>(&self, rng: &mut R)
-> (crate::tls_packet::SignatureScheme, alloc::vec::Vec<u8>)
{
@ -1910,3 +1962,12 @@ pub enum CertificatePrivateKey {
cert_eddsa_key: ed25519_dalek::SecretKey
}
}
pub enum DiffieHellmanPublicKey {
SECP256R1 {
encoded_point: p256::EncodedPoint
},
X25519 {
public_key: x25519_dalek::PublicKey
}
}

View File

@ -31,7 +31,7 @@ use crate::parse::{
get_content_type_inner_plaintext
};
use crate::buffer::TlsBuffer;
use crate::session::{Session, TlsRole};
use crate::session::{Session, TlsRole, DiffieHellmanPublicKey};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[allow(non_camel_case_types)]
@ -952,9 +952,10 @@ impl<'s> TlsSocket<'s> {
let mut version_check = false;
let mut offered_p256 = false;
let mut offered_x25519 = false;
let mut p256_public_key: Option<p256::EncodedPoint> = None;
let mut x25519_public_key: Option<x25519_dalek::PublicKey> = None;
let mut signature_schemes: Vec<SignatureScheme> = Vec::new();
// let mut p256_public_key: Option<p256::EncodedPoint> = None;
// let mut x25519_public_key: Option<x25519_dalek::PublicKey> = None;
let mut ecdhe_public_key: Option<DiffieHellmanPublicKey> = None;
let mut signature_algorithm: Option<SignatureScheme> = None;
// Verify that TLS 1.3 is offered by the client
if let Some(supported_version_extension) = client_hello.extensions.iter().find(
@ -1035,18 +1036,20 @@ impl<'s> TlsSocket<'s> {
key.group == NamedGroup::secp256r1
}
) {
p256_public_key.replace(
p256::EncodedPoint::from_untagged_bytes(
GenericArray::from_slice(
&p256_key.key_exchange[1..]
ecdhe_public_key.replace(
DiffieHellmanPublicKey::SECP256R1 {
encoded_point: p256::EncodedPoint::from_untagged_bytes(
GenericArray::from_slice(
&p256_key.key_exchange[1..]
)
)
)
}
);
}
}
// Then try X25519, if P-256 key is not found and x25519 is offered
if offered_x25519 && p256_public_key.is_none() {
if offered_x25519 && ecdhe_public_key.is_none() {
if let Some(x25519_key) = client_shares.iter().find(
|key| {
key.group == NamedGroup::x25519
@ -1056,17 +1059,19 @@ impl<'s> TlsSocket<'s> {
let mut key_content: [u8; 32] = [0; 32];
key_content.clone_from_slice(&x25519_key.key_exchange);
x25519_public_key.replace(
x25519_dalek::PublicKey::from(
key_content
)
ecdhe_public_key.replace(
DiffieHellmanPublicKey::X25519 {
public_key: x25519_dalek::PublicKey::from(
key_content
)
}
);
}
}
// If there are no applicable offered client key,
// consider sending a ClientHelloRetry
if p256_public_key.is_none() && x25519_public_key.is_none() {
if ecdhe_public_key.is_none() {
todo!()
}
} else {
@ -1087,16 +1092,76 @@ impl<'s> TlsSocket<'s> {
if let ExtensionData::SignatureAlgorithms(
SignatureSchemeList { supported_signature_algorithms, .. }
) = &signature_algorithms.extension_data {
signature_schemes.extend_from_slice(supported_signature_algorithms);
// Check compatibility of signature algorithms
if let Some(certificate_private_key) = self.session.borrow().get_certificate_private_key() {
use crate::session::CertificatePrivateKey::*;
if let Some(server_signature_algorithm) = match certificate_private_key {
// Try RSA keys:
RSA { .. } => {
supported_signature_algorithms.iter().find(
|&&signature_algorithm| {
signature_algorithm == SignatureScheme::rsa_pkcs1_sha256 ||
signature_algorithm == SignatureScheme::rsa_pkcs1_sha384 ||
signature_algorithm == SignatureScheme::rsa_pkcs1_sha512 ||
signature_algorithm == SignatureScheme::rsa_pss_rsae_sha256 ||
signature_algorithm == SignatureScheme::rsa_pss_rsae_sha384 ||
signature_algorithm == SignatureScheme::rsa_pss_rsae_sha512 ||
signature_algorithm == SignatureScheme::rsa_pss_pss_sha256 ||
signature_algorithm == SignatureScheme::rsa_pss_pss_sha384 ||
signature_algorithm == SignatureScheme::rsa_pss_pss_sha512
}
)
},
ECDSA_SECP256R1_SHA256 { .. } => {
supported_signature_algorithms.iter().find(
|&&signature_algorithm| {
signature_algorithm == SignatureScheme::ecdsa_secp256r1_sha256
}
)
},
ED25519 { .. } => {
supported_signature_algorithms.iter().find(
|&&signature_algorithm| {
signature_algorithm == SignatureScheme::ed25519
}
)
}
} {
signature_algorithm = Some(*server_signature_algorithm);
} else {
// Cannot find a suitable signature algorithm for the server side
// Terminate the negotiation with alert
todo!()
}
} else {
// Server must have a certificate ready
// Through this should be enforced when entering listening stage
unreachable!()
}
} else {
// Malformed packet, type does not match content
todo!()
}
} else {
// Will only accept authentication through certificate
// Send alert if there are no signature algorithms extension
todo!()
}
}
log::info!("Received client hello");
{
let mut session = self.session.borrow_mut();
session.server_update_for_begin(
*accepted_cipher_suite,
ecdhe_public_key.unwrap(),
session_id,
signature_algorithm.unwrap(),
handshake_slice
)
}
log::info!("Processed client hello")
}
}
_ => {},