1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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<Oid<'a>>,
}

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) = <Vec<Oid>>::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))
}