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
use std::convert::TryInto;
use asn1_rs::FromDer;
use der_parser::error::BerError;
use nom::bytes::streaming::take;
use nom::combinator::{complete, map_parser};
use nom::multi::{length_data, many1};
use nom::number::streaming::{be_u16, be_u64, be_u8};
use nom::IResult;
#[derive(Clone, Debug, PartialEq)]
pub struct SignedCertificateTimestamp<'a> {
pub version: CtVersion,
pub id: CtLogID<'a>,
pub timestamp: u64,
pub extensions: CtExtensions<'a>,
pub signature: DigitallySigned<'a>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CtVersion(pub u8);
impl CtVersion {
pub const V1: CtVersion = CtVersion(0);
}
#[derive(Clone, Debug, PartialEq)]
pub struct CtLogID<'a> {
pub key_id: &'a [u8; 32],
}
#[derive(Clone, Debug, PartialEq)]
pub struct CtExtensions<'a>(pub &'a [u8]);
#[derive(Clone, Debug, PartialEq)]
pub struct DigitallySigned<'a> {
pub hash_alg_id: u8,
pub sign_alg_id: u8,
pub data: &'a [u8],
}
pub fn parse_ct_signed_certificate_timestamp_list(
i: &[u8],
) -> IResult<&[u8], Vec<SignedCertificateTimestamp>, BerError> {
let (rem, b) = <&[u8]>::from_der(i)?;
let (b, sct_len) = be_u16(b)?;
let (_, sct_list) = map_parser(
take(sct_len as usize),
many1(complete(parse_ct_signed_certificate_timestamp)),
)(b)?;
Ok((rem, sct_list))
}
pub fn parse_ct_signed_certificate_timestamp(
i: &[u8],
) -> IResult<&[u8], SignedCertificateTimestamp, BerError> {
map_parser(
length_data(be_u16),
parse_ct_signed_certificate_timestamp_content,
)(i)
}
pub(crate) fn parse_ct_signed_certificate_timestamp_content<'a>(
i: &'a [u8],
) -> IResult<&'a [u8], SignedCertificateTimestamp, BerError> {
let (i, version) = be_u8(i)?;
let (i, id) = parse_log_id(i)?;
let (i, timestamp) = be_u64(i)?;
let (i, extensions) = parse_ct_extensions(i)?;
let (i, signature) = parse_digitally_signed(i)?;
let sct = SignedCertificateTimestamp {
version: CtVersion(version),
id,
timestamp,
extensions,
signature,
};
Ok((i, sct))
}
fn parse_log_id(i: &[u8]) -> IResult<&[u8], CtLogID, BerError> {
let (i, key_id) = take(32usize)(i)?;
Ok((
i,
CtLogID {
key_id: key_id
.try_into()
.expect("take(32) is in sync with key_id size"),
},
))
}
fn parse_ct_extensions(i: &[u8]) -> IResult<&[u8], CtExtensions, BerError> {
let (i, ext_len) = be_u16(i)?;
let (i, ext_data) = take(ext_len as usize)(i)?;
Ok((i, CtExtensions(ext_data)))
}
fn parse_digitally_signed(i: &[u8]) -> IResult<&[u8], DigitallySigned, BerError> {
let (i, hash_alg_id) = be_u8(i)?;
let (i, sign_alg_id) = be_u8(i)?;
let (i, data) = length_data(be_u16)(i)?;
let signed = DigitallySigned {
hash_alg_id,
sign_alg_id,
data,
};
Ok((i, signed))
}