1use anyhow::{Context, Result};
4use p256::NistP256;
5use x509_cert::{
6 certificate::CertificateInner,
7 der::{Decode, DecodePem},
8};
9
10use crate::{
11 tlv::{self, TlvBuffer},
12 util::cryptoutil,
13};
14
15fn decode_dn_value(dn: &x509_cert::der::Any) -> Result<u64> {
16 let valstr = dn.decode_as::<String>()?;
17 Ok(u64::from_str_radix(&valstr, 16)?)
18}
19
20fn dn_to_matter(dn: &x509_cert::name::RdnSequence, tlv: &mut TlvBuffer) -> Result<()> {
21 for extra in &dn.0 {
22 for e2 in extra.0.as_slice() {
23 if e2.oid == const_oid::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.37244.1.1") {
24 tlv.write_uint64(17, decode_dn_value(&e2.value)?)?;
25 }
26 if e2.oid == const_oid::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.37244.1.4") {
27 tlv.write_uint64(20, decode_dn_value(&e2.value)?)?;
28 }
29 if e2.oid == const_oid::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.37244.1.5") {
30 tlv.write_uint64(21, decode_dn_value(&e2.value)?)?;
31 }
32 }
33 }
34 Ok(())
35}
36
37fn extract_extension(cert: &x509_cert::TbsCertificate, oid: &str) -> Result<Vec<u8>> {
38 let extensions = cert
39 .extensions
40 .as_ref()
41 .context("can't get cert extensions")?;
42 for extension in extensions {
43 if extension.extn_id == const_oid::ObjectIdentifier::new_unwrap(oid) {
44 let v = extension.extn_value.as_bytes().to_vec();
45 return Ok(v);
46 }
47 }
48 Err(anyhow::anyhow!(format!("can't find extension {:?}", oid)))
49}
50
51pub fn get_subject_node_id_from_x509(fname: &str) -> Result<u64> {
52 let cert_file = std::fs::read_to_string(fname)?;
53 let cert = x509_cert::Certificate::from_pem(cert_file)?;
54 for extra in cert.tbs_certificate.subject.0 {
55 for e2 in extra.0.as_slice() {
56 if e2.oid == const_oid::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.37244.1.1") {
57 return decode_dn_value(&e2.value);
58 }
59 }
60 }
61 Err(anyhow::anyhow!("matter subject/node not found in x509"))
62}
63
64pub fn convert_x509_to_matter(fname: &str, ca_pubkey: &[u8]) -> Result<Vec<u8>> {
67 let x509_raw = cryptoutil::read_data_from_pem(fname)?;
68 convert_x509_bytes_to_matter(&x509_raw, ca_pubkey)
69}
70
71pub fn convert_x509_bytes_to_matter(bytes: &[u8], ca_pubkey: &[u8]) -> Result<Vec<u8>> {
74 let x509 = x509_cert::Certificate::from_der(bytes)?;
75 convert_x509_to_matter_int(&x509, ca_pubkey)
76}
77
78fn convert_x509_to_matter_int(cert: &CertificateInner, ca_pubkey: &[u8]) -> Result<Vec<u8>> {
79 let mut enc = tlv::TlvBuffer::new();
80 enc.write_anon_struct()?;
81 enc.write_octetstring(1, cert.tbs_certificate.serial_number.as_bytes())?;
82 enc.write_uint8(2, 1)?; enc.write_list(3)?; dn_to_matter(&cert.tbs_certificate.issuer, &mut enc)?;
86 enc.write_struct_end()?;
87
88 let not_before = cert.tbs_certificate.validity.not_before;
89 enc.write_uint32(
90 4,
91 (not_before.to_unix_duration().as_secs() - 946684800) as u32,
92 )?;
93 let not_after = cert.tbs_certificate.validity.not_after;
94 enc.write_uint32(
95 5,
96 (not_after.to_unix_duration().as_secs() - 946684800) as u32,
97 )?;
98
99 enc.write_list(6)?; dn_to_matter(&cert.tbs_certificate.subject, &mut enc)?;
101 enc.write_struct_end()?;
102
103 enc.write_uint8(7, 1)?;
104 enc.write_uint8(8, 1)?;
105
106 let subject_public_key = cert
107 .tbs_certificate
108 .subject_public_key_info
109 .subject_public_key
110 .as_bytes()
111 .context("can't extract subject public key")?;
112
113 enc.write_octetstring(9, subject_public_key)?;
114
115 enc.write_list(10)?;
116 enc.write_struct(1)?;
117 let is_ca = {
118 let basicc = extract_extension(
119 &cert.tbs_certificate,
120 crate::cert_x509::OID_CE_BASIC_CONSTRAINTS,
121 );
122 if let Ok(v) = basicc {
123 v[v.len() - 1] == 0xff
124 } else {
125 false
126 }
127 };
128 enc.write_bool(1, is_ca)?;
129 enc.write_struct_end()?;
130 let kus = extract_extension(&cert.tbs_certificate, crate::cert_x509::OID_CE_KEY_USAGE)?;
131 let kus = x509_cert::ext::pkix::KeyUsage::from_der(&kus)?;
132
133 enc.write_uint8(2, kus.0.bits() as u8)?;
134 let extu = extract_extension(
136 &cert.tbs_certificate,
137 crate::cert_x509::OID_CE_EXT_KEU_USAGE,
138 );
139 if extu.is_ok() {
140 enc.write_array(0x3)?;
141 let extu = x509_cert::ext::pkix::ExtendedKeyUsage::from_der(&extu?)?;
142 for u in extu.0 {
143 match u.to_string().as_str() {
144 "1.3.6.1.5.5.7.3.1" => {
145 enc.write_uint8_notag(1)?;
146 } "1.3.6.1.5.5.7.3.2" => {
148 enc.write_uint8_notag(2)?;
149 } _ => {
151 return Err(anyhow::anyhow!(
152 "unsupported oid in extendedKeyUsage {:?}",
153 u.to_string()
154 ))
155 }
156 };
157 }
158 enc.write_struct_end()?;
159 }
160
161 let cakey_sha1 = cryptoutil::sha1_enc(ca_pubkey);
163
164 enc.write_octetstring(
165 4,
166 &extract_extension(
167 &cert.tbs_certificate,
168 crate::cert_x509::OID_CE_SUBJECT_KEY_IDENTIFIER,
169 )?[2..],
170 )?;
171 enc.write_octetstring(5, &cakey_sha1)?;
172 enc.write_struct_end()?;
173
174 let sig = cert
175 .signature
176 .as_bytes()
177 .context("can't get signature from x509")?;
178
179 let sig = ecdsa::Signature::<NistP256>::from_der(sig)?;
180
181 enc.write_octetstring(11, sig.to_bytes().as_slice())?;
182
183 enc.write_struct_end()?;
184 Ok(enc.data)
185}