certificate: parseable
This commit is contained in:
parent
ed2b73389a
commit
d241e93d8e
|
@ -3,23 +3,25 @@ use num_enum::TryFromPrimitive;
|
|||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Certificate<'a> {
|
||||
tbs_certificate: TBSCertificate<'a>,
|
||||
signature_algorithm: AlgorithmIdentifier<'a>,
|
||||
signature_value: &'a [u8]
|
||||
pub tbs_certificate: TBSCertificate<'a>,
|
||||
pub signature_algorithm: AlgorithmIdentifier<'a>,
|
||||
pub signature_value: &'a [u8]
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TBSCertificate<'a> {
|
||||
version: Version,
|
||||
serial_number: &'a [u8],
|
||||
signature: AlgorithmIdentifier<'a>,
|
||||
issuer: &'a [u8],
|
||||
validity: Validity<'a>,
|
||||
subject: &'a [u8],
|
||||
subject_public_key_info: SubjectPublicKeyInfo<'a>,
|
||||
issuer_unique_id: Option<&'a [u8]>,
|
||||
subject_unique_id: Option<&'a [u8]>,
|
||||
extensions: Extensions<'a>,
|
||||
pub version: Version,
|
||||
pub serial_number: &'a [u8],
|
||||
pub signature: AlgorithmIdentifier<'a>,
|
||||
pub issuer: &'a [u8],
|
||||
pub validity: Validity<'a>,
|
||||
pub subject: &'a [u8],
|
||||
pub subject_public_key_info: SubjectPublicKeyInfo<'a>,
|
||||
pub issuer_unique_id: Option<&'a [u8]>,
|
||||
pub subject_unique_id: Option<&'a [u8]>,
|
||||
pub extensions: Extensions<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
||||
|
@ -31,44 +33,98 @@ pub enum Version {
|
|||
v3 = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Validity<'a> {
|
||||
pub not_before: Time<'a>,
|
||||
pub not_after: Time<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Time<'a> {
|
||||
UTCTime(&'a [u8]),
|
||||
GeneralizedTime(&'a [u8]),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SubjectPublicKeyInfo<'a> {
|
||||
pub algorithm: AlgorithmIdentifier<'a>,
|
||||
pub subject_public_key: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Extensions<'a> {
|
||||
extensions: Vec<Extension<'a>>
|
||||
// TODO: Give a limit to the number of policies, migrate to heapless vec
|
||||
// An arbitrary upper limit does not violate RFC5280
|
||||
pub extensions: Vec<Extension<'a>>
|
||||
}
|
||||
|
||||
pub enum Extension<'a> {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Extension<'a> {
|
||||
pub extension_id: &'a [u8],
|
||||
pub critical: bool,
|
||||
pub extension_value: ExtensionValue<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExtensionValue<'a> {
|
||||
KeyUsage {
|
||||
// Acceptable usage of this certificate
|
||||
// Cross verify with ExtendedKeyUsage
|
||||
usage: u8
|
||||
// MSb is bit 0
|
||||
usage: u16
|
||||
},
|
||||
|
||||
CertificatePolicies {
|
||||
// Policies listed in an extension
|
||||
// Need to verify its validity
|
||||
policies: Vec<&'a [u8]>
|
||||
// TODO: Give a limit to the number of policies, migrate to heapless vec
|
||||
// An arbitrary upper limit does not violate RFC5280
|
||||
info: Vec<PolicyInformation<'a>>
|
||||
},
|
||||
SubjectAlternativeName,
|
||||
|
||||
// Permitted subtrees and excluded subtrees are not implemented
|
||||
// SubjectAlternativeName,
|
||||
|
||||
BasicConstraints {
|
||||
is_ca: bool,
|
||||
path_len_constraint: Option<u8>,
|
||||
},
|
||||
|
||||
// Permitted subtrees and excluded subtrees are not implemented
|
||||
// NameConstraints,
|
||||
|
||||
// Policy mapping will not be supported
|
||||
// PolicyConstraints,
|
||||
|
||||
ExtendedKeyUsage {
|
||||
// A list of all possible extended key usage in OID
|
||||
// Cross check validity with regular KeyUsage
|
||||
any_extended_key_usage: bool,
|
||||
id_kp_server_auth: bool,
|
||||
id_kp_client_auth: bool,
|
||||
id_kp_code_signing: bool,
|
||||
id_kp_email_protection: bool,
|
||||
id_kp_time_stamping: bool,
|
||||
id_kp_oscp_signing: bool,
|
||||
},
|
||||
|
||||
InhibitAnyPolicy {
|
||||
// Number of certificates in the path that may still allow AnyPolicy
|
||||
// Certificate chain size should be limited to a small number
|
||||
skip_certs: u8
|
||||
},
|
||||
|
||||
// Extension data from an unsupported extension type
|
||||
Unrecognized,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PolicyInformation<'a> {
|
||||
pub id: &'a [u8],
|
||||
pub qualifier: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AlgorithmIdentifier<'a> {
|
||||
pub algorithm: &'a [u8],
|
||||
pub parameters: &'a [u8],
|
||||
|
|
395
src/parse.rs
395
src/parse.rs
|
@ -3,6 +3,7 @@ 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::make_error;
|
||||
|
@ -13,13 +14,20 @@ use smoltcp::Result;
|
|||
use byteorder::{ByteOrder, NetworkEndian, BigEndian};
|
||||
|
||||
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 crate::certificate::{
|
||||
Certificate as Asn1DerCertificate,
|
||||
Version as Asn1DerVersion,
|
||||
AlgorithmIdentifier as Asn1DerAlgId,
|
||||
Time as Asn1DerTime,
|
||||
Validity as Asn1DerValidity,
|
||||
SubjectPublicKeyInfo as Asn1DerSubjectPublicKeyInfo,
|
||||
Extensions as Asn1DerExtensions,
|
||||
Extension as Asn1DerExtension,
|
||||
ExtensionValue as Asn1DerExtensionValue,
|
||||
PolicyInformation as Asn1DerPolicyInformation,
|
||||
TBSCertificate as Asn1DerTBSCertificate,
|
||||
};
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::convert::TryInto;
|
||||
|
@ -368,22 +376,73 @@ 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
|
||||
// i.e. `length` can be replaced by `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, value) = take(length)(rest)?;
|
||||
Ok((rest, (tag, length, value)))
|
||||
}
|
||||
|
||||
pub fn parse_asn1_der_certificate(bytes: &[u8]) -> IResult<&[u8], (&[u8], &[u8], &[u8])> {
|
||||
let (_, (_, _, rest)) = parse_asn1_der_object(bytes)?;
|
||||
let (rest, (_, _, tbscertificate_slice)) = parse_asn1_der_object(rest)?;
|
||||
let (rest, (_, _, signature_alg)) = parse_asn1_der_object(rest)?;
|
||||
let (rest, (_, _, sig_val)) = parse_asn1_der_object(rest)?;
|
||||
Ok((rest, (tbscertificate_slice, signature_alg, sig_val)))
|
||||
pub fn parse_asn1_der_certificate(bytes: &[u8]) -> IResult<&[u8], Asn1DerCertificate> {
|
||||
let (excluded, (_, _, rest)) = parse_asn1_der_object(bytes)?;
|
||||
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)?;
|
||||
Ok((
|
||||
excluded,
|
||||
Asn1DerCertificate {
|
||||
tbs_certificate,
|
||||
signature_algorithm: sig_alg,
|
||||
signature_value: sig_value,
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
pub fn parse_asn1_der_tbs_certificate(bytes: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
|
||||
todo!()
|
||||
// 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)?;
|
||||
// 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((
|
||||
parse_asn1_der_version,
|
||||
parse_asn1_der_serial_number,
|
||||
parse_asn1_der_algorithm_identifier,
|
||||
parse_asn1_der_sequence,
|
||||
parse_asn1_der_validity,
|
||||
parse_asn1_der_sequence,
|
||||
parse_asn1_der_subject_key_public_info,
|
||||
opt(parse_asn1_der_bit_string),
|
||||
opt(parse_asn1_der_bit_string),
|
||||
parse_asn1_der_extensions
|
||||
))
|
||||
)(value)?;
|
||||
|
||||
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
|
||||
|
@ -398,9 +457,7 @@ pub fn parse_asn1_der_version(bytes: &[u8]) -> IResult<&[u8], Asn1DerVersion> {
|
|||
// 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
|
||||
let (zeroes, version_byte) = take(integer.len()-1)(integer)?;
|
||||
complete(take_till(|byte| byte != 0))(zeroes)?;
|
||||
Ok((rest, Asn1DerVersion::try_from(version_byte[0]).unwrap()))
|
||||
Ok((rest, Asn1DerVersion::try_from(integer[0]).unwrap()))
|
||||
}
|
||||
|
||||
// INTEGER: tag: 0x02
|
||||
|
@ -410,8 +467,6 @@ 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))
|
||||
}
|
||||
|
||||
|
@ -422,12 +477,35 @@ 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)));
|
||||
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 value[0] != 0 {
|
||||
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, length, 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) {
|
||||
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, length, value)) = parse_asn1_der_object(bytes)?;
|
||||
// Verify the tag is indeed 0x03
|
||||
if tag_val != 0x30 {
|
||||
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
||||
}
|
||||
Ok((rest, value))
|
||||
|
@ -537,12 +615,281 @@ pub fn parse_asn1_der_subject_key_public_info(bytes: &[u8]) -> IResult<&[u8], As
|
|||
))
|
||||
}
|
||||
|
||||
// Parser for extensions (Sequence: 0xA3)
|
||||
// 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)?;
|
||||
// Verify the tag_val is indeed 0xA3
|
||||
if tag_val != 0xA3 {
|
||||
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
||||
}
|
||||
todo!()
|
||||
|
||||
let (_, (tag_val, length, 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, 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)));
|
||||
}
|
||||
|
||||
// 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
|
||||
},
|
||||
// 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, length, 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) {
|
||||
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
||||
}
|
||||
// Erase the padded bits
|
||||
let padding = value[0];
|
||||
let usage_array: [u8; 2] = if length == 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 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)?;
|
||||
// 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, length, value)) = parse_asn1_der_object(bytes)?;
|
||||
// Verify tag value
|
||||
if tag_val != 0x30 {
|
||||
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
||||
}
|
||||
|
||||
let (_, (oid, (_, _, qualifier))) = complete(
|
||||
tuple((
|
||||
parse_asn1_der_oid,
|
||||
parse_asn1_der_object
|
||||
))
|
||||
)(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, length, 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, length, 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, length, value)) = parse_asn1_der_object(bytes)?;
|
||||
// Verify tag value
|
||||
if tag_val != 0x04 {
|
||||
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
||||
}
|
||||
Ok((rest, value))
|
||||
}
|
||||
|
||||
mod oid {
|
||||
// Extensions
|
||||
pub const CERT_KEY_USAGE: &'static [u8] = &[85, 29, 15]; // 2.5.29.15
|
||||
pub const CERT_POLICIES: &'static [u8] = &[85, 29, 32]; // 2.5.29.32
|
||||
pub const CERT_BASIC_CONSTRAINTS: &'static [u8] = &[85, 29, 19]; // 2.5.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
|
||||
// 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
|
||||
pub const ID_KP_CLIENT_AUTH: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 2]; // 1.3.6.1.5.5.7.3.2
|
||||
pub const ID_KP_CODE_SIGNING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 3]; // 1.3.6.1.5.5.7.3.3
|
||||
pub const ID_KP_EMAIL_PROTECTION: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 4]; // 1.3.6.1.5.5.7.3.4
|
||||
pub const ID_KP_TIME_STAMPING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 8]; // 1.3.6.1.5.5.7.3.8
|
||||
pub const ID_KP_OCSP_SIGNING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 9]; // 1.3.6.1.5.5.7.3.9
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue