Skip to content

Commit adc5441

Browse files
committed
Use Issuer in the public API
1 parent c69ad6f commit adc5441

File tree

10 files changed

+109
-82
lines changed

10 files changed

+109
-82
lines changed

rcgen/examples/sign-leaf-with-ca.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use rcgen::{
22
BasicConstraints, Certificate, CertificateParams, DnType, DnValue::PrintableString,
3-
ExtendedKeyUsagePurpose, IsCa, KeyPair, KeyUsagePurpose,
3+
ExtendedKeyUsagePurpose, IsCa, Issuer, KeyPair, KeyUsagePurpose,
44
};
55
use time::{Duration, OffsetDateTime};
66

77
/// Example demonstrating signing end-entity certificate with ca
88
fn main() {
9-
let (ca_params, ca, ca_key) = new_ca();
10-
let end_entity = new_end_entity(&ca_params, &ca_key);
9+
let (ca, issuer) = new_ca();
10+
let end_entity = new_end_entity(&issuer);
1111

1212
let end_entity_pem = end_entity.pem();
1313
println!("directly signed end-entity certificate: {end_entity_pem}");
@@ -16,7 +16,7 @@ fn main() {
1616
println!("ca certificate: {ca_cert_pem}");
1717
}
1818

19-
fn new_ca() -> (CertificateParams, Certificate, KeyPair) {
19+
fn new_ca() -> (Certificate, Issuer<'static, KeyPair>) {
2020
let mut params =
2121
CertificateParams::new(Vec::default()).expect("empty subject alt name can't produce error");
2222
let (yesterday, tomorrow) = validity_period();
@@ -37,10 +37,10 @@ fn new_ca() -> (CertificateParams, Certificate, KeyPair) {
3737

3838
let key_pair = KeyPair::generate().unwrap();
3939
let cert = params.self_signed(&key_pair).unwrap();
40-
(params, cert, key_pair)
40+
(cert, Issuer::new(params, key_pair))
4141
}
4242

43-
fn new_end_entity(ca: &CertificateParams, ca_key: &KeyPair) -> Certificate {
43+
fn new_end_entity(issuer: &Issuer<'static, KeyPair>) -> Certificate {
4444
let name = "entity.other.host";
4545
let mut params = CertificateParams::new(vec![name.into()]).expect("we know the name is valid");
4646
let (yesterday, tomorrow) = validity_period();
@@ -54,7 +54,7 @@ fn new_end_entity(ca: &CertificateParams, ca_key: &KeyPair) -> Certificate {
5454
params.not_after = tomorrow;
5555

5656
let key_pair = KeyPair::generate().unwrap();
57-
params.signed_by(&key_pair, ca, ca_key).unwrap()
57+
params.signed_by(&key_pair, issuer).unwrap()
5858
}
5959

6060
fn validity_period() -> (OffsetDateTime, OffsetDateTime) {

rcgen/src/certificate.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,8 @@ impl CertificateParams {
140140
pub fn signed_by(
141141
&self,
142142
public_key: &impl PublicKeyData,
143-
issuer: &CertificateParams,
144-
issuer_key: &impl SigningKey,
143+
issuer: &Issuer<'_, impl SigningKey>,
145144
) -> Result<Certificate, Error> {
146-
let issuer = Issuer::from_params(issuer, issuer_key);
147145
Ok(Certificate {
148146
der: self.serialize_der_with_signer(public_key, issuer)?,
149147
})
@@ -156,7 +154,7 @@ impl CertificateParams {
156154
pub fn self_signed(&self, signing_key: &impl SigningKey) -> Result<Certificate, Error> {
157155
let issuer = Issuer::from_params(self, signing_key);
158156
Ok(Certificate {
159-
der: self.serialize_der_with_signer(signing_key, issuer)?,
157+
der: self.serialize_der_with_signer(signing_key, &issuer)?,
160158
})
161159
}
162160

@@ -427,9 +425,9 @@ impl CertificateParams {
427425
pub(crate) fn serialize_der_with_signer<K: PublicKeyData>(
428426
&self,
429427
pub_key: &K,
430-
issuer: Issuer<'_, impl SigningKey>,
428+
issuer: &Issuer<'_, impl SigningKey>,
431429
) -> Result<CertificateDer<'static>, Error> {
432-
let der = sign_der(issuer.signing_key, |writer| {
430+
let der = sign_der(&*issuer.signing_key, |writer| {
433431
let pub_key_spki = pub_key.subject_public_key_info();
434432
// Write version
435433
writer.next().write_tagged(Tag::context(0), |writer| {
@@ -484,8 +482,7 @@ impl CertificateParams {
484482
}
485483

486484
writer.next().write_tagged(Tag::context(3), |writer| {
487-
writer
488-
.write_sequence(|writer| self.write_extensions(writer, &pub_key_spki, &issuer))
485+
writer.write_sequence(|writer| self.write_extensions(writer, &pub_key_spki, issuer))
489486
})?;
490487

491488
Ok(())
@@ -1412,12 +1409,13 @@ PITGdT9dgN88nHPCle0B1+OY+OZ5
14121409
.unwrap()
14131410
);
14141411

1412+
let issuer = Issuer::new(params, ca_kp);
14151413
let ee_key = KeyPair::generate().unwrap();
14161414
let ee_params = CertificateParams {
14171415
use_authority_key_identifier_extension: true,
14181416
..CertificateParams::default()
14191417
};
1420-
let ee_cert = ee_params.signed_by(&ee_key, &params, &ee_key).unwrap();
1418+
let ee_cert = ee_params.signed_by(&ee_key, &issuer).unwrap();
14211419

14221420
let (_, x509_ee) = x509_parser::parse_x509_certificate(ee_cert.der()).unwrap();
14231421
assert_eq!(

rcgen/src/crl.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use crate::key_pair::sign_der;
1010
use crate::ENCODE_CONFIG;
1111
use crate::{
1212
oid, write_distinguished_name, write_dt_utc_or_generalized,
13-
write_x509_authority_key_identifier, write_x509_extension, CertificateParams, Error, Issuer,
14-
KeyIdMethod, KeyUsagePurpose, SerialNumber, SigningKey,
13+
write_x509_authority_key_identifier, write_x509_extension, Error, Issuer, KeyIdMethod,
14+
KeyUsagePurpose, SerialNumber, SigningKey,
1515
};
1616

1717
/// A certificate revocation list (CRL)
@@ -43,7 +43,8 @@ use crate::{
4343
/// let key_pair = KeyPair::generate().unwrap();
4444
/// #[cfg(not(feature = "crypto"))]
4545
/// let key_pair = MyKeyPair { public_key: vec![] };
46-
/// let issuer = issuer_params.self_signed(&key_pair).unwrap();
46+
/// let issuer = Issuer::new(issuer_params, key_pair);
47+
///
4748
/// // Describe a revoked certificate.
4849
/// let revoked_cert = RevokedCertParams{
4950
/// serial_number: SerialNumber::from(9999),
@@ -62,7 +63,7 @@ use crate::{
6263
/// key_identifier_method: KeyIdMethod::Sha256,
6364
/// #[cfg(not(feature = "crypto"))]
6465
/// key_identifier_method: KeyIdMethod::PreSpecified(vec![]),
65-
/// }.signed_by(&issuer_params, &key_pair).unwrap();
66+
/// }.signed_by(&issuer).unwrap();
6667
///# }
6768
#[derive(Clone, Debug, PartialEq, Eq)]
6869
pub struct CertificateRevocationList {
@@ -186,14 +187,12 @@ impl CertificateRevocationListParams {
186187
/// Including a signature from the issuing certificate authority's key.
187188
pub fn signed_by(
188189
&self,
189-
issuer: &CertificateParams,
190-
issuer_key: &impl SigningKey,
190+
issuer: &Issuer<'_, impl SigningKey>,
191191
) -> Result<CertificateRevocationList, Error> {
192192
if self.next_update.le(&self.this_update) {
193193
return Err(Error::InvalidCrlNextUpdate);
194194
}
195195

196-
let issuer = Issuer::from_params(issuer, issuer_key);
197196
if !issuer.key_usages.is_empty() && !issuer.key_usages.contains(&KeyUsagePurpose::CrlSign) {
198197
return Err(Error::IssuerNotCrlSigner);
199198
}
@@ -203,8 +202,8 @@ impl CertificateRevocationListParams {
203202
})
204203
}
205204

206-
fn serialize_der(&self, issuer: Issuer<'_, impl SigningKey>) -> Result<Vec<u8>, Error> {
207-
sign_der(issuer.signing_key, |writer| {
205+
fn serialize_der(&self, issuer: &Issuer<'_, impl SigningKey>) -> Result<Vec<u8>, Error> {
206+
sign_der(&*issuer.signing_key, |writer| {
208207
// Write CRL version.
209208
// RFC 5280 §5.1.2.1:
210209
// This optional field describes the version of the encoded CRL. When

rcgen/src/csr.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,7 @@ impl CertificateSigningRequestParams {
200200
///
201201
/// The returned [`Certificate`] may be serialized using [`Certificate::der`] and
202202
/// [`Certificate::pem`].
203-
pub fn signed_by(
204-
&self,
205-
issuer: &CertificateParams,
206-
issuer_key: &impl SigningKey,
207-
) -> Result<Certificate, Error> {
208-
let issuer = Issuer::from_params(issuer, issuer_key);
203+
pub fn signed_by(&self, issuer: &Issuer<impl SigningKey>) -> Result<Certificate, Error> {
209204
Ok(Certificate {
210205
der: self
211206
.params

rcgen/src/lib.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use std::hash::Hash;
3939
use std::net::IpAddr;
4040
#[cfg(feature = "x509-parser")]
4141
use std::net::{Ipv4Addr, Ipv6Addr};
42+
use std::ops::Deref;
4243

4344
use time::{OffsetDateTime, Time};
4445
use yasna::models::ObjectIdentifier;
@@ -133,22 +134,41 @@ pub fn generate_simple_self_signed(
133134
Ok(CertifiedKey { cert, signing_key })
134135
}
135136

136-
struct Issuer<'a, S> {
137+
/// An issuer that can sign certificates.
138+
///
139+
/// Encapsulates the distinguished name, key identifier method, key usages and signing key
140+
/// of the issuing certificate.
141+
pub struct Issuer<'a, S> {
137142
distinguished_name: Cow<'a, DistinguishedName>,
138143
key_identifier_method: Cow<'a, KeyIdMethod>,
139144
key_usages: Cow<'a, [KeyUsagePurpose]>,
140-
signing_key: &'a S,
145+
signing_key: MaybeOwned<'a, S>,
141146
}
142147

143148
impl<'a, S: SigningKey> Issuer<'a, S> {
149+
/// Create a new issuer from the given parameters and signing key.
150+
pub fn new(params: CertificateParams, signing_key: S) -> Self {
151+
Self {
152+
distinguished_name: Cow::Owned(params.distinguished_name),
153+
key_identifier_method: Cow::Owned(params.key_identifier_method),
154+
key_usages: Cow::Owned(params.key_usages),
155+
signing_key: MaybeOwned::Owned(signing_key),
156+
}
157+
}
158+
144159
fn from_params(params: &'a CertificateParams, signing_key: &'a S) -> Self {
145160
Self {
146161
distinguished_name: Cow::Borrowed(&params.distinguished_name),
147162
key_identifier_method: Cow::Borrowed(&params.key_identifier_method),
148163
key_usages: Cow::Borrowed(&params.key_usages),
149-
signing_key,
164+
signing_key: MaybeOwned::Borrowed(signing_key),
150165
}
151166
}
167+
168+
/// Yield a reference to the signing key.
169+
pub fn key(&self) -> &S {
170+
&self.signing_key
171+
}
152172
}
153173

154174
impl<'a, S: SigningKey> fmt::Debug for Issuer<'a, S> {
@@ -171,6 +191,22 @@ impl<'a, S: SigningKey> fmt::Debug for Issuer<'a, S> {
171191
}
172192
}
173193

194+
enum MaybeOwned<'a, T> {
195+
Owned(T),
196+
Borrowed(&'a T),
197+
}
198+
199+
impl<T> Deref for MaybeOwned<'_, T> {
200+
type Target = T;
201+
202+
fn deref(&self) -> &Self::Target {
203+
match self {
204+
MaybeOwned::Owned(t) => t,
205+
MaybeOwned::Borrowed(t) => t,
206+
}
207+
}
208+
}
209+
174210
// https://tools.ietf.org/html/rfc5280#section-4.1.1
175211

176212
// Example certs usable as reference:

rcgen/tests/botan.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use time::{Duration, OffsetDateTime};
44

5-
use rcgen::{BasicConstraints, Certificate, CertificateParams, DnType, IsCa};
5+
use rcgen::{BasicConstraints, Certificate, CertificateParams, DnType, IsCa, Issuer};
66
use rcgen::{CertificateRevocationListParams, RevocationReason, RevokedCertParams};
77
use rcgen::{DnValue, KeyPair};
88
use rcgen::{KeyUsagePurpose, SerialNumber};
@@ -143,7 +143,8 @@ fn test_botan_separate_ca() {
143143
params.not_after = rcgen::date_time_ymd(3016, 1, 1);
144144

145145
let key_pair = KeyPair::generate().unwrap();
146-
let cert = params.signed_by(&key_pair, &ca_params, &ca_key).unwrap();
146+
let ca = Issuer::new(ca_params, ca_key);
147+
let cert = params.signed_by(&key_pair, &ca).unwrap();
147148
check_cert_ca(cert.der(), &cert, ca_cert.der());
148149
}
149150

@@ -169,9 +170,8 @@ fn test_botan_imported_ca() {
169170
params.not_after = rcgen::date_time_ymd(3016, 1, 1);
170171

171172
let key_pair = KeyPair::generate().unwrap();
172-
let cert = params
173-
.signed_by(&key_pair, &imported_ca_cert_params, &ca_key)
174-
.unwrap();
173+
let ca = Issuer::new(imported_ca_cert_params, ca_key);
174+
let cert = params.signed_by(&key_pair, &ca).unwrap();
175175
check_cert_ca(cert.der(), &cert, ca_cert_der);
176176
}
177177

@@ -200,9 +200,8 @@ fn test_botan_imported_ca_with_printable_string() {
200200
// Botan has a sanity check that enforces a maximum expiration date
201201
params.not_after = rcgen::date_time_ymd(3016, 1, 1);
202202
let key_pair = KeyPair::generate().unwrap();
203-
let cert = params
204-
.signed_by(&key_pair, &imported_ca_cert_params, &imported_ca_key)
205-
.unwrap();
203+
let ca = Issuer::new(imported_ca_cert_params, imported_ca_key);
204+
let cert = params.signed_by(&key_pair, &ca).unwrap();
206205

207206
check_cert_ca(cert.der(), &cert, ca_cert_der);
208207
}
@@ -219,6 +218,7 @@ fn test_botan_crl_parse() {
219218
KeyUsagePurpose::CrlSign,
220219
];
221220
let issuer_key = KeyPair::generate_for(alg).unwrap();
221+
let ca = Issuer::new(issuer, issuer_key);
222222

223223
// Create an end entity cert issued by the issuer.
224224
let (mut ee, _) = util::default_params();
@@ -227,7 +227,7 @@ fn test_botan_crl_parse() {
227227
// Botan has a sanity check that enforces a maximum expiration date
228228
ee.not_after = rcgen::date_time_ymd(3016, 1, 1);
229229
let ee_key = KeyPair::generate_for(alg).unwrap();
230-
let ee_cert = ee.signed_by(&ee_key, &issuer, &issuer_key).unwrap();
230+
let ee_cert = ee.signed_by(&ee_key, &ca).unwrap();
231231
let botan_ee = botan::Certificate::load(ee_cert.der()).unwrap();
232232

233233
// Generate a CRL with the issuer that revokes the EE cert.
@@ -246,7 +246,7 @@ fn test_botan_crl_parse() {
246246
key_identifier_method: rcgen::KeyIdMethod::Sha256,
247247
};
248248

249-
let crl = crl.signed_by(&issuer, &issuer_key).unwrap();
249+
let crl = crl.signed_by(&ca).unwrap();
250250

251251
// We should be able to load the CRL in both serializations.
252252
botan::CRL::load(crl.pem().unwrap().as_ref()).unwrap();

rcgen/tests/openssl.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use openssl::x509::{CrlStatus, X509Crl, X509Req, X509StoreContext, X509};
1414

1515
use rcgen::{
1616
BasicConstraints, Certificate, CertificateParams, DnType, DnValue, GeneralSubtree, IsCa,
17-
KeyPair, NameConstraints,
17+
Issuer, KeyPair, NameConstraints,
1818
};
1919

2020
mod util;
@@ -312,6 +312,7 @@ fn test_openssl_separate_ca() {
312312
ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
313313
let ca_cert = ca_params.self_signed(&ca_key).unwrap();
314314
let ca_cert_pem = ca_cert.pem();
315+
let ca = Issuer::new(ca_params, ca_key);
315316

316317
let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();
317318
params
@@ -321,7 +322,7 @@ fn test_openssl_separate_ca() {
321322
.distinguished_name
322323
.push(DnType::CommonName, "Dev domain");
323324
let cert_key = KeyPair::generate().unwrap();
324-
let cert = params.signed_by(&cert_key, &ca_params, &ca_key).unwrap();
325+
let cert = params.signed_by(&cert_key, &ca).unwrap();
325326
let key = cert_key.serialize_der();
326327

327328
verify_cert_ca(&cert.pem(), &key, &ca_cert_pem);
@@ -345,7 +346,8 @@ fn test_openssl_separate_ca_with_printable_string() {
345346
.distinguished_name
346347
.push(DnType::CommonName, "Dev domain");
347348
let cert_key = KeyPair::generate().unwrap();
348-
let cert = params.signed_by(&cert_key, &ca_params, &ca_key).unwrap();
349+
let ca = Issuer::new(ca_params, ca_key);
350+
let cert = params.signed_by(&cert_key, &ca).unwrap();
349351
let key = cert_key.serialize_der();
350352

351353
verify_cert_ca(&cert.pem(), &key, &ca_cert.pem());
@@ -357,6 +359,7 @@ fn test_openssl_separate_ca_with_other_signing_alg() {
357359
ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
358360
let ca_key = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256).unwrap();
359361
let ca_cert = ca_params.self_signed(&ca_key).unwrap();
362+
let ca = Issuer::new(ca_params, ca_key);
360363

361364
let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();
362365
params
@@ -366,7 +369,7 @@ fn test_openssl_separate_ca_with_other_signing_alg() {
366369
.distinguished_name
367370
.push(DnType::CommonName, "Dev domain");
368371
let cert_key = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P384_SHA384).unwrap();
369-
let cert = params.signed_by(&cert_key, &ca_params, &ca_key).unwrap();
372+
let cert = params.signed_by(&cert_key, &ca).unwrap();
370373
let key = cert_key.serialize_der();
371374

372375
verify_cert_ca(&cert.pem(), &key, &ca_cert.pem());
@@ -387,6 +390,7 @@ fn test_openssl_separate_ca_name_constraints() {
387390
excluded_subtrees: Vec::new(),
388391
});
389392
let ca_cert = ca_params.self_signed(&ca_key).unwrap();
393+
let ca = Issuer::new(ca_params, ca_key);
390394

391395
let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();
392396
params
@@ -396,7 +400,7 @@ fn test_openssl_separate_ca_name_constraints() {
396400
.distinguished_name
397401
.push(DnType::CommonName, "Dev domain");
398402
let cert_key = KeyPair::generate().unwrap();
399-
let cert = params.signed_by(&cert_key, &ca_params, &ca_key).unwrap();
403+
let cert = params.signed_by(&cert_key, &ca).unwrap();
400404
let key = cert_key.serialize_der();
401405

402406
verify_cert_ca(&cert.pem(), &key, &ca_cert.pem());

0 commit comments

Comments
 (0)