1931 lines
63 KiB
Rust
1931 lines
63 KiB
Rust
use nom::IResult;
|
|
use nom::bytes::complete::take;
|
|
use nom::bytes::complete::tag;
|
|
use nom::bytes::complete::take_till;
|
|
use nom::combinator::complete;
|
|
use nom::combinator::opt;
|
|
use nom::sequence::preceded;
|
|
use nom::sequence::tuple;
|
|
use nom::error::ErrorKind;
|
|
|
|
use chrono::{DateTime, FixedOffset};
|
|
use heapless::{String, consts::*};
|
|
|
|
use byteorder::{ByteOrder, NetworkEndian};
|
|
|
|
use crate::tls_packet::*;
|
|
|
|
use crate::certificate::{
|
|
Certificate as Asn1DerCertificate,
|
|
Version as Asn1DerVersion,
|
|
AlgorithmIdentifier as Asn1DerAlgId,
|
|
Validity as Asn1DerValidity,
|
|
SubjectPublicKeyInfo as Asn1DerSubjectPublicKeyInfo,
|
|
Extensions as Asn1DerExtensions,
|
|
Extension as Asn1DerExtension,
|
|
ExtensionValue as Asn1DerExtensionValue,
|
|
PolicyInformation as Asn1DerPolicyInformation,
|
|
TBSCertificate as Asn1DerTBSCertificate,
|
|
Name as Asn1DerName,
|
|
AttributeTypeAndValue as Asn1DerAttribute,
|
|
GeneralName as Asn1DerGeneralName,
|
|
RelativeDistinguishedName as Asn1DerRDN,
|
|
};
|
|
|
|
use crate::oid;
|
|
use crate::oid::*;
|
|
|
|
use core::convert::TryFrom;
|
|
use core::convert::TryInto;
|
|
|
|
use alloc::vec::Vec;
|
|
|
|
// Return handshake/payload slice and TLS Record
|
|
pub(crate) fn parse_tls_repr(bytes: &[u8]) -> IResult<&[u8], (&[u8], TlsRepr)> {
|
|
let content_type = take(1_usize);
|
|
let version = take(2_usize);
|
|
let length = take(2_usize);
|
|
|
|
let (rest, (content_type, version, length)) =
|
|
tuple((content_type, version, length))(bytes)?;
|
|
|
|
let mut repr = TlsRepr {
|
|
content_type: TlsContentType::try_from(content_type[0])
|
|
.unwrap(),
|
|
|
|
version: TlsVersion::try_from(NetworkEndian::read_u16(version))
|
|
.unwrap(),
|
|
|
|
length: NetworkEndian::read_u16(length),
|
|
payload: None,
|
|
handshake: None,
|
|
};
|
|
let (rest, bytes) = take(repr.length)(rest)?;
|
|
|
|
// Store a copy of the TLS Handshake slice to return
|
|
let repr_slice_clone = bytes;
|
|
{
|
|
use crate::tls_packet::TlsContentType::*;
|
|
match repr.content_type {
|
|
Handshake => {
|
|
let (_, handshake) = complete(
|
|
parse_handshake
|
|
)(bytes)?;
|
|
repr.handshake = Some(handshake);
|
|
},
|
|
ChangeCipherSpec | ApplicationData | Alert => {
|
|
let mut vec: Vec<u8> = Vec::new();
|
|
vec.extend_from_slice(bytes);
|
|
repr.payload = Some(vec);
|
|
},
|
|
_ => todo!()
|
|
}
|
|
}
|
|
Ok((rest, (repr_slice_clone, repr)))
|
|
}
|
|
|
|
// Convert TlsInnerPlainText in RFC 8446 into Handshake
|
|
// Diff from regular handshake:
|
|
// 1. Handshake can coalesced into a larger TLS record
|
|
// 2. Content type and zero paddings at the end
|
|
// Return handshake slice for hashing
|
|
pub(crate) fn parse_inner_plaintext_for_handshake(bytes: &[u8]) -> IResult<&[u8], Vec<(&[u8], HandshakeRepr)>> {
|
|
let mut remaining_bytes = bytes;
|
|
let mut handshake_vec: Vec<(&[u8], HandshakeRepr)> = Vec::new();
|
|
|
|
loop {
|
|
// Perform check on the number of remaining bytes
|
|
// Case 1: At most 4 bytes left, then that must be the content type of the TLS record
|
|
// Assert that it is indeed handshake (0x16)
|
|
// Case 2: More than 4 byte left, then that must either be
|
|
// 2.1: Another handshake representation
|
|
// 2.2: Content type | Zero padding, which can be detected by 0 length
|
|
if remaining_bytes.len() <= 4 ||
|
|
NetworkEndian::read_u24(&remaining_bytes[1..4]) == 0 {
|
|
complete(
|
|
preceded(
|
|
tag(&[0x16]),
|
|
take_till(|byte| byte != 0x00)
|
|
)
|
|
)(remaining_bytes)?;
|
|
return Ok((
|
|
&[],
|
|
handshake_vec
|
|
));
|
|
}
|
|
|
|
let (rem, handshake_repr) = parse_handshake(remaining_bytes)?;
|
|
let handshake_slice = &remaining_bytes[..(remaining_bytes.len()-rem.len())];
|
|
remaining_bytes = rem;
|
|
handshake_vec.push((handshake_slice, handshake_repr));
|
|
}
|
|
}
|
|
|
|
// Input: The entire inner plaintext including TLS record
|
|
// (record | content | content_type | zeros)
|
|
// Get the content_type of inner_plaintext
|
|
// Also get the (optional) starting index of zero paddings
|
|
pub(crate) fn get_content_type_inner_plaintext(inner_plaintext: &[u8]) -> (TlsContentType, Option<usize>) {
|
|
// Approach from the rear, discard zeros until a nonzero byte is found
|
|
let mut zero_padding_start_index = inner_plaintext.len();
|
|
while (&inner_plaintext[..zero_padding_start_index]).ends_with(&[0x00]) {
|
|
// Record wrapper takes the first 5 byte
|
|
// Worst case scenario there must be a content type
|
|
if zero_padding_start_index > 6 {
|
|
zero_padding_start_index -= 1;
|
|
} else {
|
|
return (TlsContentType::Invalid, None);
|
|
}
|
|
}
|
|
(
|
|
TlsContentType::try_from(inner_plaintext[zero_padding_start_index-1]).unwrap(),
|
|
if zero_padding_start_index < inner_plaintext.len() {
|
|
Some(zero_padding_start_index)
|
|
} else {
|
|
None
|
|
}
|
|
)
|
|
}
|
|
|
|
// Turn bytes into a handshake struct
|
|
// Will return trailing bytes, if too much bytes were supplied
|
|
pub(crate) fn parse_handshake(bytes: &[u8]) -> IResult<&[u8], HandshakeRepr> {
|
|
let handshake_type = take(1_usize);
|
|
let length = take(3_usize);
|
|
|
|
let (rest, (handshake_type, length)) =
|
|
tuple((handshake_type, length))(bytes)?;
|
|
|
|
let mut repr = HandshakeRepr {
|
|
msg_type: HandshakeType::try_from(handshake_type[0]).unwrap(),
|
|
length: NetworkEndian::read_u24(length),
|
|
handshake_data: HandshakeData::Uninitialized,
|
|
};
|
|
{
|
|
use crate::tls_packet::HandshakeType::*;
|
|
match repr.msg_type {
|
|
ClientHello => {
|
|
let (rest, data) = parse_client_hello(rest)?;
|
|
repr.handshake_data = data;
|
|
Ok((rest, repr))
|
|
},
|
|
ServerHello => {
|
|
let (rest, data) = parse_server_hello(rest)?;
|
|
repr.handshake_data = data;
|
|
Ok((rest, repr))
|
|
},
|
|
EncryptedExtensions => {
|
|
// Process EE
|
|
let (rest, handshake_data) = parse_encrypted_extensions(
|
|
rest
|
|
)?;
|
|
repr.handshake_data = HandshakeData::EncryptedExtensions(
|
|
handshake_data
|
|
);
|
|
|
|
Ok((rest, repr))
|
|
},
|
|
CertificateRequest => {
|
|
// Process certificate request
|
|
let (rest, handshake_data) = parse_certificate_request(
|
|
rest
|
|
)?;
|
|
repr.handshake_data = HandshakeData::CertificateRequest(
|
|
handshake_data
|
|
);
|
|
|
|
Ok((rest, repr))
|
|
},
|
|
Certificate => {
|
|
// Process Certificate
|
|
let (rest, handshake_data) = parse_handshake_certificate(
|
|
rest
|
|
)?;
|
|
repr.handshake_data = HandshakeData::Certificate(
|
|
handshake_data
|
|
);
|
|
|
|
Ok((rest, repr))
|
|
},
|
|
CertificateVerify => {
|
|
// Parse CertificateVerify
|
|
let (rest, handshake_data) = parse_certificate_verify(
|
|
rest
|
|
)?;
|
|
repr.handshake_data = HandshakeData::CertificateVerify(
|
|
handshake_data
|
|
);
|
|
|
|
Ok((rest, repr))
|
|
},
|
|
Finished => {
|
|
// Parse Finished, the size is determined
|
|
// Pre-split the slice and then parse for Finished
|
|
// i.e. check for completeness
|
|
let (rest, possible_verify_data) = take(repr.length)(rest)?;
|
|
let (_, handshake_data) = complete(
|
|
parse_finished
|
|
)(possible_verify_data)?;
|
|
|
|
repr.handshake_data = HandshakeData::Finished(
|
|
handshake_data
|
|
);
|
|
|
|
Ok((rest, repr))
|
|
}
|
|
_ => todo!()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn parse_client_hello(bytes: &[u8]) -> IResult<&[u8], HandshakeData> {
|
|
let version = take(2_usize);
|
|
let random = take(32_usize);
|
|
let session_id_length = take(1_usize);
|
|
let (rest, (version, random, session_id_length)) = tuple((
|
|
version, random, session_id_length
|
|
))(bytes)?;
|
|
|
|
let session_id_length = session_id_length[0];
|
|
let (rest, session_id) = take(session_id_length)(rest)?;
|
|
|
|
let (mut rest, cipher_suites_length) = take(2_usize)(rest)?;
|
|
let cipher_suites_length = NetworkEndian::read_u16(cipher_suites_length);
|
|
|
|
let mut cipher_suites: [_; 5] = [None; 5];
|
|
let mut index = 0;
|
|
|
|
// Read cipher suites
|
|
// Only 5 of them are supported in terms of enum availability
|
|
// AES_CCM_8 is not an acceptable cipher suite, but can still be recorded
|
|
for _ in 0..(cipher_suites_length/2) {
|
|
let (rem, cipher_suite) = take(2_usize)(rest)?;
|
|
|
|
if let Ok(cipher_suite) = CipherSuite::try_from(
|
|
NetworkEndian::read_u16(cipher_suite)
|
|
) {
|
|
cipher_suites[index] = Some(cipher_suite);
|
|
index += 1;
|
|
}
|
|
|
|
rest = rem;
|
|
}
|
|
|
|
let (rest, compression_method_length) = take(1_usize)(rest)?;
|
|
let compression_method_length = compression_method_length[0];
|
|
// Can only have compression method being NULL (1 byte of 0)
|
|
let (rest, compression_methods) = take(compression_method_length)(rest)?;
|
|
if compression_methods != &[0] {
|
|
return Err(nom::Err::Failure((&bytes, ErrorKind::Verify)));
|
|
}
|
|
|
|
let (mut rest, extension_length) = take(2_usize)(rest)?;
|
|
let mut extension_length = NetworkEndian::read_u16(extension_length);
|
|
|
|
let mut client_hello = ClientHello {
|
|
version: TlsVersion::try_from(NetworkEndian::read_u16(version)).unwrap(),
|
|
random: [0; 32],
|
|
session_id_length,
|
|
session_id: [0; 32],
|
|
cipher_suites_length,
|
|
cipher_suites,
|
|
compression_method_length,
|
|
compression_methods: 0,
|
|
extension_length,
|
|
extensions: Vec::new(),
|
|
};
|
|
|
|
client_hello.random.clone_from_slice(&random);
|
|
&mut client_hello.session_id[
|
|
32-(usize::try_from(session_id_length).unwrap())..
|
|
].clone_from_slice(&session_id);
|
|
|
|
while extension_length > 0 {
|
|
let (rem, extension) = parse_extension(rest, HandshakeType::ClientHello)?;
|
|
rest = rem;
|
|
extension_length -= u16::try_from(extension.get_length()).unwrap();
|
|
|
|
client_hello.extensions.push(extension);
|
|
}
|
|
|
|
Ok((rest, HandshakeData::ClientHello(client_hello)))
|
|
}
|
|
|
|
fn parse_server_hello(bytes: &[u8]) -> IResult<&[u8], HandshakeData> {
|
|
let version = take(2_usize);
|
|
let random = take(32_usize);
|
|
let session_id_echo_length = take(1_usize);
|
|
|
|
let (rest, (version, random, session_id_echo_length)) =
|
|
tuple((version, random, session_id_echo_length))(bytes)?;
|
|
|
|
let session_id_echo_length = session_id_echo_length[0];
|
|
let (rest, session_id_echo) = take(session_id_echo_length)(rest)?;
|
|
|
|
let cipher_suite = take(2_usize);
|
|
let compression_method = take(1_usize);
|
|
let extension_length = take(2_usize);
|
|
|
|
let (mut rest, (cipher_suite, compression_method, extension_length)) =
|
|
tuple((cipher_suite, compression_method, extension_length))(rest)?;
|
|
|
|
let mut server_hello = ServerHello {
|
|
version: TlsVersion::try_from(NetworkEndian::read_u16(version)).unwrap(),
|
|
random,
|
|
session_id_echo_length,
|
|
session_id_echo,
|
|
cipher_suite: CipherSuite::try_from(NetworkEndian::read_u16(cipher_suite)).unwrap(),
|
|
compression_method: compression_method[0],
|
|
extension_length: NetworkEndian::read_u16(extension_length),
|
|
extensions: Vec::new(),
|
|
};
|
|
|
|
let mut extension_vec: Vec<Extension> = Vec::new();
|
|
let mut extension_length: i32 = server_hello.extension_length.into();
|
|
while extension_length > 0 {
|
|
let (rem, extension) = parse_extension(rest, HandshakeType::ServerHello)?;
|
|
rest = rem;
|
|
extension_length -= i32::try_from(extension.get_length()).unwrap();
|
|
|
|
// Todo:: Proper error
|
|
if extension_length < 0 {
|
|
todo!()
|
|
}
|
|
|
|
extension_vec.push(extension);
|
|
}
|
|
|
|
server_hello.extensions = extension_vec;
|
|
Ok((rest, HandshakeData::ServerHello(server_hello)))
|
|
}
|
|
|
|
// For reference: This is the structure of encrypted text
|
|
// Source: RFC 8446 Section 5.2
|
|
//
|
|
// struct {
|
|
// opaque content[TLSPlaintext.length];
|
|
// ContentType type;
|
|
// uint8 zeros[length_of_padding];
|
|
// } TLSInnerPlaintext;
|
|
|
|
fn parse_encrypted_extensions(bytes: &[u8]) -> IResult<&[u8], EncryptedExtensions> {
|
|
let (rest, extension_length) = take(2_usize)(bytes)?;
|
|
let extension_length: u16 = NetworkEndian::read_u16(extension_length);
|
|
let mut extension_length_counter: i32 = extension_length.into();
|
|
let mut extension_vec: Vec<Extension> = Vec::new();
|
|
|
|
// Split the data into "extensions" and the rest
|
|
let (rest, mut encypted_extension_data) =
|
|
take(usize::try_from(extension_length).unwrap())(rest)?;
|
|
|
|
while extension_length_counter > 0 {
|
|
let (rem, extension) = parse_extension(
|
|
encypted_extension_data,
|
|
HandshakeType::EncryptedExtensions
|
|
)?;
|
|
encypted_extension_data = rem;
|
|
extension_length_counter -= i32::try_from(extension.get_length()).unwrap();
|
|
|
|
// Todo:: Proper error
|
|
if extension_length_counter < 0 {
|
|
todo!()
|
|
}
|
|
|
|
extension_vec.push(extension);
|
|
}
|
|
|
|
let encrypted_extensions = EncryptedExtensions {
|
|
length: extension_length,
|
|
extensions: extension_vec
|
|
};
|
|
|
|
// Force completeness. The entire slice is meant to be processed.
|
|
complete(
|
|
take(0_usize)
|
|
)(rest)?;
|
|
|
|
Ok((rest, encrypted_extensions))
|
|
}
|
|
|
|
fn parse_certificate_request(bytes: &[u8]) -> IResult<&[u8], CertificateRequest> {
|
|
let (rest, certificate_request_context_length) = take(1_usize)(bytes)?;
|
|
let certificate_request_context_length = certificate_request_context_length[0];
|
|
|
|
let (rest, certificate_request_context) = take(
|
|
certificate_request_context_length
|
|
)(rest)?;
|
|
|
|
let (rest, extensions_length) = take(2_usize)(rest)?;
|
|
let extensions_length = NetworkEndian::read_u16(extensions_length);
|
|
let (rest, mut extensions_data) = take(extensions_length)(rest)?;
|
|
|
|
let mut extensions: Vec<Extension> = Vec::new();
|
|
|
|
while extensions_data.len() != 0 {
|
|
let (rem, extension) = parse_extension(
|
|
extensions_data,
|
|
HandshakeType::CertificateRequest
|
|
)?;
|
|
extensions_data = rem;
|
|
extensions.push(extension);
|
|
}
|
|
|
|
let certificate_request = CertificateRequest {
|
|
certificate_request_context_length,
|
|
certificate_request_context,
|
|
extensions_length,
|
|
extensions
|
|
};
|
|
|
|
Ok((
|
|
rest,
|
|
certificate_request
|
|
))
|
|
}
|
|
|
|
fn parse_handshake_certificate(bytes: &[u8]) -> IResult<&[u8], Certificate> {
|
|
let (rest, certificate_request_context_length) = take(1_usize)(bytes)?;
|
|
let certificate_request_context_length = certificate_request_context_length[0];
|
|
|
|
let (rest, certificate_request_context) = take(
|
|
certificate_request_context_length
|
|
)(rest)?;
|
|
|
|
let (mut rest, certificate_list_length) = take(3_usize)(rest)?;
|
|
let certificate_list_length = NetworkEndian::read_u24(certificate_list_length);
|
|
|
|
let mut certificate_struct = Certificate {
|
|
certificate_request_context_length,
|
|
certificate_request_context,
|
|
certificate_list_length,
|
|
certificate_list: Vec::new()
|
|
};
|
|
|
|
let mut certificate_list_length_counter: i32 = i32::try_from(certificate_list_length).unwrap();
|
|
while certificate_list_length_counter > 0 {
|
|
let (rem, (certificate_entry_length, certificate_entry)) =
|
|
parse_handshake_certificate_entry(rest)?;
|
|
|
|
certificate_list_length_counter -= i32::try_from(certificate_entry_length).unwrap();
|
|
rest = rem;
|
|
certificate_struct.certificate_list.push(certificate_entry);
|
|
}
|
|
|
|
Ok((
|
|
rest,
|
|
certificate_struct
|
|
))
|
|
|
|
}
|
|
|
|
fn parse_handshake_certificate_entry(bytes: &[u8]) -> IResult<&[u8], (u32, CertificateEntry)> {
|
|
let (rest, (cert_entry_info_size, cert_entry_info)) =
|
|
parse_handshake_certificate_entry_info(bytes)?;
|
|
|
|
let (mut rest, extensions_length) = take(2_usize)(rest)?;
|
|
let extensions_length = NetworkEndian::read_u16(extensions_length);
|
|
|
|
let mut extension_vec: Vec<Extension> = Vec::new();
|
|
let mut extension_length_counter: i32 = extensions_length.into();
|
|
while extension_length_counter > 0 {
|
|
let (rem, extension) = parse_extension(rest, HandshakeType::ServerHello)?;
|
|
rest = rem;
|
|
extension_length_counter -= i32::try_from(extension.get_length()).unwrap();
|
|
|
|
// Todo:: Proper error
|
|
if extension_length_counter < 0 {
|
|
todo!()
|
|
}
|
|
|
|
extension_vec.push(extension);
|
|
}
|
|
|
|
Ok((
|
|
rest,
|
|
(
|
|
u32::try_from(extensions_length).unwrap() + 2 + cert_entry_info_size,
|
|
CertificateEntry {
|
|
certificate_entry_info: cert_entry_info,
|
|
extensions_length,
|
|
extensions: extension_vec
|
|
}
|
|
)
|
|
))
|
|
}
|
|
|
|
fn parse_handshake_certificate_entry_info(bytes: &[u8]) -> IResult<&[u8], (u32, CertificateEntryInfo)> {
|
|
// Only supports X.509 certificate
|
|
// No negotiation for other certificate types in prior
|
|
let (rest, cert_data_length) = take(3_usize)(bytes)?;
|
|
let cert_data_length = NetworkEndian::read_u24(cert_data_length);
|
|
|
|
// Take the portion of bytes indicated by cert_data_length, and parse as
|
|
// X509 certificate.
|
|
let (rest, cert_data) = take(cert_data_length)(rest)?;
|
|
let (_, cert_data) = complete(
|
|
parse_asn1_der_certificate
|
|
)(cert_data)?;
|
|
|
|
Ok((
|
|
rest,
|
|
(
|
|
cert_data_length + 3,
|
|
CertificateEntryInfo::X509 {
|
|
cert_data_length,
|
|
cert_data
|
|
}
|
|
)
|
|
))
|
|
}
|
|
|
|
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);
|
|
|
|
// Take the signature portion out
|
|
let (rest, signature) = take(signature_length)(rest)?;
|
|
|
|
Ok((
|
|
rest,
|
|
CertificateVerify {
|
|
algorithm: signature_scheme,
|
|
signature_length,
|
|
signature
|
|
}
|
|
))
|
|
}
|
|
|
|
fn parse_finished(bytes: &[u8]) -> IResult<&[u8], Finished> {
|
|
Ok((
|
|
&[],
|
|
Finished { verify_data: bytes }
|
|
))
|
|
}
|
|
|
|
fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8], Extension> {
|
|
let extension_type = take(2_usize);
|
|
let length = take(2_usize);
|
|
|
|
let (rest, (extension_type, length)) =
|
|
tuple((extension_type, length))(bytes)?;
|
|
|
|
let extension_type = ExtensionType::try_from(
|
|
NetworkEndian::read_u16(extension_type)
|
|
).unwrap();
|
|
let length = NetworkEndian::read_u16(length);
|
|
|
|
// Process extension data according to extension_type
|
|
// TODO: Deal with HelloRetryRequest
|
|
let (rest, extension_data) = {
|
|
log::info!("extension type: {:?}", extension_type);
|
|
// TODO: Handle all mandatory extension type
|
|
use ExtensionType::*;
|
|
match extension_type {
|
|
SupportedVersions => {
|
|
match handshake_type {
|
|
HandshakeType::ClientHello => {
|
|
let (rest, versions_length) = take(1_usize)(rest)?;
|
|
let versions_length = versions_length[0];
|
|
|
|
let (rest, mut versions_slice) = take(versions_length)(rest)?;
|
|
let mut versions = Vec::new();
|
|
|
|
while versions_slice.len() != 0 {
|
|
let (rem, version) = take(2_usize)(versions_slice)?;
|
|
|
|
let tls_version = TlsVersion::try_from(
|
|
NetworkEndian::read_u16(version)
|
|
).unwrap();
|
|
if tls_version != TlsVersion::Unknown {
|
|
versions.push(tls_version);
|
|
}
|
|
|
|
versions_slice = rem;
|
|
}
|
|
|
|
let client_supported_versions = ExtensionData::SupportedVersions(
|
|
crate::tls_packet::SupportedVersions::ClientHello {
|
|
length: versions_length,
|
|
versions,
|
|
}
|
|
);
|
|
|
|
(
|
|
rest,
|
|
client_supported_versions
|
|
)
|
|
|
|
},
|
|
HandshakeType::ServerHello => {
|
|
let (rest, selected_version) = take(2_usize)(rest)?;
|
|
let selected_version = TlsVersion::try_from(
|
|
NetworkEndian::read_u16(selected_version)
|
|
).unwrap();
|
|
(
|
|
rest,
|
|
ExtensionData::SupportedVersions(
|
|
crate::tls_packet::SupportedVersions::ServerHello {
|
|
selected_version
|
|
}
|
|
)
|
|
)
|
|
},
|
|
_ => unreachable!()
|
|
}
|
|
},
|
|
SupportedGroups => { // NamedGroupList
|
|
let (rest, length) = take(2_usize)(rest)?;
|
|
let length = NetworkEndian::read_u16(length);
|
|
|
|
// Isolate contents, for easier error handling
|
|
let (rest, mut rem_data) = take(length)(rest)?;
|
|
|
|
let mut named_group_extension = NamedGroupList {
|
|
length,
|
|
named_group_list: Vec::new(),
|
|
};
|
|
|
|
for index in 0..(length/2) {
|
|
let (rem, named_group) = take(2_usize)(rem_data)?;
|
|
rem_data = rem;
|
|
let named_group = NamedGroup::try_from(
|
|
NetworkEndian::read_u16(named_group)
|
|
).unwrap();
|
|
named_group_extension.named_group_list.push(named_group);
|
|
|
|
// Assure completeness
|
|
if index == (length/2) {
|
|
complete(take(0_usize))(rem_data)?;
|
|
}
|
|
}
|
|
(
|
|
rest,
|
|
ExtensionData::NegotiatedGroups(
|
|
named_group_extension
|
|
)
|
|
)
|
|
}
|
|
KeyShare => {
|
|
match handshake_type {
|
|
HandshakeType::ClientHello => {
|
|
let (rest, length) = take(2_usize)(rest)?;
|
|
let length = NetworkEndian::read_u16(length);
|
|
let (rest, mut keyshares) = take(length)(rest)?;
|
|
|
|
let mut client_shares = Vec::new();
|
|
|
|
// Read all keyshares
|
|
while keyshares.len() != 0 {
|
|
let group = take(2_usize);
|
|
let length = take(2_usize);
|
|
let (rem, (group, length)) = tuple((
|
|
group, length
|
|
))(keyshares)?;
|
|
|
|
let mut key_share_entry = KeyShareEntry {
|
|
group: NamedGroup::try_from(
|
|
NetworkEndian::read_u16(group)
|
|
).unwrap(),
|
|
length: NetworkEndian::read_u16(length),
|
|
key_exchange: Vec::new()
|
|
};
|
|
|
|
let (rem, key_exchange_slice) = take(
|
|
key_share_entry.length
|
|
)(rem)?;
|
|
key_share_entry.key_exchange.extend_from_slice(key_exchange_slice);
|
|
|
|
client_shares.push(key_share_entry);
|
|
|
|
keyshares = rem;
|
|
}
|
|
|
|
let key_share_ch = crate::tls_packet::KeyShareEntryContent::KeyShareClientHello {
|
|
length,
|
|
client_shares
|
|
};
|
|
|
|
(rest, ExtensionData::KeyShareEntry(key_share_ch))
|
|
},
|
|
HandshakeType::ServerHello => {
|
|
let group = take(2_usize);
|
|
let length = take(2_usize);
|
|
let (rest, (group, length)) =
|
|
tuple((group, length))(rest)?;
|
|
let group = NamedGroup::try_from(
|
|
NetworkEndian::read_u16(group)
|
|
).unwrap();
|
|
let length = NetworkEndian::read_u16(length);
|
|
let (rest, key_exchange_slice) = take(length)(rest)?;
|
|
let mut key_exchange = Vec::new();
|
|
key_exchange.extend_from_slice(key_exchange_slice);
|
|
|
|
let server_share = KeyShareEntry {
|
|
group,
|
|
length,
|
|
key_exchange,
|
|
};
|
|
let key_share_sh = crate::tls_packet::KeyShareEntryContent::KeyShareServerHello {
|
|
server_share
|
|
};
|
|
(rest, ExtensionData::KeyShareEntry(key_share_sh))
|
|
},
|
|
_ => todo!()
|
|
}
|
|
},
|
|
SignatureAlgorithms => {
|
|
let (rest, supported_signature_algorithm_length) =
|
|
take(2_usize)(rest)?;
|
|
let supported_signature_algorithm_length =
|
|
NetworkEndian::read_u16(supported_signature_algorithm_length);
|
|
|
|
// Take the allocated extension bytes from rest
|
|
let (rest, mut algorithms) = take(
|
|
supported_signature_algorithm_length
|
|
)(rest)?;
|
|
|
|
// Parse all algorithms
|
|
let mut supported_signature_algorithms: Vec<SignatureScheme> =
|
|
Vec::new();
|
|
while algorithms.len() != 0 {
|
|
let (rem, algorithm) = take(2_usize)(algorithms)?;
|
|
let sig_alg = SignatureScheme::try_from(
|
|
NetworkEndian::read_u16(algorithm)
|
|
).unwrap();
|
|
algorithms = rem;
|
|
supported_signature_algorithms.push(sig_alg);
|
|
}
|
|
|
|
let signature_scheme_list = crate::tls_packet::SignatureSchemeList {
|
|
length: supported_signature_algorithm_length,
|
|
supported_signature_algorithms
|
|
};
|
|
|
|
(rest, ExtensionData::SignatureAlgorithms(signature_scheme_list))
|
|
},
|
|
_ => {
|
|
let (rest, _) = take(length)(rest)?;
|
|
(rest, ExtensionData::Unsupported)
|
|
}
|
|
}
|
|
};
|
|
|
|
Ok((
|
|
rest,
|
|
Extension {
|
|
extension_type,
|
|
length,
|
|
extension_data
|
|
}
|
|
))
|
|
}
|
|
|
|
// 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 {
|
|
// 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)));
|
|
}
|
|
|
|
let length_size = length_byte[0] & 0x7F;
|
|
let (rem, length_slice) = take(length_size)(rest)?;
|
|
let mut length_array: [u8; 8] = [0; 8];
|
|
for array_index in 0..length_slice.len() {
|
|
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>());
|
|
|
|
// 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()
|
|
)
|
|
))
|
|
}
|
|
}
|
|
|
|
// 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, header_size)) = parse_asn1_der_header(bytes)?;
|
|
let (rest, value) = take(length)(rest)?;
|
|
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,
|
|
parse_asn1_der_algorithm_identifier,
|
|
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, _, value)) = parse_asn1_der_object(bytes)?;
|
|
// Verify the tag is indeed 0x30
|
|
if tag_val != 0x30 {
|
|
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
|
}
|
|
|
|
let (_, (
|
|
version, serial_number, signature, issuer, validity, subject,
|
|
subject_public_key_info, issuer_unique_id, subject_unique_id, extensions
|
|
)) = complete(
|
|
tuple((
|
|
opt(parse_asn1_der_version),
|
|
parse_asn1_der_serial_number,
|
|
parse_asn1_der_algorithm_identifier,
|
|
parse_asn1_der_name,
|
|
parse_asn1_der_validity,
|
|
parse_asn1_der_name,
|
|
parse_asn1_der_subject_key_public_info,
|
|
opt(parse_asn1_der_bit_string),
|
|
opt(parse_asn1_der_bit_string),
|
|
opt(parse_asn1_der_extensions)
|
|
))
|
|
)(value)?;
|
|
|
|
let version = version.unwrap_or(Asn1DerVersion::v1);
|
|
let extensions = extensions.unwrap_or(
|
|
Asn1DerExtensions { extensions: Vec::new() }
|
|
);
|
|
|
|
Ok((
|
|
rest,
|
|
Asn1DerTBSCertificate {
|
|
version,
|
|
serial_number,
|
|
signature,
|
|
issuer,
|
|
validity,
|
|
subject,
|
|
subject_public_key_info,
|
|
issuer_unique_id,
|
|
subject_unique_id,
|
|
extensions,
|
|
}
|
|
))
|
|
}
|
|
|
|
// version: [0] EXPLICIT Version DEFAULT V1
|
|
// 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, _, value)) = parse_asn1_der_object(bytes)?;
|
|
// Verify the tag is indeed 0xA0
|
|
if tag_val != 0xA0 {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)));
|
|
}
|
|
// Parse the encapsulated INTEGER, force completeness
|
|
let (_, integer) = complete(parse_asn1_der_integer)(value)?;
|
|
// Either 0, 1, or 2, take the last byte and assert all former bytes to be 0
|
|
Ok((rest, Asn1DerVersion::try_from(integer[0]).unwrap()))
|
|
}
|
|
|
|
// INTEGER: tag: 0x02
|
|
pub fn parse_asn1_der_integer(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
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)));
|
|
}
|
|
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, _, value)) = parse_asn1_der_object(bytes)?;
|
|
// Verify the tag is indeed 0x03
|
|
if tag_val != 0x03 {
|
|
return Err(nom::Err::Error((bytes, 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 unused_bit_byte[0] != 0 {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)));
|
|
}
|
|
Ok((rest, value))
|
|
}
|
|
|
|
// BOOLEAN: tag: 0x01
|
|
// Length should be 1
|
|
// 0x00 -> false; 0xFF -> true
|
|
pub fn parse_asn1_der_boolean(bytes: &[u8]) -> IResult<&[u8], bool> {
|
|
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 || value.len() != 1 || (value[0] != 0x00 && value[0] != 0xFF) {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)));
|
|
}
|
|
Ok((rest, value[0] == 0xFF))
|
|
}
|
|
|
|
// SEQUENCE: tag: 0x30
|
|
pub fn parse_asn1_der_sequence(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
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)));
|
|
}
|
|
Ok((rest, value))
|
|
}
|
|
|
|
// SET: tag: 0x31
|
|
pub fn parse_asn1_der_set(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?;
|
|
// Verify the tag is indeed 0x31
|
|
if tag_val != 0x31 {
|
|
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
|
}
|
|
|
|
Ok((rest, value))
|
|
}
|
|
|
|
// CertificateSerialNumber: alias of INTEGER
|
|
pub fn parse_asn1_der_serial_number(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
parse_asn1_der_integer(bytes)
|
|
}
|
|
|
|
// 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, _, value)) = parse_asn1_der_object(bytes)?;
|
|
// Verify the tag_val is indeed 0x30
|
|
if tag_val != 0x30 {
|
|
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
|
}
|
|
// Parse OID, leave the rest as optionl parameters
|
|
let (optional_param, oid) = parse_asn1_der_oid(value)?;
|
|
|
|
Ok((
|
|
rest,
|
|
Asn1DerAlgId {
|
|
algorithm: oid,
|
|
parameters: optional_param,
|
|
}
|
|
))
|
|
}
|
|
|
|
// Parser for Universal OID type (0x06)
|
|
pub fn parse_asn1_der_oid(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
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)));
|
|
}
|
|
Ok((rest, value))
|
|
}
|
|
|
|
// Parser for Name, applicable to issuer and subject field of TBS cert.
|
|
pub fn parse_asn1_der_name(bytes: &[u8]) -> IResult<&[u8], Asn1DerName> {
|
|
let (rest, mut rdn_sequence) = parse_asn1_der_sequence(bytes)?;
|
|
let mut attributes_vec: Vec<Asn1DerRDN> = Vec::new();
|
|
|
|
while rdn_sequence.len() != 0 {
|
|
let (rem, attribute) = parse_asn1_der_relative_distinguished_name(
|
|
rdn_sequence
|
|
)?;
|
|
rdn_sequence = rem;
|
|
attributes_vec.push(attribute);
|
|
}
|
|
|
|
Ok((
|
|
rest,
|
|
Asn1DerName {
|
|
relative_distinguished_name: attributes_vec
|
|
}
|
|
))
|
|
}
|
|
|
|
// Parser for Relative Distinguished Name (RDN)
|
|
pub fn parse_asn1_der_relative_distinguished_name(bytes: &[u8]) -> IResult<&[u8], Asn1DerRDN> {
|
|
let (rest, mut attribute_set) = parse_asn1_der_set(bytes)?;
|
|
let mut attributes_vec: Vec<Asn1DerAttribute> = Vec::new();
|
|
|
|
while attribute_set.len() != 0 {
|
|
let (rem, attribute) = parse_asn1_der_attribute_type_and_value(
|
|
attribute_set
|
|
)?;
|
|
attribute_set = rem;
|
|
attributes_vec.push(attribute);
|
|
}
|
|
|
|
Ok((
|
|
rest,
|
|
Asn1DerRDN {
|
|
type_and_attributes: attributes_vec
|
|
}
|
|
))
|
|
}
|
|
|
|
// Parser for AttributeTypeAndValue struct, typically wrapped inside Name struct
|
|
pub fn parse_asn1_der_attribute_type_and_value(bytes: &[u8]) -> IResult<&[u8], Asn1DerAttribute> {
|
|
let (rest, set) = parse_asn1_der_sequence(bytes)?;
|
|
|
|
let (_, (oid, (tag_val, _, value))) = complete(
|
|
tuple((
|
|
parse_asn1_der_oid,
|
|
parse_asn1_der_object
|
|
))
|
|
)(set)?;
|
|
|
|
// Verify that tag_val is either "PrintableString or UTF8String"
|
|
if tag_val != 0x13 && tag_val != 0x0C && tag_val != 0x16 {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)));
|
|
}
|
|
|
|
Ok((
|
|
rest,
|
|
Asn1DerAttribute {
|
|
attribute_type: oid,
|
|
attribute_value: core::str::from_utf8(value).unwrap()
|
|
}
|
|
))
|
|
}
|
|
|
|
// Parser for Time Validity Sequence Structure (0x30)
|
|
pub fn parse_asn1_der_validity(bytes: &[u8]) -> IResult<&[u8], Asn1DerValidity> {
|
|
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)));
|
|
}
|
|
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], DateTime<FixedOffset>> {
|
|
let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?;
|
|
// Handle UTCTime, Gen.Time and Invalid Tag values
|
|
match tag_val {
|
|
0x17 => {
|
|
let (_, date_time) = complete(
|
|
parse_asn1_der_utc_time
|
|
)(value)?;
|
|
Ok((
|
|
rest,
|
|
date_time
|
|
))
|
|
},
|
|
0x18 => {
|
|
// TODO: Not implemented
|
|
let (_, date_time) = complete(
|
|
parse_asn1_der_generalized_time
|
|
)(value)?;
|
|
Ok((
|
|
rest,
|
|
date_time
|
|
))
|
|
},
|
|
_ => Err(nom::Err::Failure((&[], ErrorKind::Verify)))
|
|
}
|
|
}
|
|
|
|
// Parser for UTCTime
|
|
pub fn parse_asn1_der_utc_time(bytes: &[u8]) -> IResult<&[u8], DateTime<FixedOffset>> {
|
|
|
|
// Buffer for building string
|
|
// Need 19 characters to store the whole UTC time,
|
|
// and parsible by `chrono` parser
|
|
let mut string: String<U19> = String::new();
|
|
|
|
// Decide the appropriate century (1950 to 2049)
|
|
let year_tag: u8 = core::str::from_utf8(&bytes[..2]).unwrap().parse().unwrap();
|
|
if year_tag < 50 {
|
|
string.push_str("20").unwrap();
|
|
} else {
|
|
string.push_str("19").unwrap();
|
|
}
|
|
|
|
// Take out YYMMDDhhmm first
|
|
let (rest, first_part) = take(10_usize)(bytes)?;
|
|
string.push_str(core::str::from_utf8(first_part).unwrap()).unwrap();
|
|
let (rest, _) = if u8::is_ascii_digit(&rest[0]) {
|
|
let (rest, seconds) = take(2_usize)(rest)?;
|
|
string.push_str(core::str::from_utf8(seconds).unwrap()).unwrap();
|
|
(rest, seconds)
|
|
} else {
|
|
string.push_str("00").unwrap();
|
|
// The second parameter will not be used anymore,
|
|
// putting `rest` is an arbitrary choice
|
|
(rest, rest)
|
|
};
|
|
match rest[0] as char {
|
|
'Z' => {
|
|
string.push_str("+0000")
|
|
},
|
|
_ => {
|
|
string.push_str(core::str::from_utf8(rest).unwrap())
|
|
}
|
|
}.unwrap();
|
|
|
|
Ok((
|
|
&[],
|
|
DateTime::parse_from_str(
|
|
&string, "%Y%m%d%H%M%S%z"
|
|
).unwrap()
|
|
))
|
|
}
|
|
|
|
// Parser for GeneralizedTime
|
|
pub fn parse_asn1_der_generalized_time(bytes: &[u8]) -> IResult<&[u8], DateTime<FixedOffset>> {
|
|
|
|
// Buffer for building string
|
|
let mut string: String<U23> = String::new();
|
|
|
|
// Find the first non-digit byte
|
|
let mut first_non_digit_index = 0;
|
|
while first_non_digit_index < bytes.len() {
|
|
if !u8::is_ascii_digit(&bytes[first_non_digit_index]) {
|
|
break;
|
|
}
|
|
first_non_digit_index += 1;
|
|
}
|
|
|
|
string.push_str(core::str::from_utf8(
|
|
&bytes[..first_non_digit_index]).unwrap()
|
|
).unwrap();
|
|
|
|
match first_non_digit_index {
|
|
10 => string.push_str("0000.000").unwrap(),
|
|
12 => string.push_str("00.000").unwrap(),
|
|
14 => string.push_str(".000").unwrap(),
|
|
18 => {},
|
|
_ => return Err(nom::Err::Failure((&[], ErrorKind::Verify)))
|
|
};
|
|
|
|
match bytes.len() - first_non_digit_index {
|
|
// Local time, without relative time diff to UTC time
|
|
// Assume UTC
|
|
0 | 1 => string.push_str("+0000").unwrap(),
|
|
5 => string.push_str(core::str::from_utf8(
|
|
&bytes[first_non_digit_index..]).unwrap()
|
|
).unwrap(),
|
|
_ => return Err(nom::Err::Failure((&[], ErrorKind::Verify)))
|
|
};
|
|
|
|
Ok((
|
|
&[],
|
|
DateTime::parse_from_str(
|
|
&string, "%Y%m%d%H%M%S%.3f%z"
|
|
).unwrap()
|
|
))
|
|
}
|
|
|
|
// Parser for SubjectKeyPublicInfo (Sequence: 0x30)
|
|
pub fn parse_asn1_der_subject_key_public_info(bytes: &[u8]) -> IResult<&[u8], Asn1DerSubjectPublicKeyInfo> {
|
|
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)));
|
|
}
|
|
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 (Context-specific Sequence: 0xA3, then universal Sequence: 0x30)
|
|
pub fn parse_asn1_der_extensions(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensions> {
|
|
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, _, mut value)) = complete(
|
|
parse_asn1_der_object
|
|
)(value)?;
|
|
// Verify the tag_val is indeed 0x30
|
|
if tag_val != 0x30 {
|
|
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
|
}
|
|
|
|
let mut extensions = Vec::new();
|
|
while value.len() != 0 {
|
|
let (rem, extension) = parse_asn1_der_extension(value)?;
|
|
value = rem;
|
|
extensions.push(extension);
|
|
}
|
|
|
|
Ok((
|
|
rest,
|
|
Asn1DerExtensions { extensions }
|
|
))
|
|
}
|
|
|
|
// Parser for an extension (Sequence: 0x30)
|
|
pub fn parse_asn1_der_extension(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtension> {
|
|
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)));
|
|
}
|
|
|
|
// Parse an appropriate extension according to OID and critical-ness
|
|
let (_, (oid, critical, rem_ext_data)) = complete(
|
|
tuple((
|
|
parse_asn1_der_oid,
|
|
opt(parse_asn1_der_boolean),
|
|
parse_asn1_der_octet_string
|
|
))
|
|
)(value)?;
|
|
|
|
let extension_value = match oid {
|
|
oid::CERT_KEY_USAGE => {
|
|
let (_, extension_value) = complete(
|
|
parse_asn1_der_key_usage
|
|
)(rem_ext_data)?;
|
|
extension_value
|
|
},
|
|
oid::CERT_POLICIES => {
|
|
let (_, extension_value) = complete(
|
|
parse_asn1_der_certificate_policies
|
|
)(rem_ext_data)?;
|
|
extension_value
|
|
},
|
|
oid::CERT_BASIC_CONSTRAINTS => {
|
|
let (_, extension_value) = complete(
|
|
parse_asn1_der_basic_constraints
|
|
)(rem_ext_data)?;
|
|
extension_value
|
|
},
|
|
oid::CERT_EXT_KEY_USAGE => {
|
|
let (_, extension_value) = complete(
|
|
parse_asn1_der_extended_key_usage
|
|
)(rem_ext_data)?;
|
|
extension_value
|
|
},
|
|
oid::CERT_INHIBIT_ANY_POLICY => {
|
|
let (_, extension_value) = complete(
|
|
parse_inhibit_any_policy
|
|
)(rem_ext_data)?;
|
|
extension_value
|
|
},
|
|
oid::CERT_SUBJECTALTNAME => {
|
|
let (_, extension_value) = complete(
|
|
parse_asn1_der_subject_alternative_name
|
|
)(rem_ext_data)?;
|
|
extension_value
|
|
},
|
|
oid::CERT_NAME_CONSTRAINTS => {
|
|
let (_, extension_value) = complete(
|
|
parse_asn1_der_name_constraints
|
|
)(rem_ext_data)?;
|
|
extension_value
|
|
},
|
|
oid::CERT_POLICY_CONSTRAINTS => {
|
|
let (_, extension_value) = complete(
|
|
parse_asn1_der_policy_constraints
|
|
)(rem_ext_data)?;
|
|
extension_value
|
|
}
|
|
// TODO: Parse extension value for recognized extensions
|
|
_ => Asn1DerExtensionValue::Unrecognized
|
|
};
|
|
Ok((
|
|
rest,
|
|
Asn1DerExtension {
|
|
extension_id: oid,
|
|
critical: critical.map_or(false, |b| b),
|
|
extension_value
|
|
}
|
|
))
|
|
}
|
|
|
|
// 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, _, 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 || (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 value.len() == 2 {
|
|
[value[1], 0]
|
|
} else {
|
|
[value[1], value[2]]
|
|
};
|
|
let usage = (NetworkEndian::read_u16(&usage_array) >> padding) << padding;
|
|
Ok((
|
|
rest,
|
|
Asn1DerExtensionValue::KeyUsage {
|
|
usage
|
|
}
|
|
))
|
|
}
|
|
|
|
// Parser for Subject Alternative Name
|
|
pub fn parse_asn1_der_subject_alternative_name(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> {
|
|
let (_, mut names) = complete(
|
|
parse_asn1_der_sequence
|
|
)(bytes)?;
|
|
|
|
let mut general_names: Vec<Asn1DerGeneralName> = Vec::new();
|
|
|
|
while names.len() != 0 {
|
|
let (rest, general_name) = parse_asn1_der_general_name(names)?;
|
|
|
|
general_names.push(general_name);
|
|
names = rest;
|
|
}
|
|
|
|
Ok((
|
|
&[],
|
|
Asn1DerExtensionValue::SubjectAlternativeName { general_names }
|
|
))
|
|
}
|
|
|
|
// Parser for GeneralName
|
|
pub fn parse_asn1_der_general_name(bytes: &[u8]) -> IResult<&[u8], Asn1DerGeneralName> {
|
|
let (rest, (tag_val, _, name_value)) = parse_asn1_der_object(bytes)?;
|
|
let general_name = match tag_val {
|
|
0xA0 => { // Constructed type, contains type-id and value
|
|
let (_, (oid, (inner_tag_val, _, value))) = complete(
|
|
tuple((
|
|
parse_asn1_der_oid,
|
|
parse_asn1_der_object
|
|
))
|
|
)(name_value)?;
|
|
if inner_tag_val != 0xA0 {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)));
|
|
}
|
|
// Further parse the value into an ASN.1 DER object
|
|
let (_, (_, _, name_value)) = complete(
|
|
parse_asn1_der_object
|
|
)(value)?;
|
|
Asn1DerGeneralName::OtherName { type_id: oid, value: name_value }
|
|
},
|
|
|
|
0x81 => {
|
|
Asn1DerGeneralName::RFC822Name(name_value)
|
|
},
|
|
|
|
0x82 => {
|
|
Asn1DerGeneralName::DNSName(name_value)
|
|
},
|
|
|
|
0x83 => {
|
|
Asn1DerGeneralName::X400Address(name_value)
|
|
},
|
|
|
|
0x84 => {
|
|
let (_, name) = complete(
|
|
parse_asn1_der_name
|
|
)(name_value)?;
|
|
Asn1DerGeneralName::DirectoryName(name)
|
|
},
|
|
|
|
0xA5 => {
|
|
let (_, (
|
|
(name_assigner_tag_val, _, name_assigner),
|
|
party_name
|
|
)) = complete(
|
|
tuple((
|
|
parse_asn1_der_object,
|
|
opt(parse_asn1_der_object)
|
|
))
|
|
)(name_value)?;
|
|
|
|
let general_name = if party_name.is_none() && name_assigner_tag_val == 0x81 {
|
|
Asn1DerGeneralName::EDIPartyName {
|
|
name_assigner: &[],
|
|
party_name: name_assigner
|
|
}
|
|
} else if party_name.is_some() && name_assigner_tag_val == 0x80 {
|
|
if let Some((party_name_tag_val, _, party_name_value)) = party_name {
|
|
if party_name_tag_val == 0x81 {
|
|
Asn1DerGeneralName::EDIPartyName {
|
|
name_assigner,
|
|
party_name: party_name_value
|
|
}
|
|
}
|
|
else {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)))
|
|
}
|
|
} else {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)))
|
|
}
|
|
} else {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)))
|
|
};
|
|
|
|
general_name
|
|
},
|
|
|
|
0x86 => {
|
|
Asn1DerGeneralName::URI(name_value)
|
|
},
|
|
|
|
0x87 => {
|
|
Asn1DerGeneralName::IPAddress(name_value)
|
|
},
|
|
|
|
0x88 => {
|
|
Asn1DerGeneralName::RegisteredID(name_value)
|
|
},
|
|
|
|
_ => return Err(nom::Err::Error((bytes, ErrorKind::Verify)))
|
|
};
|
|
|
|
Ok((rest, general_name))
|
|
}
|
|
|
|
// Parser for Name Constraints
|
|
pub fn parse_asn1_der_name_constraints(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> {
|
|
let (_, subtrees) = complete(
|
|
parse_asn1_der_sequence
|
|
)(bytes)?;
|
|
|
|
// Init name constraint extension
|
|
let mut permitted_subtrees = Vec::new();
|
|
let mut excluded_subtrees = Vec::new();
|
|
|
|
let (other_subtree, (mut tag_val, _, mut subtree)) = parse_asn1_der_object(subtrees)?;
|
|
|
|
if tag_val == 0xA0 {
|
|
while subtree.len() != 0 {
|
|
let (rest, permitted_names) = parse_asn1_der_sequence(subtree)?;
|
|
|
|
// Ignore the `minimum` field and `maximum` field
|
|
// Simpily reject any certificate with these 2 field could be a solution
|
|
let (_, general_name) = parse_asn1_der_general_name(permitted_names)?;
|
|
permitted_subtrees.push(general_name);
|
|
subtree = rest;
|
|
}
|
|
|
|
// Move on to the excluded subtrees, or exit the procedure
|
|
if other_subtree.len() == 0 {
|
|
return Ok((
|
|
&[],
|
|
Asn1DerExtensionValue::NameConstraints {
|
|
permitted_subtrees,
|
|
excluded_subtrees
|
|
}
|
|
))
|
|
} else {
|
|
let (_, (second_tag_val, _, second_subtree)) = complete(parse_asn1_der_object)(other_subtree)?;
|
|
tag_val = second_tag_val;
|
|
subtree = second_subtree;
|
|
}
|
|
}
|
|
|
|
if tag_val == 0xA1 {
|
|
while subtree.len() != 0 {
|
|
let (rest, excluded_names) = parse_asn1_der_sequence(subtree)?;
|
|
|
|
// Ignore the `minimum` field and `maximum` field
|
|
// Simpily reject any certificate with these 2 field could be a solution
|
|
let (_, general_name) = parse_asn1_der_general_name(excluded_names)?;
|
|
excluded_subtrees.push(general_name);
|
|
subtree = rest;
|
|
}
|
|
}
|
|
|
|
return Ok((
|
|
&[],
|
|
Asn1DerExtensionValue::NameConstraints {
|
|
permitted_subtrees,
|
|
excluded_subtrees
|
|
}
|
|
))
|
|
}
|
|
|
|
// Parser for policy constraints
|
|
pub fn parse_asn1_der_policy_constraints(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> {
|
|
// Strip sequence
|
|
let (_, constraint_seq) = complete(
|
|
parse_asn1_der_sequence
|
|
)(bytes)?;
|
|
|
|
// Init policy constraints
|
|
let mut require_explicit_policy = None;
|
|
let mut inhibit_policy_mapping = None;
|
|
|
|
let (rest, (mut tag_val, _, mut policy)) = parse_asn1_der_object(constraint_seq)?;
|
|
if tag_val == 0x80 {
|
|
let temp = if policy.len() > 1 {
|
|
// The maximum acceptable cert chain length would probably be less than 10
|
|
128
|
|
} else {
|
|
policy[0]
|
|
};
|
|
require_explicit_policy.replace(temp);
|
|
|
|
if rest.len() == 0 {
|
|
return Ok((
|
|
&[],
|
|
Asn1DerExtensionValue::PolicyConstraints {
|
|
require_explicit_policy,
|
|
inhibit_policy_mapping
|
|
}
|
|
))
|
|
}
|
|
|
|
let (_, (second_tag_val, _, second_policy)) = complete(
|
|
parse_asn1_der_object
|
|
)(rest)?;
|
|
tag_val = second_tag_val;
|
|
policy = second_policy;
|
|
}
|
|
|
|
if tag_val == 0x81 {
|
|
let temp = if policy.len() > 1 {
|
|
// The maximum acceptable cert chain length would probably be less than 10
|
|
128
|
|
} else {
|
|
policy[0]
|
|
};
|
|
inhibit_policy_mapping.replace(temp);
|
|
}
|
|
|
|
Ok((
|
|
&[],
|
|
Asn1DerExtensionValue::PolicyConstraints {
|
|
require_explicit_policy,
|
|
inhibit_policy_mapping
|
|
}
|
|
))
|
|
}
|
|
|
|
// Parser for CertificatePolicies Extension (sequence: 0x30)
|
|
pub fn parse_asn1_der_certificate_policies(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> {
|
|
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)));
|
|
}
|
|
|
|
let mut vec: Vec<Asn1DerPolicyInformation> = Vec::new();
|
|
|
|
while value.len() != 0 {
|
|
let (rem, info) = parse_asn1_der_policy_information(value)?;
|
|
value = rem;
|
|
vec.push(info);
|
|
}
|
|
|
|
Ok((
|
|
rest,
|
|
Asn1DerExtensionValue::CertificatePolicies {
|
|
info: vec,
|
|
}
|
|
))
|
|
}
|
|
|
|
// Parser for PolicyInformation (Sequence: 0x30)
|
|
pub fn parse_asn1_der_policy_information(bytes: &[u8]) -> IResult<&[u8], Asn1DerPolicyInformation> {
|
|
let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?;
|
|
// Verify tag value
|
|
if tag_val != 0x30 {
|
|
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
|
}
|
|
|
|
let (qualifier, oid) = parse_asn1_der_oid(value)?;
|
|
|
|
Ok((
|
|
rest,
|
|
Asn1DerPolicyInformation {
|
|
id: oid,
|
|
qualifier
|
|
}
|
|
))
|
|
}
|
|
|
|
// Parser for BasicConstraints (Sequence: 0x30)
|
|
pub fn parse_asn1_der_basic_constraints(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> {
|
|
let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?;
|
|
// Verify tag value
|
|
if tag_val != 0x30 {
|
|
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
|
}
|
|
let (_, (is_ca, path_len_constraint)) = complete(
|
|
tuple((
|
|
opt(parse_asn1_der_boolean),
|
|
opt(parse_asn1_der_integer)
|
|
))
|
|
)(value)?;
|
|
let is_ca = is_ca.map_or(false, |b| b);
|
|
let path_len_constraint = path_len_constraint.map(
|
|
|slice| {
|
|
if slice.len() != 1 {
|
|
255
|
|
} else {
|
|
slice[0]
|
|
}
|
|
}
|
|
);
|
|
Ok((
|
|
rest,
|
|
Asn1DerExtensionValue::BasicConstraints {
|
|
is_ca,
|
|
path_len_constraint
|
|
}
|
|
))
|
|
}
|
|
|
|
// 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, _, mut value)) = parse_asn1_der_object(bytes)?;
|
|
// Verify tag value
|
|
if tag_val != 0x30 {
|
|
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
|
}
|
|
|
|
let mut flags: [bool; 7] = [false; 7];
|
|
|
|
while value.len() != 0 {
|
|
let (rem, oid_val) = parse_asn1_der_oid(value)?;
|
|
value = rem;
|
|
match oid_val {
|
|
oid::ANY_EXTENDED_KEY_USAGE => flags[0] = true,
|
|
oid::ID_KP_SERVER_AUTH => flags[1] = true,
|
|
oid::ID_KP_CLIENT_AUTH => flags[2] = true,
|
|
oid::ID_KP_CODE_SIGNING => flags[3] = true,
|
|
oid::ID_KP_EMAIL_PROTECTION => flags[4] = true,
|
|
oid::ID_KP_TIME_STAMPING => flags[5] = true,
|
|
oid::ID_KP_OCSP_SIGNING => flags[6] = true,
|
|
_ => {},
|
|
}
|
|
}
|
|
|
|
Ok((
|
|
rest,
|
|
Asn1DerExtensionValue::ExtendedKeyUsage {
|
|
any_extended_key_usage: flags[0],
|
|
id_kp_server_auth: flags[1],
|
|
id_kp_client_auth: flags[2],
|
|
id_kp_code_signing: flags[3],
|
|
id_kp_email_protection: flags[4],
|
|
id_kp_time_stamping: flags[5],
|
|
id_kp_oscp_signing: flags[6],
|
|
}
|
|
))
|
|
}
|
|
|
|
// Parser for inhibit anyPolicy extension (integer)
|
|
pub fn parse_inhibit_any_policy(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> {
|
|
let (rest, integer_slice) = parse_asn1_der_integer(bytes)?;
|
|
Ok((
|
|
rest,
|
|
Asn1DerExtensionValue::InhibitAnyPolicy {
|
|
skip_certs: {
|
|
if integer_slice.len() == 1 {
|
|
integer_slice[0]
|
|
} else {
|
|
255
|
|
}
|
|
}
|
|
}
|
|
))
|
|
}
|
|
|
|
|
|
// Parser for octet string (tag: 0x04)
|
|
pub fn parse_asn1_der_octet_string(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?;
|
|
// Verify tag value
|
|
if tag_val != 0x04 {
|
|
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
|
}
|
|
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)
|
|
))
|
|
}
|
|
|
|
/*
|
|
* Prasers for PSS signature algorithms parameters in certificate
|
|
*/
|
|
|
|
// Take addition parameter of PSS algorithm idenfier
|
|
// Return hash function OID
|
|
pub fn parse_rsa_ssa_pss_parameters(params: &[u8]) -> IResult<&[u8], (&[u8], usize)> {
|
|
// Handle the case where there is literally no optional parameter
|
|
// Return default SHA1 OID and 20 salt length
|
|
if params.len() == 0 {
|
|
return Ok((&[], (ID_SHA1, 20)))
|
|
}
|
|
|
|
// Parse as RSASSA-PSS-params (Sequence: 0x30)
|
|
let (_, rsa_ssa_params) = complete(
|
|
parse_asn1_der_sequence
|
|
)(params)?;
|
|
|
|
let (_, (hash_alg, mgf_hash_alg, salt_len, _)) = complete(
|
|
tuple((
|
|
opt(parse_hash_algorithm),
|
|
opt(parse_mask_gen_algorithm),
|
|
opt(parse_salt_length),
|
|
opt(parse_trailer_field)
|
|
))
|
|
)(rsa_ssa_params)?;
|
|
|
|
let hash_alg = hash_alg.unwrap_or(
|
|
Asn1DerAlgId { algorithm: ID_SHA1, parameters: &[] }
|
|
);
|
|
let mgf_hash_alg = mgf_hash_alg.unwrap_or(
|
|
Asn1DerAlgId { algorithm: ID_SHA1, parameters: &[] }
|
|
);
|
|
let salt_len = salt_len.unwrap_or(&[0x14]);
|
|
|
|
// Verify that the hash functions listed in HashFunc and MGF are consistent
|
|
if hash_alg.algorithm != mgf_hash_alg.algorithm {
|
|
todo!()
|
|
}
|
|
|
|
// Parse encoded salt length integer into usize
|
|
if salt_len.len() > core::mem::size_of::<usize>() {
|
|
todo!()
|
|
}
|
|
let mut array_buffer: [u8; core::mem::size_of::<usize>()] = [0; core::mem::size_of::<usize>()];
|
|
array_buffer[(core::mem::size_of::<usize>()-salt_len.len())..].clone_from_slice(salt_len);
|
|
let salt_len = usize::from_be_bytes(array_buffer);
|
|
|
|
Ok((
|
|
&[],
|
|
(
|
|
hash_alg.algorithm,
|
|
salt_len
|
|
)
|
|
))
|
|
}
|
|
|
|
fn parse_hash_algorithm(bytes: &[u8]) -> IResult<&[u8], Asn1DerAlgId> {
|
|
// Parse HashAlgorithm [0]
|
|
let (rest, (tag_val, _, hash_alg)) = parse_asn1_der_object(bytes)?;
|
|
// Verify the tag is indeed 0xA0
|
|
if tag_val != 0xA0 {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)));
|
|
}
|
|
// Parse the encapsulated algorithm identifier, force completeness
|
|
let (_, hash_alg) = complete(parse_asn1_der_algorithm_identifier)(hash_alg)?;
|
|
Ok((
|
|
rest, hash_alg
|
|
))
|
|
}
|
|
|
|
fn parse_mask_gen_algorithm(bytes: &[u8]) -> IResult<&[u8], Asn1DerAlgId> {
|
|
// Parse MaskGenAlgorithm [1]
|
|
let (rest, (tag_val, _, mask_gen_alg)) = parse_asn1_der_object(bytes)?;
|
|
// Verify the tag is indeed 0xA1
|
|
if tag_val != 0xA1 {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)));
|
|
}
|
|
// Parse the encapsulated algorithm identifier, force completeness
|
|
let (_, mgf) = complete(parse_asn1_der_algorithm_identifier)(mask_gen_alg)?;
|
|
// Algorithm field of mgf should always be mgf1
|
|
if mgf.algorithm != ID_MGF1 {
|
|
todo!()
|
|
}
|
|
// Parse the parameters of MGF Alg. Ident. to get hash algorithm under MGF
|
|
let (_, mgf_hash_alg) = complete(parse_asn1_der_algorithm_identifier)(
|
|
mgf.parameters
|
|
)?;
|
|
Ok((
|
|
rest, mgf_hash_alg
|
|
))
|
|
}
|
|
|
|
fn parse_salt_length(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
// Parse salt length [2]
|
|
let (rest, (tag_val, _, salt_len)) = parse_asn1_der_object(bytes)?;
|
|
if tag_val != 0xA2 {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)));
|
|
}
|
|
// Parse the encapsulated integer, force completeness
|
|
let (_, salt_len) = complete(
|
|
parse_asn1_der_integer
|
|
)(salt_len)?;
|
|
|
|
Ok((
|
|
rest, salt_len
|
|
))
|
|
}
|
|
|
|
fn parse_trailer_field(bytes: &[u8]) -> IResult<&[u8], ()> {
|
|
// Parse trailer field [3]
|
|
let (_, (tag_val, _, trailer_field)) = complete(
|
|
parse_asn1_der_object
|
|
)(bytes)?;
|
|
if tag_val != 0xA3 {
|
|
return Err(nom::Err::Error((bytes, ErrorKind::Verify)));
|
|
}
|
|
// Parse the encapsulated integer, force completeness
|
|
let (_, trailer_field) = complete(
|
|
parse_asn1_der_integer
|
|
)(trailer_field)?;
|
|
// The value must be 1 stated in RFC 4055
|
|
if trailer_field.len() < 1 || trailer_field[trailer_field.len() - 1] != 1 {
|
|
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
|
}
|
|
|
|
Ok((
|
|
&[], ()
|
|
))
|
|
}
|
|
|
|
// Parser for identifying `r` and `s` fields of ECDSA signatures
|
|
pub fn parse_ecdsa_signature(sig: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
|
|
let (_, sig_val) = complete(
|
|
parse_asn1_der_sequence
|
|
)(sig)?;
|
|
complete(
|
|
tuple((
|
|
parse_asn1_der_integer,
|
|
parse_asn1_der_integer
|
|
))
|
|
)(sig_val)
|
|
}
|