cert: add key verify
This commit is contained in:
parent
1261b36b8f
commit
0042fea902
|
@ -6,6 +6,7 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
hkdf = "0.9.0"
|
||||
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 }
|
||||
|
|
|
@ -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<bool, TlsError> {
|
||||
// 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<RSAPublicKey, ()> {
|
||||
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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
40
src/main.rs
40
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::<sha2::Sha256, OsRng>(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] = [
|
||||
|
|
164
src/parse.rs
164
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<HandshakeRepr>> {
|
||||
// Return handshake slice for hashing
|
||||
pub(crate) fn parse_inner_plaintext_for_handshake(bytes: &[u8]) -> IResult<&[u8], (&[u8], Vec<HandshakeRepr>)> {
|
||||
let mut remaining_bytes = bytes;
|
||||
let mut handshake_vec: Vec<HandshakeRepr> = 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::<usize>().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::<usize>());
|
||||
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
|
||||
|
|
|
@ -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<RSAPublicKey>,
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
103
src/tls.rs
103
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)]
|
||||
|
@ -359,8 +365,8 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
|
|||
}
|
||||
|
||||
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<R: RngCore + CryptoRng> TlsSocket<R> {
|
|||
|
||||
// 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<R: RngCore + CryptoRng> TlsSocket<R> {
|
|||
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<R: RngCore + CryptoRng> TlsSocket<R> {
|
|||
&mut payload
|
||||
);
|
||||
}
|
||||
// log::info!("Decrypted payload {:?}", payload);
|
||||
|
||||
// Parse the certificate from TLS payload
|
||||
let parse_result = parse_inner_plaintext_for_handshake(&payload);
|
||||
let (_, (handshake_slice, mut handshake_vec)) = parse_result
|
||||
.map_err(|_| Error::Unrecognized)?;
|
||||
|
||||
// Verify that it is indeed an 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
|
||||
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)?;
|
||||
|
||||
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 {
|
||||
// Process the other handshakes in "handshake_vec"
|
||||
todo!()
|
||||
// Get hash from session, validate signature
|
||||
}
|
||||
|
||||
// TODO: Process Certificate
|
||||
|
||||
// Update session TLS state to WAIT_CV
|
||||
self.session.borrow_mut().client_update_for_wait_cert_cr();
|
||||
},
|
||||
|
||||
_ => {},
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Extension>,
|
||||
}
|
||||
|
||||
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<CertificateEntry<'a>>,
|
||||
}
|
||||
|
||||
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],
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue