Skip to content

Commit 3ba6630

Browse files
gaojiaqi7jyao1
authored andcommitted
crypto: support getting CRL num from a PEM CRL
Signed-off-by: Jiaqi Gao <[email protected]>
1 parent d9c6282 commit 3ba6630

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

src/crypto/src/crl.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Copyright (c) 2022 Intel Corporation
2+
//
3+
// SPDX-License-Identifier: BSD-2-Clause-Patent
4+
5+
use crate::x509::{Extension, Time};
6+
use crate::Error;
7+
use alloc::vec::Vec;
8+
use der::asn1::{AnyRef, BitStringRef, ObjectIdentifier};
9+
use der::{Choice, Decode, Encode, ErrorKind, Header, Sequence, Tag, TagMode, TagNumber, Tagged};
10+
use rustls_pemfile::Item;
11+
12+
const CRL_NUMBER_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.5.29.20");
13+
14+
#[derive(Sequence)]
15+
pub struct Crl<'a> {
16+
tbs_cert_list: TbsCertList<'a>,
17+
signature_algorithm: AnyRef<'a>,
18+
signature_value: BitStringRef<'a>,
19+
}
20+
21+
#[derive(Sequence)]
22+
struct TbsCertList<'a> {
23+
version: Option<AnyRef<'a>>,
24+
signature: AnyRef<'a>,
25+
issuer: AnyRef<'a>,
26+
this_update: Time,
27+
next_update: Option<Time>,
28+
revoked_certificates: Option<Vec<RevokedCertificate<'a>>>,
29+
crl_extensions: Option<Extensions<'a>>,
30+
}
31+
32+
#[derive(Sequence)]
33+
struct RevokedCertificate<'a> {
34+
user_certificate: AnyRef<'a>,
35+
revocation_date: AnyRef<'a>,
36+
crl_entry_extensions: Option<AnyRef<'a>>,
37+
}
38+
39+
#[derive(Clone, Debug, Eq, PartialEq)]
40+
pub struct Extensions<'a>(Vec<Extension<'a>>);
41+
42+
impl<'a> Extensions<'a> {
43+
pub fn get(&self) -> &Vec<Extension<'a>> {
44+
&self.0
45+
}
46+
}
47+
48+
impl Encode for Extensions<'_> {
49+
fn encoded_len(&self) -> der::Result<der::Length> {
50+
let len = self.0.encoded_len()?;
51+
let explicit = Header::new(
52+
Tag::ContextSpecific {
53+
constructed: true,
54+
number: TagNumber::new(0),
55+
},
56+
len,
57+
)?;
58+
explicit.encoded_len() + len
59+
}
60+
61+
fn encode(&self, encoder: &mut impl der::Writer) -> der::Result<()> {
62+
let len = self.0.encoded_len()?;
63+
let explicit = Header::new(
64+
Tag::ContextSpecific {
65+
constructed: true,
66+
number: TagNumber::new(0),
67+
},
68+
len,
69+
)?;
70+
explicit.encode(encoder)?;
71+
self.0.encode(encoder)
72+
}
73+
}
74+
75+
impl<'a> Decode<'a> for Extensions<'a> {
76+
fn decode<R: der::Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
77+
let ext = decoder
78+
.context_specific(TagNumber::new(0), TagMode::Explicit)?
79+
.ok_or(der::Error::new(ErrorKind::Failed, decoder.position()))?;
80+
Ok(Self(ext))
81+
}
82+
}
83+
84+
impl Tagged for Extensions<'_> {
85+
fn tag(&self) -> Tag {
86+
Tag::ContextSpecific {
87+
constructed: true,
88+
number: TagNumber::new(0),
89+
}
90+
}
91+
}
92+
93+
impl<'a> Choice<'a> for Extensions<'a> {
94+
fn can_decode(tag: Tag) -> bool {
95+
tag == Tag::ContextSpecific {
96+
constructed: true,
97+
number: TagNumber::new(0),
98+
}
99+
}
100+
}
101+
102+
/// Parses a CRL and returns the CRL Number extension value
103+
pub fn get_crl_number(crl: &[u8]) -> Result<u32, Error> {
104+
let crl_der = match rustls_pemfile::read_one_from_slice(crl) {
105+
Ok(Some((Item::Crl(data), _))) => data.to_vec(),
106+
Ok(Some(_)) | Ok(None) | Err(_) => return Err(Error::DecodePemCert),
107+
};
108+
109+
let crl = Crl::from_der(&crl_der).map_err(|_| Error::ParseCertificate)?;
110+
111+
if let Some(cs) = crl.tbs_cert_list.crl_extensions {
112+
for ext in cs.get().iter() {
113+
if ext.extn_id == CRL_NUMBER_OID {
114+
let number =
115+
u32::from_der(ext.extn_value.ok_or(Error::CrlNumberNotFound)?.as_bytes())
116+
.map_err(|_| Error::CrlNumberNotFound)?;
117+
return Ok(number);
118+
}
119+
}
120+
}
121+
122+
Err(Error::CrlNumberNotFound)
123+
}
124+
125+
#[cfg(test)]
126+
mod test {
127+
use super::*;
128+
129+
#[test]
130+
fn test_get_crl_number() {
131+
const CRL1: &[u8] = b"-----BEGIN X509 CRL-----
132+
MIIBITCByAIBATAKBggqhkjOPQQDAjBoMRowGAYDVQQDDBFJbnRlbCBTR1ggUm9v
133+
dCBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRh
134+
IENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTI1MDkxNjExNTMxMloX
135+
DTI2MDkxNjExNTMxMlqgLzAtMAoGA1UdFAQDAgEBMB8GA1UdIwQYMBaAFOnoRFJT
136+
NlxLGJoR/EMYLKXcIIBIMAoGCCqGSM49BAMCA0gAMEUCIQDv5KEBogNCzPgupOPj
137+
FIYJaOubypBPCGqnE0XcYTgFDwIgeSfXk71tIbV5lqp6gWCpN98/xu/8c7y36EV3
138+
pkfootI=
139+
-----END X509 CRL-----";
140+
141+
const CRL2: &[u8] = b"-----BEGIN X509 CRL-----
142+
MIIBKTCB0AIBATAKBggqhkjOPQQDAjBwMSIwIAYDVQQDDBlJbnRlbCBTR1ggUENL
143+
IFBsYXRmb3JtIENBMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEUMBIGA1UE
144+
BwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYDVQQGEwJVUxcNMjUxMTIw
145+
MDY0ODQ5WhcNMjUxMjIwMDY0ODQ5WqAvMC0wCgYDVR0UBAMCAQEwHwYDVR0jBBgw
146+
FoAUWSPTp0qoY1QuOXCt4A8HK1ckKrcwCgYIKoZIzj0EAwIDSAAwRQIgQB8+Xmh7
147+
QJEvrDG15ucaA2b2pByR86M8+3mDd5g5c0sCIQD1WVRItKvP90kBT6EZp03qAOCU
148+
IrrRoE+AsML37e56hg==
149+
-----END X509 CRL-----";
150+
151+
assert_eq!(get_crl_number(CRL1).unwrap(), 1);
152+
assert_eq!(get_crl_number(CRL2).unwrap(), 1);
153+
}
154+
}

src/crypto/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ cfg_if::cfg_if! {
2121
}
2222
}
2323

24+
pub mod crl;
2425
pub mod x509;
2526

2627
pub type Result<T> = core::result::Result<T, Error>;
@@ -80,6 +81,9 @@ pub enum Error {
8081
/// Unsupported signature algorithm
8182
UnsupportedAlgorithm,
8283

84+
/// CRL number extension missing
85+
CrlNumberNotFound,
86+
8387
/// Unexpected error that should not happen
8488
Unexpected,
8589
}

0 commit comments

Comments
 (0)