x509_parser/extensions/
sct.rs1use std::convert::TryInto;
6
7use asn1_rs::FromDer;
8use der_parser::error::BerError;
9use nom::bytes::streaming::take;
10use nom::combinator::{complete, map_parser};
11use nom::multi::{length_data, many1};
12use nom::number::streaming::{be_u16, be_u64, be_u8};
13use nom::IResult;
14
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct SignedCertificateTimestamp<'a> {
17 pub version: CtVersion,
18 pub id: CtLogID<'a>,
19 pub timestamp: u64,
20 pub extensions: CtExtensions<'a>,
21 pub signature: DigitallySigned<'a>,
22}
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
27pub struct CtVersion(pub u8);
28
29impl CtVersion {
30 pub const V1: CtVersion = CtVersion(0);
31}
32
33#[derive(Clone, Debug, PartialEq, Eq)]
36pub struct CtLogID<'a> {
37 pub key_id: &'a [u8; 32],
38}
39
40#[derive(Clone, Debug, PartialEq, Eq)]
43pub struct CtExtensions<'a>(pub &'a [u8]);
44
45#[derive(Clone, Debug, PartialEq, Eq)]
46pub struct DigitallySigned<'a> {
47 pub hash_alg_id: u8,
48 pub sign_alg_id: u8,
49 pub data: &'a [u8],
50}
51
52pub fn parse_ct_signed_certificate_timestamp_list(
54 i: &[u8],
55) -> IResult<&[u8], Vec<SignedCertificateTimestamp>, BerError> {
56 let (rem, b) = <&[u8]>::from_der(i)?;
59 let (b, sct_len) = be_u16(b)?;
60 let (_, sct_list) = map_parser(
61 take(sct_len as usize),
62 many1(complete(parse_ct_signed_certificate_timestamp)),
63 )(b)?;
64 Ok((rem, sct_list))
65}
66
67pub fn parse_ct_signed_certificate_timestamp(
69 i: &[u8],
70) -> IResult<&[u8], SignedCertificateTimestamp, BerError> {
71 map_parser(
72 length_data(be_u16),
73 parse_ct_signed_certificate_timestamp_content,
74 )(i)
75}
76
77pub(crate) fn parse_ct_signed_certificate_timestamp_content(
78 i: &[u8],
79) -> IResult<&[u8], SignedCertificateTimestamp, BerError> {
80 let (i, version) = be_u8(i)?;
81 let (i, id) = parse_log_id(i)?;
82 let (i, timestamp) = be_u64(i)?;
83 let (i, extensions) = parse_ct_extensions(i)?;
84 let (i, signature) = parse_digitally_signed(i)?;
85 let sct = SignedCertificateTimestamp {
86 version: CtVersion(version),
87 id,
88 timestamp,
89 extensions,
90 signature,
91 };
92 Ok((i, sct))
93}
94
95fn parse_log_id(i: &[u8]) -> IResult<&[u8], CtLogID, BerError> {
97 let (i, key_id) = take(32usize)(i)?;
98 Ok((
99 i,
100 CtLogID {
101 key_id: key_id
102 .try_into()
103 .expect("take(32) is in sync with key_id size"),
104 },
105 ))
106}
107
108fn parse_ct_extensions(i: &[u8]) -> IResult<&[u8], CtExtensions, BerError> {
109 let (i, ext_len) = be_u16(i)?;
110 let (i, ext_data) = take(ext_len as usize)(i)?;
111 Ok((i, CtExtensions(ext_data)))
112}
113
114fn parse_digitally_signed(i: &[u8]) -> IResult<&[u8], DigitallySigned, BerError> {
115 let (i, hash_alg_id) = be_u8(i)?;
116 let (i, sign_alg_id) = be_u8(i)?;
117 let (i, data) = length_data(be_u16)(i)?;
118 let signed = DigitallySigned {
119 hash_alg_id,
120 sign_alg_id,
121 data,
122 };
123 Ok((i, signed))
124}