Skip to content

Commit a8c8cb6

Browse files
committed
get extensions built
1 parent 051b0df commit a8c8cb6

File tree

2 files changed

+132
-18
lines changed

2 files changed

+132
-18
lines changed

x509-cert/src/builder.rs

+62-8
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ use crate::{
77
asn1::{BitString, BitStringRef, UIntRef},
88
Decode, Encode, SliceReader,
99
},
10+
ext::{pkix::BasicConstraints, Extension},
1011
name::Name,
1112
spki::{AlgorithmIdentifier, SubjectPublicKeyInfo},
1213
time::Validity,
1314
};
15+
use const_oid::AssociatedOid;
1416

1517
pub type Result<T> = core::result::Result<T, der::Error>;
1618

@@ -34,10 +36,45 @@ impl UniqueIds {
3436
}
3537
}
3638

39+
#[derive(Clone, Copy, Debug, PartialEq)]
40+
pub enum Profile {
41+
Root,
42+
SubCA,
43+
Leaf,
44+
}
45+
46+
impl Profile {
47+
fn build_extensions(&self) -> Result<Vec<Vec<u8>>> {
48+
let mut extensions = Vec::new();
49+
50+
match self {
51+
Profile::Root => {
52+
let ca_true = BasicConstraints {
53+
ca: true,
54+
path_len_constraint: None,
55+
}
56+
.to_vec()?;
57+
58+
extensions.push(
59+
Extension {
60+
extn_id: BasicConstraints::OID,
61+
critical: true,
62+
extn_value: &ca_true,
63+
}
64+
.to_vec()?,
65+
);
66+
}
67+
_ => {}
68+
};
69+
70+
Ok(extensions)
71+
}
72+
}
73+
3774
pub enum CertificateVersion {
3875
V1,
3976
V2(UniqueIds),
40-
V3(UniqueIds),
77+
V3 { uids: UniqueIds, profile: Profile },
4178
}
4279

4380
impl Into<Version> for CertificateVersion {
@@ -46,7 +83,7 @@ impl Into<Version> for CertificateVersion {
4683
match self {
4784
V1 => Version::V1,
4885
V2(_) => Version::V2,
49-
V3(_) => Version::V3,
86+
V3 { .. } => Version::V3,
5087
}
5188
}
5289
}
@@ -87,14 +124,16 @@ impl<SA: CertSignatureAlgorithm> CertificateBuilder<SA> {
87124
let serial_number = serial_number.to_vec()?;
88125
let subject_public_key_info = subject_public_key_info.to_vec()?;
89126

90-
let (version, (issuer_unique_id, subject_unique_id)) = match version {
91-
CertificateVersion::V1 => (Version::V1, (None, None)),
92-
CertificateVersion::V2(uids) => (Version::V2, uids.to_vec()?),
93-
CertificateVersion::V3(uids) => (Version::V3, uids.to_vec()?),
127+
let (version, (issuer_unique_id, subject_unique_id), extensions) = match version {
128+
CertificateVersion::V1 => (Version::V1, (None, None), Vec::new()),
129+
CertificateVersion::V2(uids) => (Version::V2, uids.to_vec()?, Vec::new()),
130+
CertificateVersion::V3 { uids, profile } => {
131+
(Version::V3, uids.to_vec()?, profile.build_extensions()?)
132+
}
94133
};
134+
println!("extensions: {:?}", extensions);
95135

96136
let signature = Default::default();
97-
let extensions = Default::default();
98137

99138
Ok(Self {
100139
version,
@@ -135,6 +174,21 @@ impl<SA: CertSignatureAlgorithm> CertificateBuilder<SA> {
135174
let issuer_unique_id = unique_id_mapper(&self.issuer_unique_id)?;
136175
let subject_unique_id = unique_id_mapper(&self.subject_unique_id)?;
137176

177+
let extensions = if self.version == Version::V3 {
178+
println!("LASKJD1");
179+
let mut extensions = Vec::new();
180+
for extension in &self.extensions {
181+
extensions.push(Extension::decode(&mut SliceReader::new(&extension)?)?);
182+
//extensions.push(Extension::from_der(&extension)?);
183+
}
184+
println!("LASKJD2");
185+
186+
Some(extensions)
187+
} else {
188+
None
189+
};
190+
println!("LASKJD3");
191+
138192
let tbs_certificate = TbsCertificate {
139193
version: self.version,
140194
serial_number,
@@ -145,7 +199,7 @@ impl<SA: CertSignatureAlgorithm> CertificateBuilder<SA> {
145199
subject_public_key_info,
146200
issuer_unique_id,
147201
subject_unique_id,
148-
extensions: None,
202+
extensions,
149203
};
150204

151205
self.signature = signer.sign(&tbs_certificate);

x509-cert/tests/builder.rs

+70-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![cfg(all(feature = "builder", feature = "pem"))]
22

3-
use der::{asn1::UIntRef, pem::LineEnding, EncodePem};
3+
use der::{asn1::UIntRef, pem::LineEnding, Decode, EncodePem};
44
use spki::SubjectPublicKeyInfo;
55
use std::{
66
fs::File,
@@ -10,7 +10,7 @@ use std::{
1010
};
1111
use tempfile::tempdir;
1212
use x509_cert::{
13-
builder::{CertificateBuilder, CertificateVersion, Signer, UniqueIds},
13+
builder::{CertificateBuilder, CertificateVersion, Profile, Signer, UniqueIds},
1414
certificate::{Certificate, TbsCertificate},
1515
constants,
1616
name::Name,
@@ -72,6 +72,8 @@ fn check_certificate(cert: &Certificate) {
7272
.read_to_end(&mut output_buf)
7373
.expect("read zlint output");
7474

75+
//println!("{}", String::from_utf8(output_buf.clone()).unwrap());
76+
7577
let output: zlint::LintResult =
7678
serde_json::from_slice(&output_buf).expect("parse zlint output");
7779

@@ -91,12 +93,16 @@ fn basic_certificate() {
9193
let serial_number = 42u32.to_be_bytes();
9294
let serial_number = UIntRef::new(&serial_number[..]).expect("create serial");
9395
let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
94-
let issuer = Name::default();
95-
let subject = Name::default();
96+
let issuer = Name::encode_from_string("CN=ca.example.com").unwrap();
97+
let issuer = Name::from_der(&issuer).unwrap();
98+
let subject = Name::encode_from_string("CN=demo.example.com").unwrap();
99+
let subject = Name::from_der(&subject).unwrap();
96100
let pub_key = SubjectPublicKeyInfo::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key");
97101

102+
let profile = Profile::Root;
103+
98104
let mut builder = CertificateBuilder::new(
99-
CertificateVersion::V3(uids),
105+
CertificateVersion::V3 { uids, profile },
100106
serial_number,
101107
constants::RsaWithSha256,
102108
validity,
@@ -116,7 +122,11 @@ fn basic_certificate() {
116122
}
117123
}
118124

119-
check_certificate(&builder.build(MockSigner).unwrap());
125+
let certificate = builder.build(MockSigner).unwrap();
126+
127+
println!("{}", openssl::text_output(&certificate));
128+
129+
check_certificate(&certificate);
120130
}
121131

122132
#[test]
@@ -140,11 +150,14 @@ mod zlint {
140150

141151
#[derive(Debug, Copy, Clone, PartialEq)]
142152
pub enum Status {
143-
NA,
153+
NotApplicable,
154+
NotEffective,
144155
Pass,
156+
Notice,
145157
Info,
146158
Warn,
147159
Error,
160+
Fatal,
148161
}
149162

150163
impl Status {
@@ -176,8 +189,11 @@ mod zlint {
176189
while let Some((key, value)) = access.next_entry::<&str, &str>()? {
177190
if key == "result" {
178191
value_output = Some(match value {
179-
"NA" => Status::NA,
192+
"NA" => Status::NotApplicable,
193+
"NE" => Status::NotEffective,
180194
"pass" => Status::Pass,
195+
"notice" => Status::Notice,
196+
"fatal" => Status::Fatal,
181197
"error" => Status::Error,
182198
"warn" => Status::Warn,
183199
"info" => Status::Info,
@@ -208,10 +224,11 @@ mod zlint {
208224

209225
impl LintResult {
210226
pub fn check_lints(&self, ignored: &[&str]) -> bool {
211-
let mut failed = Vec::new();
227+
let mut failed = HashMap::<String, Status>::new();
228+
212229
for (key, value) in &self.0 {
213230
if !value.is_successful() && !ignored.contains(&key.as_str()) {
214-
failed.push(String::from(key));
231+
failed.insert(String::from(key), value.clone());
215232
}
216233
}
217234

@@ -221,3 +238,46 @@ mod zlint {
221238
}
222239
}
223240
}
241+
242+
mod openssl {
243+
use der::{pem::LineEnding, EncodePem};
244+
use std::{
245+
fs::File,
246+
io::{Read, Write},
247+
process::{Command, Stdio},
248+
};
249+
use tempfile::tempdir;
250+
use x509_cert::certificate::Certificate;
251+
252+
pub fn text_output(cert: &Certificate) -> String {
253+
let tmp_dir = tempdir().expect("create tempdir");
254+
let cert_path = tmp_dir.path().join("cert.pem");
255+
256+
let pem = cert.to_pem(LineEnding::LF).expect("generate pem");
257+
let mut cert_file = File::create(&cert_path).expect("create pem file");
258+
cert_file
259+
.write_all(pem.as_bytes())
260+
.expect("Create pem file");
261+
262+
let mut child = Command::new("openssl")
263+
.arg("x509")
264+
.arg("-in")
265+
.arg(&cert_path)
266+
.arg("-noout")
267+
.arg("-text")
268+
.stderr(Stdio::inherit())
269+
.stdout(Stdio::piped())
270+
.spawn()
271+
.expect("zlint failed");
272+
let mut stdout = child.stdout.take().unwrap();
273+
let exit_status = child.wait().expect("get openssl x509 status");
274+
275+
assert!(exit_status.success(), "openssl failed");
276+
let mut output_buf = Vec::new();
277+
stdout
278+
.read_to_end(&mut output_buf)
279+
.expect("read openssl output");
280+
281+
String::from_utf8(output_buf.clone()).unwrap()
282+
}
283+
}

0 commit comments

Comments
 (0)