From 1c689b353559a3b9ac48158fa0f5f96611ea8ac9 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 22 Oct 2020 17:41:33 +0800 Subject: [PATCH] certificate: parse sig-alg --- src/certificate.rs | 35 ++++++++++++---- src/parse.rs | 101 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 126 insertions(+), 10 deletions(-) diff --git a/src/certificate.rs b/src/certificate.rs index 8807c4b..4fc819c 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -1,6 +1,8 @@ use num_enum::IntoPrimitive; use num_enum::TryFromPrimitive; +use alloc::vec::Vec; + pub struct Certificate<'a> { tbs_certificate: TBSCertificate<'a>, signature_algorithm: AlgorithmIdentifier<'a>, @@ -17,7 +19,7 @@ pub struct TBSCertificate<'a> { subject_public_key_info: SubjectPublicKeyInfo<'a>, issuer_unique_id: Option<&'a [u8]>, subject_unique_id: Option<&'a [u8]>, - extensions: Extensions, + extensions: Extensions<'a>, } #[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)] @@ -30,8 +32,8 @@ pub enum Version { } pub struct Validity<'a> { - not_before: Time<'a>, - not_after: Time<'a>, + pub not_before: Time<'a>, + pub not_after: Time<'a>, } pub enum Time<'a> { @@ -40,12 +42,31 @@ pub enum Time<'a> { } pub struct SubjectPublicKeyInfo<'a> { - algorithm: AlgorithmIdentifier<'a>, - subject_public_key: &'a [u8], + pub algorithm: AlgorithmIdentifier<'a>, + pub subject_public_key: &'a [u8], } -pub struct Extensions { - +pub struct Extensions<'a> { + extensions: Vec> +} + +pub enum Extension<'a> { + KeyUsage { + // Acceptable usage of this certificate + // Cross verify with ExtendedKeyUsage + usage: u8 + }, + CertificatePolicies { + // Policies listed in an extension + // Need to verify its validity + policies: Vec<&'a [u8]> + }, + SubjectAlternativeName, + BasicConstraints { + is_ca: bool, + path_len_constraint: Option, + }, + } pub struct AlgorithmIdentifier<'a> { diff --git a/src/parse.rs b/src/parse.rs index c75887d..54582fa 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -16,6 +16,10 @@ use crate::tls_packet::*; use crate::certificate::Certificate as Asn1DerCertificate; use crate::certificate::Version as Asn1DerVersion; use crate::certificate::AlgorithmIdentifier as Asn1DerAlgId; +use crate::certificate::Time as Asn1DerTime; +use crate::certificate::Validity as Asn1DerValidity; +use crate::certificate::SubjectPublicKeyInfo as Asn1DerSubjectPublicKeyInfo; +use crate::certificate::Extensions as Asn1DerExtensions; use core::convert::TryFrom; use core::convert::TryInto; @@ -362,6 +366,8 @@ pub fn parse_asn1_der_header(bytes: &[u8]) -> IResult<&[u8], (u8, usize)> { } } +// TODO: Not return length +// It is quite useless when the value slice of the exact same length is returned pub fn parse_asn1_der_object(bytes: &[u8]) -> IResult<&[u8], (u8, usize, &[u8])> { let (rest, (tag, length)) = parse_asn1_der_header(bytes)?; let (rest, value) = take(length)(rest)?; @@ -404,6 +410,26 @@ pub fn parse_asn1_der_integer(bytes: &[u8]) -> IResult<&[u8], &[u8]> { if tag_val != 0x02 { return Err(nom::Err::Failure((&[], ErrorKind::Verify))); } + // Consume the leading 0x00 byte + let (value, _) = tag(&[0x00])(value)?; + Ok((rest, value)) +} + +// BIT STRING: tag: 0x03 +// 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)?; + // Verify the tag is indeed 0x03 + if tag_val != 0x03 { + return Err(nom::Err::Failure((&[], ErrorKind::Verify))); + } + // Dump `unused_bit` field + let (value, unused_bit_byte) = take(1_usize)(value)?; + // Assert no unused bits, otherwise it is a malformatted key + if value[0] != 0 { + return Err(nom::Err::Failure((&[], ErrorKind::Verify))); + } Ok((rest, value)) } @@ -446,8 +472,77 @@ pub fn parse_asn1_der_oid(bytes: &[u8]) -> IResult<&[u8], &[u8]> { Ok((rest, value)) } -// Parser for Time Validity Structure -pub fn parse_asn1_der_validity(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)?; - + // Verify the tag_val is indeed 0x30 + if tag_val != 0x30 { + return Err(nom::Err::Failure((&[], ErrorKind::Verify))); + } + let (_, (not_before, not_after)) = complete( + tuple(( + parse_ans1_der_time, + parse_ans1_der_time + )) + )(value)?; + Ok(( + rest, + Asn1DerValidity { + not_before, + not_after, + } + )) +} + +// 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)?; + // Handle UTCTime, Gen.Time and Invalid Tag values + match tag_val { + 0x17 => { + Ok(( + rest, + Asn1DerTime::UTCTime(value) + )) + }, + 0x18 => { + Ok(( + rest, + Asn1DerTime::GeneralizedTime(value) + )) + }, + _ => Err(nom::Err::Failure((&[], ErrorKind::Verify))) + } +} + +// 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)?; + // Verify the tag_val is indeed 0x30 + if tag_val != 0x30 { + return Err(nom::Err::Failure((&[], ErrorKind::Verify))); + } + let (_, (algorithm, subject_public_key)) = complete( + tuple(( + parse_asn1_der_algorithm_identifier, + parse_asn1_der_bit_string, + )) + )(value)?; + Ok(( + rest, + Asn1DerSubjectPublicKeyInfo { + algorithm, + subject_public_key + } + )) +} + +// Parser for extensions (Sequence: 0xA3) +pub fn parse_asn1_der_extensions(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensions> { + let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?; + // Verify the tag_val is indeed 0xA3 + if tag_val != 0xA3 { + return Err(nom::Err::Failure((&[], ErrorKind::Verify))); + } + todo!() }