From 0042fea902ff69fe8de62ee2207264e97daebec0 Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 28 Oct 2020 17:33:00 +0800 Subject: [PATCH] cert: add key verify --- Cargo.toml | 3 +- src/certificate.rs | 67 +++++++++++++++++- src/lib.rs | 5 +- src/main.rs | 40 +++++++++-- src/parse.rs | 164 +++++++++++++++++++++++++++++++++++---------- src/session.rs | 16 ++++- src/tls.rs | 91 +++++++++++++++++++++---- src/tls_packet.rs | 49 ++++++++++++++ 8 files changed, 378 insertions(+), 57 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7957703..24359a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,8 @@ edition = "2018" [dependencies] hkdf = "0.9.0" -sha2 = { version = "0.9.1", default-features = false } +sha-1 = { version = "0.9.1", default-features = false } +sha2 = { version = "0.9.1", default-features = false } byteorder = { version = "1.3.4", default-features = false } num_enum = { version = "0.5.1", default-features = false } log = "0.4.11" diff --git a/src/certificate.rs b/src/certificate.rs index 73a8e23..91c93a2 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -1,13 +1,21 @@ use num_enum::IntoPrimitive; use num_enum::TryFromPrimitive; +use crate::parse::parse_asn1_der_object; +use crate::parse::parse_asn1_der_rsa_public_key; +use crate::Error as TlsError; + +use sha1::{Sha1, Digest}; +use rsa::{PublicKey, RSAPublicKey, PaddingScheme, BigUint, Hash}; + use alloc::vec::Vec; #[derive(Debug, Clone)] pub struct Certificate<'a> { pub tbs_certificate: TBSCertificate<'a>, pub signature_algorithm: AlgorithmIdentifier<'a>, - pub signature_value: &'a [u8] + pub signature_value: &'a [u8], + pub tbs_certificate_encoded: &'a [u8], } #[derive(Debug, Clone)] @@ -129,3 +137,60 @@ pub struct AlgorithmIdentifier<'a> { pub algorithm: &'a [u8], pub parameters: &'a [u8], } + +// TODO: MOve this to impl block of Certificate +// Verify self-signed root certificate parsed certificate +pub fn validate_root_certificate(cert: &Certificate) -> Result { + // Verify Signature + match cert.signature_algorithm.algorithm { + SHA1_WITH_RSA_ENCRYPTION => { + let mut hasher = Sha1::new(); + hasher.update(cert.tbs_certificate_encoded); + + // TODO: invoke method to get public key + let (_, (modulus, exponent)) = parse_asn1_der_rsa_public_key( + cert.tbs_certificate.subject_public_key_info.subject_public_key + ).map_err(|_| TlsError::ParsingError)?; + + let rsa_public_key = RSAPublicKey::new( + BigUint::from_bytes_be(modulus), + BigUint::from_bytes_be(exponent) + ).map_err(|_| TlsError::SignatureValidationError)?; + + let padding = PaddingScheme::new_pkcs1v15_sign(Some(Hash::SHA1)); + let verify_result = rsa_public_key.verify( + padding, + &hasher.finalize(), + cert.signature_value + ); + log::info!("Verification result: {:?}", verify_result); + Ok(verify_result.is_ok()) + } + _ => { + todo!() + } + } +} + +impl<'a> Certificate<'a> { + // Return the public key, if used for RSA + pub fn return_rsa_public_key(&self) -> Result { + if self.signature_algorithm.algorithm != oid::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(|_| ()) + } +} + +mod oid { + // ECDSA signature algorithms + pub const SHA1_WITH_RSA_ENCRYPTION: &'static [u8] = &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05]; +} + diff --git a/src/lib.rs b/src/lib.rs index a9b938f..bbf80de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ #![no_std] -#[macro_use] extern crate alloc; pub mod tls; @@ -15,10 +14,12 @@ use nom::error::ParseError; // TODO: Implement errors // Details: Encapsulate smoltcp & nom errors +#[derive(Debug, Clone)] pub enum Error { PropagatedError(smoltcp::Error), - ParsingError(nom::error::ErrorKind), + ParsingError, EncryptionError, DecryptionError, CapacityError, + SignatureValidationError, } diff --git a/src/main.rs b/src/main.rs index c9844f5..fc2c417 100644 --- a/src/main.rs +++ b/src/main.rs @@ -97,15 +97,45 @@ fn main() { ).unwrap(); println!("{:X?}", public_key); - let hash = sha2::Sha256::new().chain(&CERTIFICATE[4..(0x209+8)]).finalize(); + let transcript_hash = sha2::Sha256::new() + .chain(&CLIENT_HELLO) + .chain(&SERVER_HELLO) + .chain(&ENCRYPTED_EXTENSION) + .chain(&CERTIFICATE) + .finalize(); + println!("Transcript: {:X?}", transcript_hash); + + let hash = sha2::Sha256::new() + .chain(&MANY20) + .chain(&CONTEXT_STRING) + .chain(&SINGLE_ZERO_BYTE) + .chain(&transcript_hash) + .finalize(); + println!("Hash: {:X?}", hash); - let padding = PaddingScheme::new_pkcs1v15_sign(Some(Hash::SHA2_256)); - println!("Sig Verify: {:?}", public_key.verify(padding, &hash, &SIGNATURE)); + let padding = PaddingScheme::new_pss::(rng); + println!("Sig Verify: {:?}", public_key.verify(padding, &hash, &VERIFY_SIGNATURE)); } -const CERTIFICATE: [u8; 0x325] = [ - 0x30, 0x82, 0x03, 0x21, 0x30, 0x82, 0x02, 0x09, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x15, 0x5a, 0x92, 0xad, 0xc2, 0x04, 0x8f, 0x90, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x22, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x30, 0x30, 0x35, 0x30, 0x31, 0x33, 0x38, 0x31, 0x37, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x30, 0x35, 0x30, 0x31, 0x33, 0x38, 0x31, 0x37, 0x5a, 0x30, 0x2b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x75, 0x6c, 0x66, 0x68, 0x65, 0x69, 0x6d, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc4, 0x80, 0x36, 0x06, 0xba, 0xe7, 0x47, 0x6b, 0x08, 0x94, 0x04, 0xec, 0xa7, 0xb6, 0x91, 0x04, 0x3f, 0xf7, 0x92, 0xbc, 0x19, 0xee, 0xfb, 0x7d, 0x74, 0xd7, 0xa8, 0x0d, 0x00, 0x1e, 0x7b, 0x4b, 0x3a, 0x4a, 0xe6, 0x0f, 0xe8, 0xc0, 0x71, 0xfc, 0x73, 0xe7, 0x02, 0x4c, 0x0d, 0xbc, 0xf4, 0xbd, 0xd1, 0x1d, 0x39, 0x6b, 0xba, 0x70, 0x46, 0x4a, 0x13, 0xe9, 0x4a, 0xf8, 0x3d, 0xf3, 0xe1, 0x09, 0x59, 0x54, 0x7b, 0xc9, 0x55, 0xfb, 0x41, 0x2d, 0xa3, 0x76, 0x52, 0x11, 0xe1, 0xf3, 0xdc, 0x77, 0x6c, 0xaa, 0x53, 0x37, 0x6e, 0xca, 0x3a, 0xec, 0xbe, 0xc3, 0xaa, 0xb7, 0x3b, 0x31, 0xd5, 0x6c, 0xb6, 0x52, 0x9c, 0x80, 0x98, 0xbc, 0xc9, 0xe0, 0x28, 0x18, 0xe2, 0x0b, 0xf7, 0xf8, 0xa0, 0x3a, 0xfd, 0x17, 0x04, 0x50, 0x9e, 0xce, 0x79, 0xbd, 0x9f, 0x39, 0xf1, 0xea, 0x69, 0xec, 0x47, 0x97, 0x2e, 0x83, 0x0f, 0xb5, 0xca, 0x95, 0xde, 0x95, 0xa1, 0xe6, 0x04, 0x22, 0xd5, 0xee, 0xbe, 0x52, 0x79, 0x54, 0xa1, 0xe7, 0xbf, 0x8a, 0x86, 0xf6, 0x46, 0x6d, 0x0d, 0x9f, 0x16, 0x95, 0x1a, 0x4c, 0xf7, 0xa0, 0x46, 0x92, 0x59, 0x5c, 0x13, 0x52, 0xf2, 0x54, 0x9e, 0x5a, 0xfb, 0x4e, 0xbf, 0xd7, 0x7a, 0x37, 0x95, 0x01, 0x44, 0xe4, 0xc0, 0x26, 0x87, 0x4c, 0x65, 0x3e, 0x40, 0x7d, 0x7d, 0x23, 0x07, 0x44, 0x01, 0xf4, 0x84, 0xff, 0xd0, 0x8f, 0x7a, 0x1f, 0xa0, 0x52, 0x10, 0xd1, 0xf4, 0xf0, 0xd5, 0xce, 0x79, 0x70, 0x29, 0x32, 0xe2, 0xca, 0xbe, 0x70, 0x1f, 0xdf, 0xad, 0x6b, 0x4b, 0xb7, 0x11, 0x01, 0xf4, 0x4b, 0xad, 0x66, 0x6a, 0x11, 0x13, 0x0f, 0xe2, 0xee, 0x82, 0x9e, 0x4d, 0x02, 0x9d, 0xc9, 0x1c, 0xdd, 0x67, 0x16, 0xdb, 0xb9, 0x06, 0x18, 0x86, 0xed, 0xc1, 0xba, 0x94, 0x21, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x52, 0x30, 0x50, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x89, 0x4f, 0xde, 0x5b, 0xcc, 0x69, 0xe2, 0x52, 0xcf, 0x3e, 0xa3, 0x00, 0xdf, 0xb1, 0x97, 0xb8, 0x1d, 0xe1, 0xc1, 0x46, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x59, 0x16, 0x45, 0xa6, 0x9a, 0x2e, 0x37, 0x79, 0xe4, 0xf6, 0xdd, 0x27, 0x1a, 0xba, 0x1c, 0x0b, 0xfd, 0x6c, 0xd7, 0x55, 0x99, 0xb5, 0xe7, 0xc3, 0x6e, 0x53, 0x3e, 0xff, 0x36, 0x59, 0x08, 0x43, 0x24, 0xc9, 0xe7, 0xa5, 0x04, 0x07, 0x9d, 0x39, 0xe0, 0xd4, 0x29, 0x87, 0xff, 0xe3, 0xeb, 0xdd, 0x09, 0xc1, 0xcf, 0x1d, 0x91, 0x44, 0x55, 0x87, 0x0b, 0x57, 0x1d, 0xd1, 0x9b, 0xdf, 0x1d, 0x24, 0xf8, 0xbb, 0x9a, 0x11, 0xfe, 0x80, 0xfd, 0x59, 0x2b, 0xa0, 0x39, 0x8c, 0xde, 0x11, 0xe2, 0x65, 0x1e, 0x61, 0x8c, 0xe5, 0x98, 0xfa, 0x96, 0xe5, 0x37, 0x2e, 0xef, 0x3d, 0x24, 0x8a, 0xfd, 0xe1, 0x74, 0x63, 0xeb, 0xbf, 0xab, 0xb8, 0xe4, 0xd1, 0xab, 0x50, 0x2a, 0x54, 0xec, 0x00, 0x64, 0xe9, 0x2f, 0x78, 0x19, 0x66, 0x0d, 0x3f, 0x27, 0xcf, 0x20, 0x9e, 0x66, 0x7f, 0xce, 0x5a, 0xe2, 0xe4, 0xac, 0x99, 0xc7, 0xc9, 0x38, 0x18, 0xf8, 0xb2, 0x51, 0x07, 0x22, 0xdf, 0xed, 0x97, 0xf3, 0x2e, 0x3e, 0x93, 0x49, 0xd4, 0xc6, 0x6c, 0x9e, 0xa6, 0x39, 0x6d, 0x74, 0x44, 0x62, 0xa0, 0x6b, 0x42, 0xc6, 0xd5, 0xba, 0x68, 0x8e, 0xac, 0x3a, 0x01, 0x7b, 0xdd, 0xfc, 0x8e, 0x2c, 0xfc, 0xad, 0x27, 0xcb, 0x69, 0xd3, 0xcc, 0xdc, 0xa2, 0x80, 0x41, 0x44, 0x65, 0xd3, 0xae, 0x34, 0x8c, 0xe0, 0xf3, 0x4a, 0xb2, 0xfb, 0x9c, 0x61, 0x83, 0x71, 0x31, 0x2b, 0x19, 0x10, 0x41, 0x64, 0x1c, 0x23, 0x7f, 0x11, 0xa5, 0xd6, 0x5c, 0x84, 0x4f, 0x04, 0x04, 0x84, 0x99, 0x38, 0x71, 0x2b, 0x95, 0x9e, 0xd6, 0x85, 0xbc, 0x5c, 0x5d, 0xd6, 0x45, 0xed, 0x19, 0x90, 0x94, 0x73, 0x40, 0x29, 0x26, 0xdc, 0xb4, 0x0e, 0x34, 0x69, 0xa1, 0x59, 0x41, 0xe8, 0xe2, 0xcc, 0xa8, 0x4b, 0xb6, 0x08, 0x46, 0x36, 0xa0 +const CLIENT_HELLO: [u8; 0xCA] = [ + 0x01, 0x00, 0x00, 0xc6, 0x03, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x06, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0x01, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x18, 0x00, 0x16, 0x00, 0x00, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x75, 0x6c, 0x66, 0x68, 0x65, 0x69, 0x6d, 0x2e, 0x6e, 0x65, 0x74, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x35, 0x80, 0x72, 0xd6, 0x36, 0x58, 0x80, 0xd1, 0xae, 0xea, 0x32, 0x9a, 0xdf, 0x91, 0x21, 0x38, 0x38, 0x51, 0xed, 0x21, 0xa2, 0x8e, 0x3b, 0x75, 0xe9, 0x65, 0xd0, 0xd2, 0xcd, 0x16, 0x62, 0x54, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04 +]; + +const SERVER_HELLO: [u8; 0x7A] = [ + 0x02, 0x00, 0x00, 0x76, 0x03, 0x03, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x20, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x9f, 0xd7, 0xad, 0x6d, 0xcf, 0xf4, 0x29, 0x8d, 0xd3, 0xf9, 0x6d, 0x5b, 0x1b, 0x2a, 0xf9, 0x10, 0xa0, 0x53, 0x5b, 0x14, 0x88, 0xd7, 0xf8, 0xfa, 0xbb, 0x34, 0x9a, 0x98, 0x28, 0x80, 0xb6, 0x15, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04 +]; + +const ENCRYPTED_EXTENSION: [u8; 6] = [0x08, 0x00, 0x00, 0x02, 0x00, 0x00]; + +const MANY20: [u8; 64] = [0x20; 64]; + +const CONTEXT_STRING: &'static str = "TLS 1.3, server CertificateVerify"; + +const SINGLE_ZERO_BYTE: [u8; 1] = [0]; + +const CERTIFICATE: [u8; 818] = [ + 0x0b, 0x00, 0x03, 0x2e, 0x00, 0x00, 0x03, 0x2a, 0x00, 0x03, 0x25, 0x30, 0x82, 0x03, 0x21, 0x30, 0x82, 0x02, 0x09, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x15, 0x5a, 0x92, 0xad, 0xc2, 0x04, 0x8f, 0x90, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x22, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x30, 0x30, 0x35, 0x30, 0x31, 0x33, 0x38, 0x31, 0x37, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x30, 0x35, 0x30, 0x31, 0x33, 0x38, 0x31, 0x37, 0x5a, 0x30, 0x2b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x75, 0x6c, 0x66, 0x68, 0x65, 0x69, 0x6d, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc4, 0x80, 0x36, 0x06, 0xba, 0xe7, 0x47, 0x6b, 0x08, 0x94, 0x04, 0xec, 0xa7, 0xb6, 0x91, 0x04, 0x3f, 0xf7, 0x92, 0xbc, 0x19, 0xee, 0xfb, 0x7d, 0x74, 0xd7, 0xa8, 0x0d, 0x00, 0x1e, 0x7b, 0x4b, 0x3a, 0x4a, 0xe6, 0x0f, 0xe8, 0xc0, 0x71, 0xfc, 0x73, 0xe7, 0x02, 0x4c, 0x0d, 0xbc, 0xf4, 0xbd, 0xd1, 0x1d, 0x39, 0x6b, 0xba, 0x70, 0x46, 0x4a, 0x13, 0xe9, 0x4a, 0xf8, 0x3d, 0xf3, 0xe1, 0x09, 0x59, 0x54, 0x7b, 0xc9, 0x55, 0xfb, 0x41, 0x2d, 0xa3, 0x76, 0x52, 0x11, 0xe1, 0xf3, 0xdc, 0x77, 0x6c, 0xaa, 0x53, 0x37, 0x6e, 0xca, 0x3a, 0xec, 0xbe, 0xc3, 0xaa, 0xb7, 0x3b, 0x31, 0xd5, 0x6c, 0xb6, 0x52, 0x9c, 0x80, 0x98, 0xbc, 0xc9, 0xe0, 0x28, 0x18, 0xe2, 0x0b, 0xf7, 0xf8, 0xa0, 0x3a, 0xfd, 0x17, 0x04, 0x50, 0x9e, 0xce, 0x79, 0xbd, 0x9f, 0x39, 0xf1, 0xea, 0x69, 0xec, 0x47, 0x97, 0x2e, 0x83, 0x0f, 0xb5, 0xca, 0x95, 0xde, 0x95, 0xa1, 0xe6, 0x04, 0x22, 0xd5, 0xee, 0xbe, 0x52, 0x79, 0x54, 0xa1, 0xe7, 0xbf, 0x8a, 0x86, 0xf6, 0x46, 0x6d, 0x0d, 0x9f, 0x16, 0x95, 0x1a, 0x4c, 0xf7, 0xa0, 0x46, 0x92, 0x59, 0x5c, 0x13, 0x52, 0xf2, 0x54, 0x9e, 0x5a, 0xfb, 0x4e, 0xbf, 0xd7, 0x7a, 0x37, 0x95, 0x01, 0x44, 0xe4, 0xc0, 0x26, 0x87, 0x4c, 0x65, 0x3e, 0x40, 0x7d, 0x7d, 0x23, 0x07, 0x44, 0x01, 0xf4, 0x84, 0xff, 0xd0, 0x8f, 0x7a, 0x1f, 0xa0, 0x52, 0x10, 0xd1, 0xf4, 0xf0, 0xd5, 0xce, 0x79, 0x70, 0x29, 0x32, 0xe2, 0xca, 0xbe, 0x70, 0x1f, 0xdf, 0xad, 0x6b, 0x4b, 0xb7, 0x11, 0x01, 0xf4, 0x4b, 0xad, 0x66, 0x6a, 0x11, 0x13, 0x0f, 0xe2, 0xee, 0x82, 0x9e, 0x4d, 0x02, 0x9d, 0xc9, 0x1c, 0xdd, 0x67, 0x16, 0xdb, 0xb9, 0x06, 0x18, 0x86, 0xed, 0xc1, 0xba, 0x94, 0x21, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x52, 0x30, 0x50, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x89, 0x4f, 0xde, 0x5b, 0xcc, 0x69, 0xe2, 0x52, 0xcf, 0x3e, 0xa3, 0x00, 0xdf, 0xb1, 0x97, 0xb8, 0x1d, 0xe1, 0xc1, 0x46, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x59, 0x16, 0x45, 0xa6, 0x9a, 0x2e, 0x37, 0x79, 0xe4, 0xf6, 0xdd, 0x27, 0x1a, 0xba, 0x1c, 0x0b, 0xfd, 0x6c, 0xd7, 0x55, 0x99, 0xb5, 0xe7, 0xc3, 0x6e, 0x53, 0x3e, 0xff, 0x36, 0x59, 0x08, 0x43, 0x24, 0xc9, 0xe7, 0xa5, 0x04, 0x07, 0x9d, 0x39, 0xe0, 0xd4, 0x29, 0x87, 0xff, 0xe3, 0xeb, 0xdd, 0x09, 0xc1, 0xcf, 0x1d, 0x91, 0x44, 0x55, 0x87, 0x0b, 0x57, 0x1d, 0xd1, 0x9b, 0xdf, 0x1d, 0x24, 0xf8, 0xbb, 0x9a, 0x11, 0xfe, 0x80, 0xfd, 0x59, 0x2b, 0xa0, 0x39, 0x8c, 0xde, 0x11, 0xe2, 0x65, 0x1e, 0x61, 0x8c, 0xe5, 0x98, 0xfa, 0x96, 0xe5, 0x37, 0x2e, 0xef, 0x3d, 0x24, 0x8a, 0xfd, 0xe1, 0x74, 0x63, 0xeb, 0xbf, 0xab, 0xb8, 0xe4, 0xd1, 0xab, 0x50, 0x2a, 0x54, 0xec, 0x00, 0x64, 0xe9, 0x2f, 0x78, 0x19, 0x66, 0x0d, 0x3f, 0x27, 0xcf, 0x20, 0x9e, 0x66, 0x7f, 0xce, 0x5a, 0xe2, 0xe4, 0xac, 0x99, 0xc7, 0xc9, 0x38, 0x18, 0xf8, 0xb2, 0x51, 0x07, 0x22, 0xdf, 0xed, 0x97, 0xf3, 0x2e, 0x3e, 0x93, 0x49, 0xd4, 0xc6, 0x6c, 0x9e, 0xa6, 0x39, 0x6d, 0x74, 0x44, 0x62, 0xa0, 0x6b, 0x42, 0xc6, 0xd5, 0xba, 0x68, 0x8e, 0xac, 0x3a, 0x01, 0x7b, 0xdd, 0xfc, 0x8e, 0x2c, 0xfc, 0xad, 0x27, 0xcb, 0x69, 0xd3, 0xcc, 0xdc, 0xa2, 0x80, 0x41, 0x44, 0x65, 0xd3, 0xae, 0x34, 0x8c, 0xe0, 0xf3, 0x4a, 0xb2, 0xfb, 0x9c, 0x61, 0x83, 0x71, 0x31, 0x2b, 0x19, 0x10, 0x41, 0x64, 0x1c, 0x23, 0x7f, 0x11, 0xa5, 0xd6, 0x5c, 0x84, 0x4f, 0x04, 0x04, 0x84, 0x99, 0x38, 0x71, 0x2b, 0x95, 0x9e, 0xd6, 0x85, 0xbc, 0x5c, 0x5d, 0xd6, 0x45, 0xed, 0x19, 0x90, 0x94, 0x73, 0x40, 0x29, 0x26, 0xdc, 0xb4, 0x0e, 0x34, 0x69, 0xa1, 0x59, 0x41, 0xe8, 0xe2, 0xcc, 0xa8, 0x4b, 0xb6, 0x08, 0x46, 0x36, 0xa0, 0x00, 0x00 ]; const PUBLIC_KEY: [u8; 256] = [ diff --git a/src/parse.rs b/src/parse.rs index 4ce56b2..ddb6b7c 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -78,7 +78,8 @@ pub(crate) fn parse_tls_repr(bytes: &[u8]) -> IResult<&[u8], TlsRepr> { // Diff from regular handshake: // 1. Handshake can coalesced into a larger TLS record // 2. Content type and zero paddings at the end -pub(crate) fn parse_inner_plaintext_for_handshake(bytes: &[u8]) -> IResult<&[u8], Vec> { +// Return handshake slice for hashing +pub(crate) fn parse_inner_plaintext_for_handshake(bytes: &[u8]) -> IResult<&[u8], (&[u8], Vec)> { let mut remaining_bytes = bytes; let mut handshake_vec: Vec = Vec::new(); @@ -97,7 +98,17 @@ pub(crate) fn parse_inner_plaintext_for_handshake(bytes: &[u8]) -> IResult<&[u8] take_till(|byte| byte != 0x00) ) )(remaining_bytes)?; - return Ok((&[], handshake_vec)); + return Ok(( + &[], + ( + // A concatenation of all handshakes received + // The remaining content_type byte and zero paddings are stripped + &bytes[ + ..(bytes.len()-remaining_bytes.len()) + ], + handshake_vec + ) + )); } let (rem, handshake_repr) = parse_handshake(remaining_bytes)?; @@ -154,7 +165,18 @@ pub(crate) fn parse_handshake(bytes: &[u8]) -> IResult<&[u8], HandshakeRepr> { ); Ok((rest, repr)) - } + }, + CertificateVerify => { + // Parse CertificateVerify + let (rest, handshake_data) = parse_certificate_verify( + rest + )?; + repr.handshake_data = HandshakeData::CertificateVerify( + handshake_data + ); + + Ok((rest, repr)) + }, _ => todo!() } } @@ -351,6 +373,33 @@ fn parse_handshake_certificate_entry_info(bytes: &[u8]) -> IResult<&[u8], (u32, )) } +fn parse_certificate_verify(bytes: &[u8]) -> IResult<&[u8], CertificateVerify> { + let signature_scheme = take(2_usize); + let signature_length = take(2_usize); + let (rest, (signature_scheme, signature_length)) = tuple(( + signature_scheme, + signature_length + ))(bytes)?; + + let signature_scheme = SignatureScheme::try_from( + NetworkEndian::read_u16(signature_scheme) + ).unwrap(); + let signature_length = NetworkEndian::read_u16(signature_length); + + let (_, signature) = complete( + take(signature_length) + )(rest)?; + + Ok(( + &[], + CertificateVerify { + algorithm: signature_scheme, + signature_length, + signature + } + )) +} + fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8], Extension> { let extension_type = take(2_usize); let length = take(2_usize); @@ -468,13 +517,18 @@ fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8] )) } -pub fn parse_asn1_der_header(bytes: &[u8]) -> IResult<&[u8], (u8, usize)> { +// Parse tag and length +// Return remaining bytes, tag (as byte), indicated length, +// and header (tag + length field) length +pub fn parse_asn1_der_header(bytes: &[u8]) -> IResult<&[u8], (u8, usize, usize)> { // Parse tag let (rest, tag) = take(1_usize)(bytes)?; // Parse length let (rest, length_byte) = take(1_usize)(rest)?; if length_byte[0] <= 0x7F { - Ok((rest, (tag[0], length_byte[0].into()))) + // Header length is 2 bytes + // Tag: 1; Length: 1 + Ok((rest, (tag[0], length_byte[0].into(), 2))) } else { if length_byte[0] & 0x7F > core::mem::size_of::().try_into().unwrap() { return Err(nom::Err::Failure((length_byte, ErrorKind::TooLarge))); @@ -487,21 +541,35 @@ pub fn parse_asn1_der_header(bytes: &[u8]) -> IResult<&[u8], (u8, usize)> { length_array[array_index + 8 - length_slice.len()] = length_slice[array_index]; } let (_, length_array) = length_array.split_at(8 - core::mem::size_of::()); - Ok((rem, (tag[0], usize::from_be_bytes((*length_array).try_into().unwrap())))) + + // Header length: + // Tag: 1; Length: long_form_indic (1) + size of length (length_size) + Ok(( + rem, + ( + tag[0], + usize::from_be_bytes((*length_array).try_into().unwrap()), + 1 + 1 + usize::try_from(length_size).unwrap() + ) + )) } } -// TODO: Not return length -// It is quite useless when the value slice of the exact same length is returned -// i.e. `length` can be replaced by `value.len()` +// Length: (return param) returns the length of the entire asn1_der_object +// Length of the value within the ASN.1 DER object = value.len() pub fn parse_asn1_der_object(bytes: &[u8]) -> IResult<&[u8], (u8, usize, &[u8])> { - let (rest, (tag, length)) = parse_asn1_der_header(bytes)?; + let (rest, (tag, length, header_size)) = parse_asn1_der_header(bytes)?; let (rest, value) = take(length)(rest)?; - Ok((rest, (tag, length, value))) + Ok((rest, (tag, length + header_size, value))) } pub fn parse_asn1_der_certificate(bytes: &[u8]) -> IResult<&[u8], Asn1DerCertificate> { let (excluded, (_, _, rest)) = parse_asn1_der_object(bytes)?; + + // Return encoded TBS certificate in ASN1 DER + // For convenience of validation + let tbs_certificate_encoded = rest; + let (_, (tbs_certificate, sig_alg, sig_value)) = complete( tuple(( parse_asn1_der_tbs_certificate, @@ -509,19 +577,24 @@ pub fn parse_asn1_der_certificate(bytes: &[u8]) -> IResult<&[u8], Asn1DerCertifi parse_asn1_der_bit_string )) )(rest)?; + + let (_, (_, tbs_certificate_length, _)) = + parse_asn1_der_object(tbs_certificate_encoded)?; + Ok(( excluded, Asn1DerCertificate { tbs_certificate, signature_algorithm: sig_alg, signature_value: sig_value, + tbs_certificate_encoded: &tbs_certificate_encoded[0..tbs_certificate_length] } )) } // Parser for TBSCertificate (Sequence: 0x30) pub fn parse_asn1_der_tbs_certificate(bytes: &[u8]) -> IResult<&[u8], Asn1DerTBSCertificate> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag is indeed 0x30 if tag_val != 0x30 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -566,7 +639,7 @@ pub fn parse_asn1_der_tbs_certificate(bytes: &[u8]) -> IResult<&[u8], Asn1DerTBS // Version encapsulates an Integer // i.e. context-specific, constructed, type [0] -> tag: A0 pub fn parse_asn1_der_version(bytes: &[u8]) -> IResult<&[u8], Asn1DerVersion> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag is indeed 0xA0 if tag_val != 0xA0 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -579,7 +652,7 @@ pub fn parse_asn1_der_version(bytes: &[u8]) -> IResult<&[u8], Asn1DerVersion> { // INTEGER: tag: 0x02 pub fn parse_asn1_der_integer(bytes: &[u8]) -> IResult<&[u8], &[u8]> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag is indeed 0x02 if tag_val != 0x02 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -591,7 +664,7 @@ pub fn parse_asn1_der_integer(bytes: &[u8]) -> IResult<&[u8], &[u8]> { // Assumption: No unused bits at the last byte // Public keys are always represented in bytes pub fn parse_asn1_der_bit_string(bytes: &[u8]) -> IResult<&[u8], &[u8]> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag is indeed 0x03 if tag_val != 0x03 { return Err(nom::Err::Error((bytes, ErrorKind::Verify))); @@ -609,10 +682,10 @@ pub fn parse_asn1_der_bit_string(bytes: &[u8]) -> IResult<&[u8], &[u8]> { // Length should be 1 // 0x00 -> false; 0xFF -> true pub fn parse_asn1_der_boolean(bytes: &[u8]) -> IResult<&[u8], bool> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag is indeed 0x01 and the length is 1 // The value should be 0x00 or 0xFF - if tag_val != 0x01 || length != 1 || (value[0] != 0x00 && value[0] != 0xFF) { + if tag_val != 0x01 || value.len() != 1 || (value[0] != 0x00 && value[0] != 0xFF) { return Err(nom::Err::Error((bytes, ErrorKind::Verify))); } Ok((rest, value[0] == 0xFF)) @@ -620,7 +693,7 @@ pub fn parse_asn1_der_boolean(bytes: &[u8]) -> IResult<&[u8], bool> { // SEQUENCE: tag: 0x30 pub fn parse_asn1_der_sequence(bytes: &[u8]) -> IResult<&[u8], &[u8]> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag is indeed 0x03 if tag_val != 0x30 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -636,7 +709,7 @@ pub fn parse_asn1_der_serial_number(bytes: &[u8]) -> IResult<&[u8], &[u8]> { // Algorithm Identifier: Sequence -> universal, constructed, 0 (0x30) // Encapsulates OID (alg) and optional params (params) pub fn parse_asn1_der_algorithm_identifier(bytes: &[u8]) -> IResult<&[u8], Asn1DerAlgId> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag_val is indeed 0x30 if tag_val != 0x30 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -659,7 +732,7 @@ pub fn parse_asn1_der_algorithm_identifier(bytes: &[u8]) -> IResult<&[u8], Asn1D // Parser for Universal OID type (0x06) pub fn parse_asn1_der_oid(bytes: &[u8]) -> IResult<&[u8], &[u8]> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag_val is indeed 0x06 if tag_val != 0x06 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -669,7 +742,7 @@ pub fn parse_asn1_der_oid(bytes: &[u8]) -> IResult<&[u8], &[u8]> { // Parser for Time Validity Sequence Structure (0x30) pub fn parse_asn1_der_validity(bytes: &[u8]) -> IResult<&[u8], Asn1DerValidity> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag_val is indeed 0x30 if tag_val != 0x30 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -691,7 +764,7 @@ pub fn parse_asn1_der_validity(bytes: &[u8]) -> IResult<&[u8], Asn1DerValidity> // Parser for Time Representation (0x17: UTCTime, 0x18: GeneralizedTime) pub fn parse_ans1_der_time(bytes: &[u8]) -> IResult<&[u8], Asn1DerTime> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Handle UTCTime, Gen.Time and Invalid Tag values match tag_val { 0x17 => { @@ -712,7 +785,7 @@ pub fn parse_ans1_der_time(bytes: &[u8]) -> IResult<&[u8], Asn1DerTime> { // Parser for SubjectKeyPublicInfo (Sequence: 0x30) pub fn parse_asn1_der_subject_key_public_info(bytes: &[u8]) -> IResult<&[u8], Asn1DerSubjectPublicKeyInfo> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag_val is indeed 0x30 if tag_val != 0x30 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -734,13 +807,13 @@ pub fn parse_asn1_der_subject_key_public_info(bytes: &[u8]) -> IResult<&[u8], As // Parser for extensions (Context-specific Sequence: 0xA3, then universal Sequence: 0x30) pub fn parse_asn1_der_extensions(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensions> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag_val is indeed 0xA3 if tag_val != 0xA3 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); } - let (_, (tag_val, length, mut value)) = complete( + let (_, (tag_val, _, mut value)) = complete( parse_asn1_der_object )(value)?; // Verify the tag_val is indeed 0x30 @@ -763,7 +836,7 @@ pub fn parse_asn1_der_extensions(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensio // Parser for an extension (Sequence: 0x30) pub fn parse_asn1_der_extension(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtension> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag_val is indeed 0x30 if tag_val != 0x30 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -825,15 +898,15 @@ pub fn parse_asn1_der_extension(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtension // Parser for KeyUsage Extension, may have bit padding // Do not use parse_asn1_der_bit_string, that assumes no bit padding pub fn parse_asn1_der_key_usage(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify the tag_val represents a bitstring, and it must have length 2 // i.e. bit-padding | bit-string - if tag_val != 0x03 || (length != 2 && length != 3) { + if tag_val != 0x03 || (value.len() != 2 && value.len() != 3) { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); } // Erase the padded bits let padding = value[0]; - let usage_array: [u8; 2] = if length == 2 { + let usage_array: [u8; 2] = if value.len() == 2 { [value[1], 0] } else { [value[1], value[2]] @@ -849,7 +922,7 @@ pub fn parse_asn1_der_key_usage(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtension // Parser for CertificatePolicies Extension (sequence: 0x30) pub fn parse_asn1_der_certificate_policies(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> { - let (rest, (tag_val, length, mut value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, mut value)) = parse_asn1_der_object(bytes)?; // Verify tag value if tag_val != 0x30 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -873,7 +946,7 @@ pub fn parse_asn1_der_certificate_policies(bytes: &[u8]) -> IResult<&[u8], Asn1D // Parser for PolicyInformation (Sequence: 0x30) pub fn parse_asn1_der_policy_information(bytes: &[u8]) -> IResult<&[u8], Asn1DerPolicyInformation> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify tag value if tag_val != 0x30 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -897,7 +970,7 @@ pub fn parse_asn1_der_policy_information(bytes: &[u8]) -> IResult<&[u8], Asn1Der // Parser for BasicConstraints (Sequence: 0x30) pub fn parse_asn1_der_basic_constraints(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify tag value if tag_val != 0x30 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -929,7 +1002,7 @@ pub fn parse_asn1_der_basic_constraints(bytes: &[u8]) -> IResult<&[u8], Asn1DerE // Parser for Extended Key Usage Extension (Sequence: 0x30) pub fn parse_asn1_der_extended_key_usage(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> { - let (rest, (tag_val, length, mut value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, mut value)) = parse_asn1_der_object(bytes)?; // Verify tag value if tag_val != 0x30 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -986,7 +1059,7 @@ pub fn parse_inhibit_any_policy(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtension // Parser for octet string (tag: 0x04) pub fn parse_asn1_der_octet_string(bytes: &[u8]) -> IResult<&[u8], &[u8]> { - let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?; // Verify tag value if tag_val != 0x04 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); @@ -994,6 +1067,29 @@ pub fn parse_asn1_der_octet_string(bytes: &[u8]) -> IResult<&[u8], &[u8]> { Ok((rest, value)) } +// Take ASN.1 DER encoded public key +// Return a slice of modulus, and a slice of exponent +// Construct numeric value by wrapping rsa::BigUint with the return values +pub fn parse_asn1_der_rsa_public_key(bytes: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> { + // RSA Public key is a sequence of 2 integers + let (_, (tag_val, _, value)) = complete(parse_asn1_der_object)(bytes)?; + // Verify tag value + if tag_val != 0x30 { + return Err(nom::Err::Failure((&[], ErrorKind::Verify))); + } + let (_, (modulus, exponent)) = complete( + tuple(( + parse_asn1_der_integer, + parse_asn1_der_integer + )) + )(value)?; + + Ok(( + &[], + (modulus, exponent) + )) +} + mod oid { // Extensions pub const CERT_KEY_USAGE: &'static [u8] = &[85, 29, 15]; // 2.5.29.15 diff --git a/src/session.rs b/src/session.rs index f010499..2d363e8 100644 --- a/src/session.rs +++ b/src/session.rs @@ -8,6 +8,7 @@ use ccm::Ccm; use hkdf::Hkdf; use generic_array::GenericArray; use byteorder::{ByteOrder, NetworkEndian, BigEndian}; +use rsa::RSAPublicKey; use core::convert::AsRef; use core::cell::RefCell; @@ -50,6 +51,9 @@ pub(crate) struct Session { // Reset to 0 on rekey AND key exchange // TODO: Force rekey if sequence_number need to wrap sequence_number: u64, + // Certificate public key + // For Handling CertificateVerify + cert_rsa_public_key: Option, } impl Session { @@ -73,6 +77,7 @@ impl Session { client_nonce: None, server_nonce: None, sequence_number: 0, + cert_rsa_public_key: None } } @@ -425,11 +430,18 @@ impl Session { self.sequence_number = 0; } - pub(crate) fn client_update_for_ee(&mut self) { + pub(crate) fn client_update_for_ee(&mut self, ee_slice: &[u8]) { + self.hash.update(ee_slice); self.state = TlsState::WAIT_CERT_CR; } - pub(crate) fn client_update_for_wait_cert_cr(&mut self) { + pub(crate) fn client_update_for_wait_cert_cr( + &mut self, + cert_slice: &[u8], + cert_rsa_public_key: RSAPublicKey + ) { + self.hash.update(cert_slice); + self.cert_rsa_public_key.replace(cert_rsa_public_key); self.state = TlsState::WAIT_CV; } diff --git a/src/tls.rs b/src/tls.rs index 5f347ba..43c13f1 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -30,6 +30,11 @@ use aes_gcm::aes::Aes128; use aes_gcm::{AeadInPlace, NewAead}; use sha2::{Sha256, Sha384, Sha512, Digest}; +use nom::bytes::complete::take; +use nom::IResult; +use nom::error::make_error; +use nom::error::ErrorKind; + use alloc::vec::{ self, Vec }; use crate::Error as TlsError; @@ -37,6 +42,7 @@ use crate::tls_packet::*; use crate::parse::{ parse_tls_repr, parse_handshake, parse_inner_plaintext_for_handshake }; use crate::buffer::TlsBuffer; use crate::session::{Session, TlsRole}; +use crate::certificate::validate_root_certificate; #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[allow(non_camel_case_types)] @@ -166,7 +172,7 @@ impl TlsSocket { // TLS Client wait for server's certificate cerify // No need to send anything - TlsState::WAIT_CV=> {}, + TlsState::WAIT_CV => {}, _ => todo!() } @@ -359,8 +365,8 @@ impl TlsSocket { } let parse_result = parse_inner_plaintext_for_handshake(&payload); - let (_, mut handshake_vec) = parse_result - .map_err(|_| Error::Unrecognized)?; + let (_, (mut handshake_slice, mut handshake_vec)) = + parse_result.map_err(|_| Error::Unrecognized)?; // Verify that it is indeed an EE let might_be_ee = handshake_vec.remove(0); @@ -373,7 +379,18 @@ impl TlsSocket { // Practically, nothing will be done about cookies/server name // Extension processing is therefore skipped - self.session.borrow_mut().client_update_for_ee(); + // Update hash of the session, get EE by taking appropriate length of data + + let (handshake_slice, ee_slice) = + take::<_, _, (&[u8], ErrorKind)>( + might_be_ee.length + 4 + )(handshake_slice) + .map_err(|_| Error::Unrecognized)?; + + self.session.borrow_mut() + .client_update_for_ee( + &ee_slice + ); // TODO: Handle in WAIT_CERT_CR if there are still unprocessed handshakes // Ideas: 1. Split off WAIT_CERT_CR handling into a separate function @@ -392,7 +409,7 @@ impl TlsSocket { todo!() } - // Pull out the `payload` from TlsRepr, decrypt as EE + // Pull out the `payload` from TlsRepr, decrypt as CERT let mut payload = repr.payload.take().unwrap(); // Instantiate associated data and decrypt @@ -408,28 +425,78 @@ impl TlsSocket { &mut payload ); } - // log::info!("Decrypted payload {:?}", payload); // Parse the certificate from TLS payload let parse_result = parse_inner_plaintext_for_handshake(&payload); - let (_, mut handshake_vec) = parse_result + let (_, (handshake_slice, mut handshake_vec)) = parse_result .map_err(|_| Error::Unrecognized)?; - - log::info!("Decrypted certificate {:X?}", handshake_vec); // Verify that it is indeed an Certificate - let might_be_ee = handshake_vec.remove(0); - if might_be_ee.get_msg_type() != HandshakeType::Certificate { + let might_be_cert = handshake_vec.remove(0); + if might_be_cert.get_msg_type() != HandshakeType::Certificate { // Process the other handshakes in "handshake_vec" todo!() } // TODO: Process Certificate + let cert = might_be_cert.get_asn1_der_certificate().unwrap(); + log::info!("Certificate Acquisition"); + log::info!("Validation {:?}", + validate_root_certificate(cert) + ); // Update session TLS state to WAIT_CV - self.session.borrow_mut().client_update_for_wait_cert_cr(); + let (handshake_slice, cert_slice) = + take::<_, _, (&[u8], ErrorKind)>( + might_be_cert.length + 4 + )(handshake_slice) + .map_err(|_| Error::Unrecognized)?; + + self.session.borrow_mut() + .client_update_for_wait_cert_cr( + &cert_slice, + cert.return_rsa_public_key().unwrap() + ); + + }, + // In this stage, server will eventually send a CertificateVerify + // Verify that the signature is indeed correct + TlsState::WAIT_CV => { + // CertificateVerify is disguised as Application Data + if !repr.is_application_data() { + // Abort communication, this affect IV calculation + todo!() + } + + // Pull out the `payload` from TlsRepr, decrypt as CV + // Keep 1 copy to update hash + let mut payload = repr.payload.take().unwrap(); + let cert_slice = payload.clone(); + + // Instantiate associated data and decrypt + let mut array: [u8; 5] = [0; 5]; + let mut buffer = TlsBuffer::new(&mut array); + buffer.write_u8(repr.content_type.into())?; + buffer.write_u16(repr.version.into())?; + buffer.write_u16(repr.length)?; + let associated_data: &[u8] = buffer.into(); + { + self.session.borrow_mut().decrypt_in_place( + associated_data, + &mut payload + ); + } + + // Parse the certificate from TLS payload + let parse_result = parse_inner_plaintext_for_handshake(&payload); + let (_, mut handshake_vec) = parse_result + .map_err(|_| Error::Unrecognized)?; + + // Get hash from session, validate signature + } + _ => {}, } diff --git a/src/tls_packet.rs b/src/tls_packet.rs index aba5777..db64784 100644 --- a/src/tls_packet.rs +++ b/src/tls_packet.rs @@ -12,6 +12,8 @@ use core::convert::TryInto; use alloc::vec::Vec; +use crate::certificate::Certificate as Asn1DerCertificate; + pub(crate) const HRR_RANDOM: [u8; 32] = [ 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, @@ -162,6 +164,19 @@ impl<'a, 'b> HandshakeRepr<'a> { pub(crate) fn get_msg_type(&self) -> HandshakeType { self.msg_type } + + pub(crate) fn get_asn1_der_certificate(&self) -> Result<&Asn1DerCertificate, ()> { + if self.msg_type != HandshakeType::Certificate { + return Err(()) + }; + if let HandshakeData::Certificate( + cert + ) = &self.handshake_data { + Ok(cert.get_certificate(0)) + } else { + Err(()) + } + } } #[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)] @@ -196,6 +211,7 @@ pub(crate) enum HandshakeData<'a> { ServerHello(ServerHello<'a>), EncryptedExtensions(EncryptedExtensions), Certificate(Certificate<'a>), + CertificateVerify(CertificateVerify<'a>), } impl<'a> HandshakeData<'a> { @@ -668,6 +684,20 @@ pub(crate) enum CertificateEntryInfo<'a> { } } +impl<'a> CertificateEntryInfo<'a> { + pub(crate) fn get_certificate(&self) -> &Asn1DerCertificate { + match self { + CertificateEntryInfo::RawPublicKey { + ASN1_subjectPublicKeyInfo_length, + ASN1_subjectPublicKeyInfo + } => todo!(), + CertificateEntryInfo::X509 { + cert_data_length, cert_data + } => &cert_data + } + } +} + #[derive(Debug, Clone)] pub(crate) struct CertificateEntry<'a> { pub(crate) certificate_entry_info: CertificateEntryInfo<'a>, @@ -675,6 +705,12 @@ pub(crate) struct CertificateEntry<'a> { pub(crate) extensions: Vec, } +impl<'a> CertificateEntry<'a> { + pub(crate) fn get_certificate(&self) -> &Asn1DerCertificate { + self.certificate_entry_info.get_certificate() + } +} + #[derive(Debug, Clone)] pub(crate) struct Certificate<'a> { pub(crate) certificate_request_context_length: u8, // 0 length unless responding to CERT_REQUEST @@ -682,3 +718,16 @@ pub(crate) struct Certificate<'a> { pub(crate) certificate_list_length: u32, // Only 24 bits pub(crate) certificate_list: Vec>, } + +impl<'a> Certificate<'a> { + pub(crate) fn get_certificate(&self, index: usize) -> &Asn1DerCertificate { + self.certificate_list[index].get_certificate() + } +} + +#[derive(Debug, Clone)] +pub(crate) struct CertificateVerify<'a> { + pub(crate) algorithm: SignatureScheme, + pub(crate) signature_length: u16, + pub(crate) signature: &'a [u8], +}