Skip to content

Commit 240c0f9

Browse files
committed
document the api
1 parent 822c7de commit 240c0f9

File tree

9 files changed

+245
-120
lines changed

9 files changed

+245
-120
lines changed

x509-cert/src/builder.rs

+169-109
Large diffs are not rendered by default.

x509-cert/src/constants.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
1+
//! Constants for X509 signature algorithm
2+
13
use crate::{builder::CertSignatureAlgorithm, der::asn1, spki::AlgorithmIdentifier};
24

5+
/// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { iso(1)
6+
/// member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 11 }
7+
///
8+
/// https://datatracker.ietf.org/doc/html/rfc5754#section-3.2
39
pub struct RsaWithSha256;
410

511
impl RsaWithSha256 {
612
const OID: asn1::ObjectIdentifier = asn1::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.11");
713
}
814

915
impl CertSignatureAlgorithm for RsaWithSha256 {
10-
fn signature_algorithm(&self) -> AlgorithmIdentifier<'_> {
16+
fn identifier(&self) -> AlgorithmIdentifier<'_> {
1117
AlgorithmIdentifier {
1218
oid: RsaWithSha256::OID.clone(),
1319
parameters: Some(asn1::AnyRef::NULL),

x509-cert/src/ext.rs

+21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Standardized X.509 Certificate Extensions
22
3+
use const_oid::AssociatedOid;
34
use der::Sequence;
45
use spki::ObjectIdentifier;
56

@@ -42,3 +43,23 @@ pub struct Extension<'a> {
4243
///
4344
/// [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9
4445
pub type Extensions<'a> = alloc::vec::Vec<Extension<'a>>;
46+
47+
/// Trait to be implemented by extensions to allow them to be formated as x509 v3 extensions by
48+
/// builder.
49+
pub trait AsExtension: AssociatedOid + der::Encode {
50+
/// Should the extension be marked critical
51+
const CRITICAL: bool;
52+
53+
/// Returns the der representation of the Extension.
54+
fn to_extension_vec(&self) -> Result<alloc::vec::Vec<u8>, der::Error> {
55+
use der::Encode;
56+
let content = self.to_vec()?;
57+
58+
Extension {
59+
extn_id: <Self as AssociatedOid>::OID,
60+
critical: Self::CRITICAL,
61+
extn_value: &content,
62+
}
63+
.to_vec()
64+
}
65+
}

x509-cert/src/ext/pkix.rs

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ impl<'a> AssociatedOid for SubjectKeyIdentifier<'a> {
4848
}
4949

5050
impl_newtype!(SubjectKeyIdentifier<'a>, OctetStringRef<'a>);
51+
impl_extension!(SubjectKeyIdentifier<'a>);
5152

5253
/// SubjectAltName as defined in [RFC 5280 Section 4.2.1.6].
5354
///
@@ -64,6 +65,7 @@ impl<'a> AssociatedOid for SubjectAltName<'a> {
6465
}
6566

6667
impl_newtype!(SubjectAltName<'a>, name::GeneralNames<'a>);
68+
impl_extension!(SubjectAltName<'a>);
6769

6870
/// IssuerAltName as defined in [RFC 5280 Section 4.2.1.7].
6971
///
@@ -80,6 +82,7 @@ impl<'a> AssociatedOid for IssuerAltName<'a> {
8082
}
8183

8284
impl_newtype!(IssuerAltName<'a>, name::GeneralNames<'a>);
85+
impl_extension!(IssuerAltName<'a>);
8386

8487
/// SubjectDirectoryAttributes as defined in [RFC 5280 Section 4.2.1.8].
8588
///

x509-cert/src/ext/pkix/authkeyid.rs

+2
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,5 @@ pub struct AuthorityKeyIdentifier<'a> {
3434
impl<'a> AssociatedOid for AuthorityKeyIdentifier<'a> {
3535
const OID: ObjectIdentifier = ID_CE_AUTHORITY_KEY_IDENTIFIER;
3636
}
37+
38+
impl_extension!(AuthorityKeyIdentifier<'a>);

x509-cert/src/ext/pkix/constraints/basic.rs

+2
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ pub struct BasicConstraints {
2222
impl AssociatedOid for BasicConstraints {
2323
const OID: ObjectIdentifier = ID_CE_BASIC_CONSTRAINTS;
2424
}
25+
26+
impl_extension!(BasicConstraints, critical = true);

x509-cert/src/ext/pkix/keyusage.rs

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ impl AssociatedOid for KeyUsage {
5252
}
5353

5454
impl_newtype!(KeyUsage, FlagSet<KeyUsages>);
55+
impl_extension!(KeyUsage, critical = true);
5556

5657
/// ExtKeyUsageSyntax as defined in [RFC 5280 Section 4.2.1.12].
5758
///

x509-cert/src/macros.rs

+13
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,16 @@ macro_rules! impl_newtype {
7171
}
7272
};
7373
}
74+
75+
/// Implements the AsExtension traits for every defined Extension paylooad
76+
macro_rules! impl_extension {
77+
($newtype:ty) => {
78+
impl_extension!($newtype, critical = false);
79+
};
80+
($newtype:ty, critical = $critical:expr) => {
81+
#[allow(unused_lifetimes)]
82+
impl<'a> crate::ext::AsExtension for $newtype {
83+
const CRITICAL: bool = $critical;
84+
}
85+
};
86+
}

x509-cert/tests/builder.rs

+27-10
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const ZLINT_CONFIG: &str = &"
3939
Rounds = 100
4040
";
4141

42-
fn check_certificate(cert: &Certificate) {
42+
fn check_certificate(cert: &Certificate, ignored: &[&str]) {
4343
let tmp_dir = tempdir().expect("create tempdir");
4444
let config_path = tmp_dir.path().join("config.toml");
4545
let cert_path = tmp_dir.path().join("cert.pem");
@@ -78,7 +78,6 @@ fn check_certificate(cert: &Certificate) {
7878
let output: zlint::LintResult =
7979
serde_json::from_slice(&output_buf).expect("parse zlint output");
8080

81-
let ignored = &[];
8281
assert!(output.check_lints(ignored));
8382
}
8483

@@ -103,20 +102,21 @@ fn root_ca_certificate() {
103102

104103
let mut builder = CertificateBuilder::new(
105104
profile,
106-
CertificateVersion::V3 { uids },
105+
CertificateVersion::V3(uids),
107106
serial_number,
108-
constants::RsaWithSha256,
109107
validity,
110108
subject,
111109
pub_key,
110+
&RsaCertSigner,
112111
)
113112
.expect("Create certificate");
114113

115-
let certificate = builder.build(RsaCertSigner).unwrap();
114+
let certificate = builder.build().unwrap();
116115

117116
println!("{}", openssl::text_output(&certificate));
118117

119-
check_certificate(&certificate);
118+
let ignored = &[];
119+
check_certificate(&certificate, ignored);
120120
}
121121

122122
#[test]
@@ -147,20 +147,29 @@ fn sub_ca_certificate() {
147147

148148
let mut builder = CertificateBuilder::new(
149149
profile,
150-
CertificateVersion::V3 { uids },
150+
CertificateVersion::V3(uids),
151151
serial_number,
152-
constants::RsaWithSha256,
152+
//constants::RsaWithSha256,
153153
validity,
154154
subject,
155155
pub_key,
156+
&RsaCertSigner,
156157
)
157158
.expect("Create certificate");
158159

159-
let certificate = builder.build(RsaCertSigner).unwrap();
160+
let certificate = builder.build().unwrap();
160161

161162
println!("{}", openssl::text_output(&certificate));
162163

163-
check_certificate(&certificate);
164+
// TODO(baloo): not too sure we should tackle those in this API.
165+
let ignored = &[
166+
"w_sub_ca_aia_missing",
167+
"e_sub_ca_crl_distribution_points_missing",
168+
"e_sub_ca_certificate_policies_missing",
169+
"w_sub_ca_aia_does_not_contain_issuing_ca_url",
170+
];
171+
172+
check_certificate(&certificate, ignored);
164173
}
165174

166175
const RSA_2048_PRIV_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-priv.der");
@@ -170,6 +179,14 @@ struct RsaCertSigner;
170179
impl Signer for RsaCertSigner {
171180
type Alg = constants::RsaWithSha256;
172181

182+
fn signature_algorithm(&self) -> Self::Alg {
183+
constants::RsaWithSha256
184+
}
185+
186+
fn public_key(&self) -> SubjectPublicKeyInfo {
187+
SubjectPublicKeyInfo::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key")
188+
}
189+
173190
fn sign(&self, input: &TbsCertificate<'_>) -> Vec<u8> {
174191
use rsa::pkcs1v15::SigningKey;
175192
use rsa::signature::{RandomizedSigner, Signature};

0 commit comments

Comments
 (0)