1use byteorder::WriteBytesExt;
4use std::time::{Duration, SystemTime};
5
6use crate::util::asn1;
7use crate::util::cryptoutil;
8use anyhow::{Context, Result};
9
10fn add_ext(encoder: &mut asn1::Encoder, oid: &str, critical: bool, value: &[u8]) -> Result<()> {
11 encoder.start_seq(0x30)?;
12 encoder.write_oid(oid)?;
13 if critical {
14 encoder.write_bool(critical)?;
15 }
16 encoder.write_octet_string(value)?;
17 encoder.end_seq();
18 Ok(())
19}
20
21fn encode_nodeid(id: u64) -> String {
22 format!("{:0>16X}", id)
23}
24
25fn systemtime_to_x509_time(st: std::time::SystemTime) -> Result<String> {
26 let der_datetime = x509_cert::der::asn1::UtcTime::from_system_time(st)?;
27 let mut v = Vec::new();
28 x509_cert::der::EncodeValue::encode_value(&der_datetime, &mut v)?;
29 Ok(std::str::from_utf8(&v)?.to_owned())
30}
31
32const OID_MATTER_DN_NODE: &str = "1.3.6.1.4.1.37244.1.1";
33const OID_MATTER_DN_CA: &str = "1.3.6.1.4.1.37244.1.4";
34const OID_MATTER_DN_FABRIC: &str = "1.3.6.1.4.1.37244.1.5";
35
36const OID_SIG_ECDSA_WITH_SHA256: &str = "1.2.840.10045.4.3.2";
37
38pub(crate) const OID_CE_SUBJECT_KEY_IDENTIFIER: &str = "2.5.29.14";
39pub(crate) const OID_CE_KEY_USAGE: &str = "2.5.29.15";
40pub(crate) const OID_CE_BASIC_CONSTRAINTS: &str = "2.5.29.19";
41pub(crate) const OID_CE_EXT_KEU_USAGE: &str = "2.5.29.37";
42pub(crate) const OID_CE_AUTHORITY_KEY_IDENTIFIER: &str = "2.5.29.35";
43
44fn add_rdn(encoder: &mut asn1::Encoder, oid: &str, id: u64) -> Result<()> {
45 encoder.start_seq(0x31)?; encoder.start_seq(0x30)?; encoder.write_oid(oid)?;
48 encoder.write_string(&encode_nodeid(id))?;
49 encoder.end_seq();
50 encoder.end_seq();
51 Ok(())
52}
53
54pub fn encode_x509(
56 node_public_key: &[u8],
57 node_id: u64,
58 fabric_id: u64,
59 ca_id: u64,
60 ca_private: &p256::SecretKey,
61 ca: bool,
62) -> Result<Vec<u8>> {
63 let mut encoder = asn1::Encoder::new();
64 encoder.start_seq(0x30)?;
65 encoder.start_seq(0x30)?;
66
67 encoder.start_seq(0xa0)?;
68 encoder.write_int(2)?; encoder.end_seq();
70
71 encoder.write_int(10001)?; encoder.start_seq(0x30)?; encoder.write_oid(OID_SIG_ECDSA_WITH_SHA256)?;
75 encoder.end_seq();
76
77 encoder.start_seq(0x30)?; add_rdn(&mut encoder, OID_MATTER_DN_CA, ca_id)?;
79 encoder.end_seq();
80
81 encoder.start_seq(0x30)?; let now = SystemTime::now();
84 encoder.write_string_with_tag(0x17, &systemtime_to_x509_time(now)?)?;
85 let not_after = now
86 .checked_add(Duration::from_secs(60 * 60 * 24 * 100))
87 .context("time continuity error")?;
88 encoder.write_string_with_tag(0x17, &systemtime_to_x509_time(not_after)?)?;
89 encoder.end_seq();
90
91 if ca {
92 encoder.start_seq(0x30)?; add_rdn(&mut encoder, OID_MATTER_DN_CA, node_id)?;
94 encoder.end_seq();
95 } else {
96 encoder.start_seq(0x30)?; add_rdn(&mut encoder, OID_MATTER_DN_NODE, node_id)?;
98 add_rdn(&mut encoder, OID_MATTER_DN_FABRIC, fabric_id)?;
99 encoder.end_seq();
100 }
101
102 encoder.start_seq(0x30)?; encoder.start_seq(0x30)?; encoder.write_oid("1.2.840.10045.2.1")?;
105 encoder.write_oid("1.2.840.10045.3.1.7")?;
106 encoder.end_seq();
107
108 let mut pk2 = Vec::new();
109 pk2.write_u8(0)?;
110
111 pk2.extend_from_slice(node_public_key);
112 encoder.write_octet_string_with_tag(0x3, &pk2)?;
113 encoder.end_seq();
114
115 let subjectkeyidasn = {
116 let mut encoder = asn1::Encoder::new();
117 encoder.write_octet_string(&cryptoutil::sha1_enc(node_public_key))?;
118 encoder.encode()
119 };
120
121 let authoritykey_sha1_asn = {
122 let mut encoder = asn1::Encoder::new();
123 encoder.start_seq(0x30)?;
124 let pubkey = ca_private.public_key().to_sec1_bytes();
125 encoder.write_octet_string_with_tag(0x80, &cryptoutil::sha1_enc(&pubkey))?;
126 encoder.encode()
127 };
128
129 encoder.start_seq(0xa3)?;
130 encoder.start_seq(0x30)?;
131 if ca {
133 add_ext(
134 &mut encoder,
135 OID_CE_BASIC_CONSTRAINTS,
136 true,
137 &[0x30, 0x03, 0x01, 0x01, 0xFF],
138 )?
139 } else {
140 add_ext(&mut encoder, OID_CE_BASIC_CONSTRAINTS, true, &[0x30, 0x00])?
141 }
142 if ca {
144 add_ext(
145 &mut encoder,
146 OID_CE_KEY_USAGE,
147 true,
148 &[0x03, 0x02, 0x01, 0x06],
149 )?;
150 } else {
151 add_ext(
152 &mut encoder,
153 OID_CE_KEY_USAGE,
154 true,
155 &[0x03, 0x02, 0x07, 0x80],
156 )?;
157 }
158 if !ca {
160 let mut ext_ku_encoder = asn1::Encoder::new();
161 ext_ku_encoder.start_seq(0x30)?;
162 ext_ku_encoder.write_oid("1.3.6.1.5.5.7.3.2")?; ext_ku_encoder.write_oid("1.3.6.1.5.5.7.3.1")?; let ext_ku_bytes = ext_ku_encoder.encode();
165 add_ext(&mut encoder, OID_CE_EXT_KEU_USAGE, true, &ext_ku_bytes)?;
166 }
167 add_ext(
169 &mut encoder,
170 OID_CE_SUBJECT_KEY_IDENTIFIER,
171 false,
172 &subjectkeyidasn,
173 )?;
174
175 add_ext(
177 &mut encoder,
178 OID_CE_AUTHORITY_KEY_IDENTIFIER,
179 false,
180 &authoritykey_sha1_asn,
181 )?;
182
183 encoder.end_seq();
184 encoder.end_seq();
185 encoder.end_seq();
186
187 let to_sign = encoder.clone();
188 let to_sign_bytes = &to_sign.encode()[4..];
189 let key = ecdsa::SigningKey::from(ca_private);
190 let signed = key.sign_recoverable(to_sign_bytes)?.0;
191
192 encoder.start_seq(0x30)?; encoder.write_oid(OID_SIG_ECDSA_WITH_SHA256)?;
194 encoder.end_seq();
195 let mut signed_b = vec![0];
196 signed_b.extend_from_slice(signed.to_der().as_bytes());
197
198 encoder.write_octet_string_with_tag(0x3, &signed_b)?;
199
200 let res = encoder.encode();
201
202 Ok(res)
203}