Compare commits
2 Commits
9aeecc968e
...
45216e8af6
Author | SHA1 | Date |
---|---|---|
occheung | 45216e8af6 | |
occheung | a57998dc2d |
|
@ -66,6 +66,11 @@ version = "5.1.2"
|
|||
default-features = false
|
||||
features = []
|
||||
|
||||
[dependencies.chrono]
|
||||
version = "0.4.19"
|
||||
default-features = false
|
||||
features = []
|
||||
|
||||
[dependencies.simple_logger]
|
||||
version = "1.11.0"
|
||||
optional = true
|
||||
|
|
|
@ -3,6 +3,8 @@ use num_enum::TryFromPrimitive;
|
|||
|
||||
use generic_array::GenericArray;
|
||||
|
||||
use chrono::{DateTime, FixedOffset};
|
||||
|
||||
use crate::parse::parse_asn1_der_rsa_public_key;
|
||||
use crate::parse::parse_rsa_ssa_pss_parameters;
|
||||
use crate::parse::parse_ecdsa_signature;
|
||||
|
@ -38,7 +40,7 @@ pub struct TBSCertificate<'a> {
|
|||
pub serial_number: &'a [u8],
|
||||
pub signature: AlgorithmIdentifier<'a>,
|
||||
pub issuer: Name<'a>,
|
||||
pub validity: Validity<'a>,
|
||||
pub validity: Validity,
|
||||
pub subject: Name<'a>,
|
||||
pub subject_public_key_info: SubjectPublicKeyInfo<'a>,
|
||||
pub issuer_unique_id: Option<&'a [u8]>,
|
||||
|
@ -57,9 +59,9 @@ pub enum Version {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Validity<'a> {
|
||||
pub not_before: Time<'a>,
|
||||
pub not_after: Time<'a>,
|
||||
pub struct Validity {
|
||||
pub not_before: DateTime<FixedOffset>,
|
||||
pub not_after: DateTime<FixedOffset>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -105,7 +107,6 @@ pub enum ExtensionValue<'a> {
|
|||
info: Vec<PolicyInformation<'a>>
|
||||
},
|
||||
|
||||
// Permitted subtrees and excluded subtrees are not implemented
|
||||
SubjectAlternativeName {
|
||||
general_names: Vec<GeneralName<'a>>,
|
||||
},
|
||||
|
@ -115,11 +116,23 @@ pub enum ExtensionValue<'a> {
|
|||
path_len_constraint: Option<u8>,
|
||||
},
|
||||
|
||||
// Permitted subtrees and excluded subtrees are not implemented
|
||||
// NameConstraints,
|
||||
NameConstraints {
|
||||
// Owns a list of acceptable/unacceptable GeneralNames
|
||||
// Maximum field should not exist, minimum field is always 0
|
||||
// Vector size of 0 equivalent to NIL
|
||||
// While it doesn't make sense to have both subtrees,
|
||||
// the RFC (RFC 5280) mandated that any subtree stated in
|
||||
// excluded subtree cannot be permitted, even if it is part of
|
||||
// the permitted subtree.
|
||||
// It is probably intentional to have OPTIONAL over CHOICE
|
||||
permitted_subtrees: Vec<GeneralName<'a>>,
|
||||
excluded_subtrees: Vec<GeneralName<'a>>,
|
||||
},
|
||||
|
||||
// Policy mapping will not be supported
|
||||
// PolicyConstraints,
|
||||
PolicyConstraints {
|
||||
require_explicit_policy: Option<u8>,
|
||||
inhibit_policy_mapping: Option<u8>,
|
||||
},
|
||||
|
||||
ExtendedKeyUsage {
|
||||
// A list of all possible extended key usage in OID
|
||||
|
|
|
@ -120,7 +120,7 @@ const CA_SIGNED_CERT: [u8; 0x0356] =
|
|||
"308203523082023a02146048517ee55aabd1e8f2bd7db1d91e679708e644300d06092a864886f70d01010b05003067310b30090603550406130255533113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c74643120301e06035504030c176578616d706c65732e63612e756c666865696d2e6e6574301e170d3230313130363034323035305a170d3230313230363034323035305a3064310b30090603550406130255533113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c7464311d301b06035504030c146578616d706c65732e756c666865696d2e6e657430820122300d06092a864886f70d01010105000382010f003082010a0282010100b2940671bfe7ace7416ba9d34018c229588e9d4eed8bd6623e44ab1239e8f1f0de9050b2f485a98e63f5b483330fb0b5abaeb33d11889033b0b684bf34696d28206bb361782c4b106a8d47874cbbdf971b5ab887bca508bccf250a1a811cee078464638e441941347d4c8885ac9b59d9fc9636276912b04d9e3ab29bd8ad319572ae54f0b6145c4d675a78607dcc4793a4d432f1c2a41ea29dd4f7262b6fe472dfaea51aca992b4624e73fa9901fa364fc5b721052ef3187e659d58d2706770d365380a7ebab6caac5b23271c01531fdf95368ee48af5383035f249be7c18f50ce9e52877558efe4b2e29f61328396e2a3b5e71309ad13d93d6ba3d5c3eb2b650203010001300d06092a864886f70d01010b0500038201010063c9ab0f5d2e164513e8e74b656ae4f48dd004c3ead9f1026b7741cbf02bb0efcf19e0fbf8a788dae059a2393167f016bafc0e3efd5c5b4c43079b6506eb67f17f44f9591503c7d1fdb77bf631894817393ea82610ad5106d23ec6bf1a6d96d749f05c0136cd71256617a51fe862529aee4a37d5f456dc7da8b220ff10ede4e87bc63e4589b3f81133a7f82ab900419e8a2d802d59e99cfbbd268702efd17616168b45b5211da0e644c29dcb92dbbf32b43586bbab05deb0261771605c52836363bd28ff9853d44436349f5ba11f2640bc9c42688e0d5eb6cac9f3f5e5f98652fa4f4ba52604371ec45f09d678e31d463285a4b3734f587f35a339920544f476"
|
||||
);
|
||||
|
||||
const SELF_SIGNED_WITH_SAN: [u8; 0x03E8] =
|
||||
const SELF_SIGNED_WITH_SAN: [u8; 0x046C] =
|
||||
hex_literal::hex!(
|
||||
"308203e4308202cca00302010202145e88e088cb38c6b2b61eb94eae6d2c2429382148300d06092a864886f70d01010b05003070310b3009060355040613025553310b300906035504080c0256413111300f06035504070c08536f6d654369747931123010060355040a0c094d79436f6d70616e7931133011060355040b0c0a4d794469766973696f6e3118301606035504030c0f7777772e636f6d70616e792e636f6d301e170d3230313130363039303230345a170d3232313130363039303230345a3070310b3009060355040613025553310b300906035504080c0256413111300f06035504070c08536f6d654369747931123010060355040a0c094d79436f6d70616e7931133011060355040b0c0a4d794469766973696f6e3118301606035504030c0f7777772e636f6d70616e792e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100e1d7d8ddb3ec0e334e7d8e5aff8272384e755488e887b1ac9c520a95fbfb75aff84e5d5bab76fe397d0bd73e9bf5358824ecf26c2040f4f04ccff04e60e5469294fb2b18fa8533d8826d1cac977d37f0673fb102fa583e78cb965271f66160b86889acf7add28804eeaeff385084961c3e60dda38f83dd7f37eead28dfedd715fbc57512e9f7c0b297eea2ad752483bc09d9dfd7d8466a5de3f875bb5b9a86b6f0cc4853bab323c0e31369d36f4e230d498198d800f2fefdc70525e5e8785262d90e67c442dc1c92ea22239dbdb0f5915b0e9ac05fd23a755e92030af606b0bf738bd5d9e7416c278785066057a3a828030229a5e6ec8f1a561fa6d4b03473650203010001a3763074300b0603551d0f04040302043030130603551d25040c300a06082b0601050507030130500603551d1104493047820f7777772e636f6d70616e792e6e6574820b636f6d70616e792e636f6d820b636f6d70616e792e6e6574810b626f6240636f6d70616e79810d616c69636540636f6d70616e79300d06092a864886f70d01010b050003820101008ee6ca325376df41ca6858c5ab6bc2d82d20b8d20bd7a6a007a62047f67e4c5988dc60e6e313a3d4456c87ac9b7d064af61012d9e5e630839471255166fb3f2de460dbf2ff88f2b26d385e605c7f47f8bd0a34e1ab4726e82642c5eba7e2b49a05c829704618362341ce02dca477b76e6d8919a4ec568aafa581a710220c7101d686f36f381b1851c06ed9f2c3de26befb95ea653dc7429c0abe8dd66b2328d7b41222b06237840835a15073d3f314c0d84b812fe7829e42da8174dac600845bf367685c5607196c2bcc06aad54eec531d93cfb6fea7995d65272cab575faaac7c9029a312e664ef0d3880fa4e0acaeee4c144ffb994a64118713def59360f6c"
|
||||
"3082046830820350a00302010202145525dc68e0e749158bf5bee8fe12c71675127510300d06092a864886f70d01010b05003073310b3009060355040613025553310b300906035504080c0256413114301206035504070c0b416e6f746865724369747931123010060355040a0c094d79436f6d70616e7931133011060355040b0c0a4d794469766973696f6e3118301606035504030c0f7777772e636f6d70616e792e636f6d301e170d3230313130393035353034385a170d3231313130393035353034385a3073310b3009060355040613025553310b300906035504080c0256413114301206035504070c0b416e6f746865724369747931123010060355040a0c094d79436f6d70616e7931133011060355040b0c0a4d794469766973696f6e3118301606035504030c0f7777772e636f6d70616e792e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100a03fec3ee07c6dce516520ab9166b7b5d95c13196328cb443e8419d748889ebc99a22b8032240a816b585e2affaea7383e4b655aacc06ee67814693fc440f6a27939e793a85280334a4662da460802123d191dccfe029997cc7f94f7ff9aef7a2d662f01fb9cd153e14c6b21ab28b209f09082d635b705bca4553efaeaddc21d7fc73366130a54270175c608cff2f2336fbf13896ebfc44016259032c81f2499f19ce14da840f25b0339fae72926b231ec6f14b7ff66716be0d3471f6485b6657270834fc4058e93625d4df95eb3a95c2eec48c3f060cdd740e373fc240e3c76d5c3c3f11cb53dab471d8af6b46e0294b3c7a75c82edcbab24af0448237310b90203010001a381f33081f0300b0603551d0f04040302043030130603551d25040c300a06082b0601050507030130760603551d11046f306d820f7777772e636f6d70616e792e6e6574820b636f6d70616e792e636f6d820b636f6d70616e792e6e6574810b626f6240636f6d70616e79810d616c69636540636f6d70616e79a01e06032a0304a0170c15736f6d65206f74686572206964656e7469666965728704c0a801c830430603551d1e043c303aa01c300e820c2e6578616d706c652e636f6d300a8708c0a80001ffffff00a11a300a8708c0aa0001ffffff00300c820a2e6c6f63616c686f7374300f0603551d2404083006800103810105300d06092a864886f70d01010b0500038201010079721d5b3b0f17edc425ac5f6faa5d085760eba5ebd0bc2a5010a0893e46c68656fecc0b66c7216fb093a07aaad88819011b9daa0407aef06778c7c04dbc2f5dd20d3156cccd3a36298b26d8d548d2ae4564b55f1e00fe49d6a7c53f05eecd0b63d7716d51a59c71141f9b223cbf79c57d46a7a240d2bc851f38c7da45c9ec7ad99381605247e46309541ea89fe9e175f8fd4c296b7ea667dafb8d4310e577c79be50a1d3b48c4d012a01aaf605816f37f5a00f1cb86dee776b31f8a444a79f48313502b23d001d1f3a641f9ec05960180cfa0440b8002afc3b49c3c1779adfd7f9ecef38fb14c2b3902323314990928f764c70a579e02453fec03bc78f98914"
|
||||
);
|
||||
|
|
|
@ -73,6 +73,8 @@ pub const CERT_BASIC_CONSTRAINTS: &'static [u8] = &[85, 29, 19];
|
|||
pub const CERT_EXT_KEY_USAGE: &'static [u8] = &[85, 29, 37]; // 2.5.29.37
|
||||
pub const CERT_INHIBIT_ANY_POLICY: &'static [u8] = &[85, 29, 54]; // 2.5.29.54
|
||||
pub const CERT_SUBJECTALTNAME: &'static [u8] = &[85, 29, 17]; // 2.5.29.17
|
||||
pub const CERT_NAME_CONSTRAINTS: &'static [u8] = &[85, 29, 30]; // 2.5.29.30
|
||||
pub const CERT_POLICY_CONSTRAINTS: &'static [u8] = &[85, 29, 36]; // 2.5.29.36
|
||||
// Extended Key Extensions
|
||||
pub const ANY_EXTENDED_KEY_USAGE: &'static [u8] = &[85, 29, 37, 0]; // 2.5.29.37.0
|
||||
pub const ID_KP_SERVER_AUTH: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 1]; // 1.3.6.1.5.5.7.3.1
|
||||
|
|
440
src/parse.rs
440
src/parse.rs
|
@ -7,6 +7,11 @@ use nom::combinator::opt;
|
|||
use nom::sequence::preceded;
|
||||
use nom::sequence::tuple;
|
||||
use nom::error::ErrorKind;
|
||||
use nom::character::complete::digit0;
|
||||
use nom::character::is_digit;
|
||||
|
||||
use chrono::{DateTime, FixedOffset, TimeZone};
|
||||
use heapless::{String, consts::*};
|
||||
|
||||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
|
||||
|
@ -26,7 +31,7 @@ use crate::certificate::{
|
|||
TBSCertificate as Asn1DerTBSCertificate,
|
||||
Name as Asn1DerName,
|
||||
AttributeTypeAndValue as Asn1DerAttribute,
|
||||
GeneralName as Asn1DerGeneralName
|
||||
GeneralName as Asn1DerGeneralName,
|
||||
};
|
||||
|
||||
use crate::oid;
|
||||
|
@ -876,26 +881,121 @@ 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> {
|
||||
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,
|
||||
Asn1DerTime::UTCTime(value)
|
||||
date_time
|
||||
))
|
||||
},
|
||||
0x18 => {
|
||||
// TODO: Not implemented
|
||||
let (_, date_time) = complete(
|
||||
parse_asn1_der_generalized_time
|
||||
)(value)?;
|
||||
Ok((
|
||||
rest,
|
||||
Asn1DerTime::GeneralizedTime(value)
|
||||
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
|
||||
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");
|
||||
} else {
|
||||
string.push_str("19");
|
||||
}
|
||||
|
||||
// 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
|
||||
(rest, rest)
|
||||
};
|
||||
match rest[0] as char {
|
||||
'Z' => {
|
||||
string.push_str("+0000")
|
||||
},
|
||||
_ => {
|
||||
string.push_str(core::str::from_utf8(rest).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)?;
|
||||
|
@ -952,6 +1052,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> {
|
||||
log::info!("Extension: {:X?}\n", bytes);
|
||||
let (rest, (tag_val, _, value)) = parse_asn1_der_object(bytes)?;
|
||||
// Verify the tag_val is indeed 0x30
|
||||
if tag_val != 0x30 {
|
||||
|
@ -1003,6 +1104,18 @@ pub fn parse_asn1_der_extension(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtension
|
|||
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
|
||||
|
@ -1051,113 +1164,10 @@ pub fn parse_asn1_der_subject_alternative_name(bytes: &[u8]) -> IResult<&[u8], A
|
|||
let mut general_names: Vec<Asn1DerGeneralName> = Vec::new();
|
||||
|
||||
while names.len() != 0 {
|
||||
let (rest, (tag_val, _, name_value)) = parse_asn1_der_object(names)?;
|
||||
match tag_val {
|
||||
0x80 => {
|
||||
let (_, seq) = complete(
|
||||
parse_asn1_der_sequence
|
||||
)(name_value)?;
|
||||
let (_, (oid, (inner_tag_val, _, value))) = complete(
|
||||
tuple((
|
||||
parse_asn1_der_oid,
|
||||
parse_asn1_der_object
|
||||
))
|
||||
)(seq)?;
|
||||
if inner_tag_val != 0x80 {
|
||||
return Err(nom::Err::Error((bytes, ErrorKind::Verify)));
|
||||
}
|
||||
general_names.push(
|
||||
Asn1DerGeneralName::OtherName { type_id: oid, value }
|
||||
);
|
||||
},
|
||||
|
||||
0x81 => {
|
||||
general_names.push(
|
||||
Asn1DerGeneralName::RFC822Name(name_value)
|
||||
);
|
||||
},
|
||||
|
||||
0x82 => {
|
||||
general_names.push(
|
||||
Asn1DerGeneralName::DNSName(name_value)
|
||||
);
|
||||
},
|
||||
|
||||
0x83 => {
|
||||
general_names.push(
|
||||
Asn1DerGeneralName::X400Address(name_value)
|
||||
);
|
||||
},
|
||||
|
||||
0x84 => {
|
||||
general_names.push(
|
||||
Asn1DerGeneralName::DirectoryName(name_value)
|
||||
);
|
||||
},
|
||||
|
||||
0x85 => {
|
||||
let (_, seq) = complete(
|
||||
parse_asn1_der_sequence
|
||||
)(name_value)?;
|
||||
let (_, (
|
||||
(name_assigner_tag_val, _, name_assigner),
|
||||
party_name
|
||||
)) = complete(
|
||||
tuple((
|
||||
parse_asn1_der_object,
|
||||
opt(parse_asn1_der_object)
|
||||
))
|
||||
)(seq)?;
|
||||
|
||||
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_names.push(
|
||||
general_name
|
||||
);
|
||||
},
|
||||
|
||||
0x86 => {
|
||||
general_names.push(
|
||||
Asn1DerGeneralName::URI(name_value)
|
||||
);
|
||||
},
|
||||
|
||||
0x87 => {
|
||||
general_names.push(
|
||||
Asn1DerGeneralName::IPAddress(name_value)
|
||||
);
|
||||
},
|
||||
|
||||
0x88 => {
|
||||
general_names.push(
|
||||
Asn1DerGeneralName::RegisteredID(name_value)
|
||||
);
|
||||
},
|
||||
|
||||
_ => return Err(nom::Err::Error((bytes, ErrorKind::Verify)))
|
||||
}
|
||||
log::info!("Name bytes: {:X?}\nLength: {:?}\n", names, names.len());
|
||||
let (rest, general_name) = parse_asn1_der_general_name(names)?;
|
||||
|
||||
general_names.push(general_name);
|
||||
names = rest;
|
||||
}
|
||||
|
||||
|
@ -1167,6 +1177,216 @@ pub fn parse_asn1_der_subject_alternative_name(bytes: &[u8]) -> IResult<&[u8], A
|
|||
))
|
||||
}
|
||||
|
||||
// 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)));
|
||||
}
|
||||
log::info!("Parsed inner tag");
|
||||
// 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 => {
|
||||
Asn1DerGeneralName::DirectoryName(name_value)
|
||||
},
|
||||
|
||||
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)?;
|
||||
|
|
Loading…
Reference in New Issue