use crate::error::{X509Error, X509Result}; use asn1_rs::FromDer; use der_parser::der::*; use der_parser::error::BerError; use der_parser::{oid, oid::Oid}; use nom::{Err, IResult}; use std::fmt; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct KeyUsage { pub flags: u16, } impl KeyUsage { pub fn digital_signature(&self) -> bool { self.flags & 1 == 1 } pub fn non_repudiation(&self) -> bool { (self.flags >> 1) & 1u16 == 1 } pub fn key_encipherment(&self) -> bool { (self.flags >> 2) & 1u16 == 1 } pub fn data_encipherment(&self) -> bool { (self.flags >> 3) & 1u16 == 1 } pub fn key_agreement(&self) -> bool { (self.flags >> 4) & 1u16 == 1 } pub fn key_cert_sign(&self) -> bool { (self.flags >> 5) & 1u16 == 1 } pub fn crl_sign(&self) -> bool { (self.flags >> 6) & 1u16 == 1 } pub fn encipher_only(&self) -> bool { (self.flags >> 7) & 1u16 == 1 } pub fn decipher_only(&self) -> bool { (self.flags >> 8) & 1u16 == 1 } } // This list must have the same order as KeyUsage flags declaration (4.2.1.3) const KEY_USAGE_FLAGS: &[&str] = &[ "Digital Signature", "Non Repudiation", "Key Encipherment", "Data Encipherment", "Key Agreement", "Key Cert Sign", "CRL Sign", "Encipher Only", "Decipher Only", ]; impl fmt::Display for KeyUsage { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut s = KEY_USAGE_FLAGS .iter() .enumerate() .fold(String::new(), |acc, (idx, s)| { if self.flags >> idx & 1 != 0 { acc + s + ", " } else { acc } }); s.pop(); s.pop(); f.write_str(&s) } } impl<'a> FromDer<'a, X509Error> for KeyUsage { fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { parse_keyusage(i).map_err(Err::convert) } } #[derive(Clone, Debug, PartialEq, Eq)] pub struct ExtendedKeyUsage<'a> { pub any: bool, pub server_auth: bool, pub client_auth: bool, pub code_signing: bool, pub email_protection: bool, pub time_stamping: bool, pub ocsp_signing: bool, pub other: Vec>, } impl<'a> FromDer<'a, X509Error> for ExtendedKeyUsage<'a> { fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { parse_extendedkeyusage(i).map_err(Err::convert) } } pub(crate) fn parse_keyusage(i: &[u8]) -> IResult<&[u8], KeyUsage, BerError> { let (rest, obj) = parse_der_bitstring(i)?; let bitstring = obj .content .as_bitstring() .or(Err(Err::Error(BerError::BerTypeError)))?; let flags = bitstring .data .iter() .rev() .fold(0, |acc, x| acc << 8 | (x.reverse_bits() as u16)); Ok((rest, KeyUsage { flags })) } pub(crate) fn parse_extendedkeyusage(i: &[u8]) -> IResult<&[u8], ExtendedKeyUsage, BerError> { let (ret, seq) = >::from_der(i)?; let mut seen = std::collections::HashSet::new(); let mut eku = ExtendedKeyUsage { any: false, server_auth: false, client_auth: false, code_signing: false, email_protection: false, time_stamping: false, ocsp_signing: false, other: Vec::new(), }; for oid in &seq { if !seen.insert(oid.clone()) { continue; } let asn1 = oid.as_bytes(); if asn1 == oid!(raw 2.5.29.37.0) { eku.any = true; } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.1) { eku.server_auth = true; } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.2) { eku.client_auth = true; } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.3) { eku.code_signing = true; } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.4) { eku.email_protection = true; } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.8) { eku.time_stamping = true; } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.9) { eku.ocsp_signing = true; } else { eku.other.push(oid.clone()); } } Ok((ret, eku)) }