x509_parser/extensions/
keyusage.rs

1use crate::error::{X509Error, X509Result};
2use asn1_rs::FromDer;
3use der_parser::der::*;
4use der_parser::error::BerError;
5use der_parser::{oid, oid::Oid};
6use nom::{Err, IResult};
7use std::fmt;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub struct KeyUsage {
11    pub flags: u16,
12}
13
14impl KeyUsage {
15    pub fn digital_signature(&self) -> bool {
16        self.flags & 1 == 1
17    }
18    pub fn non_repudiation(&self) -> bool {
19        (self.flags >> 1) & 1u16 == 1
20    }
21    pub fn key_encipherment(&self) -> bool {
22        (self.flags >> 2) & 1u16 == 1
23    }
24    pub fn data_encipherment(&self) -> bool {
25        (self.flags >> 3) & 1u16 == 1
26    }
27    pub fn key_agreement(&self) -> bool {
28        (self.flags >> 4) & 1u16 == 1
29    }
30    pub fn key_cert_sign(&self) -> bool {
31        (self.flags >> 5) & 1u16 == 1
32    }
33    pub fn crl_sign(&self) -> bool {
34        (self.flags >> 6) & 1u16 == 1
35    }
36    pub fn encipher_only(&self) -> bool {
37        (self.flags >> 7) & 1u16 == 1
38    }
39    pub fn decipher_only(&self) -> bool {
40        (self.flags >> 8) & 1u16 == 1
41    }
42}
43
44// This list must have the same order as KeyUsage flags declaration (4.2.1.3)
45const KEY_USAGE_FLAGS: &[&str] = &[
46    "Digital Signature",
47    "Non Repudiation",
48    "Key Encipherment",
49    "Data Encipherment",
50    "Key Agreement",
51    "Key Cert Sign",
52    "CRL Sign",
53    "Encipher Only",
54    "Decipher Only",
55];
56
57impl fmt::Display for KeyUsage {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        let mut s = KEY_USAGE_FLAGS
60            .iter()
61            .enumerate()
62            .fold(String::new(), |acc, (idx, s)| {
63                if (self.flags >> idx) & 1 != 0 {
64                    acc + s + ", "
65                } else {
66                    acc
67                }
68            });
69        s.pop();
70        s.pop();
71        f.write_str(&s)
72    }
73}
74
75impl<'a> FromDer<'a, X509Error> for KeyUsage {
76    fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
77        parse_keyusage(i).map_err(Err::convert)
78    }
79}
80
81#[derive(Clone, Debug, PartialEq, Eq)]
82pub struct ExtendedKeyUsage<'a> {
83    pub any: bool,
84    pub server_auth: bool,
85    pub client_auth: bool,
86    pub code_signing: bool,
87    pub email_protection: bool,
88    pub time_stamping: bool,
89    pub ocsp_signing: bool,
90    pub other: Vec<Oid<'a>>,
91}
92
93impl<'a> FromDer<'a, X509Error> for ExtendedKeyUsage<'a> {
94    fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
95        parse_extendedkeyusage(i).map_err(Err::convert)
96    }
97}
98
99pub(crate) fn parse_keyusage(i: &[u8]) -> IResult<&[u8], KeyUsage, BerError> {
100    let (rest, obj) = parse_der_bitstring(i)?;
101    let bitstring = obj
102        .content
103        .as_bitstring()
104        .or(Err(Err::Error(BerError::BerTypeError)))?;
105    let flags = bitstring
106        .data
107        .iter()
108        .rev()
109        .fold(0, |acc, x| (acc << 8) | (x.reverse_bits() as u16));
110    Ok((rest, KeyUsage { flags }))
111}
112
113pub(crate) fn parse_extendedkeyusage(i: &[u8]) -> IResult<&[u8], ExtendedKeyUsage, BerError> {
114    let (ret, seq) = <Vec<Oid>>::from_der(i)?;
115    let mut seen = std::collections::HashSet::new();
116    let mut eku = ExtendedKeyUsage {
117        any: false,
118        server_auth: false,
119        client_auth: false,
120        code_signing: false,
121        email_protection: false,
122        time_stamping: false,
123        ocsp_signing: false,
124        other: Vec::new(),
125    };
126    for oid in &seq {
127        if !seen.insert(oid.clone()) {
128            continue;
129        }
130        let asn1 = oid.as_bytes();
131        if asn1 == oid!(raw 2.5.29.37.0) {
132            eku.any = true;
133        } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.1) {
134            eku.server_auth = true;
135        } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.2) {
136            eku.client_auth = true;
137        } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.3) {
138            eku.code_signing = true;
139        } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.4) {
140            eku.email_protection = true;
141        } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.8) {
142            eku.time_stamping = true;
143        } else if asn1 == oid!(raw 1.3.6.1.5.5.7.3.9) {
144            eku.ocsp_signing = true;
145        } else {
146            eku.other.push(oid.clone());
147        }
148    }
149    Ok((ret, eku))
150}