Skip to content

Commit 5f7af28

Browse files
committed
Invert KeyPair/SigningKey hierarchy
1 parent 2a653cc commit 5f7af28

File tree

6 files changed

+39
-74
lines changed

6 files changed

+39
-74
lines changed

rcgen/src/certificate.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::ENCODE_CONFIG;
1818
use crate::{
1919
oid, write_distinguished_name, write_dt_utc_or_generalized,
2020
write_x509_authority_key_identifier, write_x509_extension, DistinguishedName, Error, Issuer,
21-
KeyIdMethod, KeyPair, KeyUsagePurpose, SanType, SerialNumber,
21+
KeyIdMethod, KeyUsagePurpose, SanType, SerialNumber, SigningKey,
2222
};
2323

2424
/// An issued certificate together with the parameters used to generate it.
@@ -159,7 +159,7 @@ impl CertificateParams {
159159
self,
160160
public_key: &impl PublicKeyData,
161161
issuer: &Certificate,
162-
issuer_key: &KeyPair,
162+
issuer_key: &impl SigningKey,
163163
) -> Result<Certificate, Error> {
164164
let issuer = Issuer {
165165
distinguished_name: &issuer.params.distinguished_name,
@@ -180,7 +180,7 @@ impl CertificateParams {
180180
///
181181
/// The returned [`Certificate`] may be serialized using [`Certificate::der`] and
182182
/// [`Certificate::pem`].
183-
pub fn self_signed(self, key_pair: &KeyPair) -> Result<Certificate, Error> {
183+
pub fn self_signed(self, key_pair: &impl SigningKey) -> Result<Certificate, Error> {
184184
let issuer = Issuer {
185185
distinguished_name: &self.distinguished_name,
186186
key_identifier_method: &self.key_identifier_method,
@@ -210,7 +210,7 @@ impl CertificateParams {
210210
///
211211
/// This function is only of use if you have an existing CA certificate
212212
/// you would like to use to sign a certificate generated by `rcgen`.
213-
/// By providing the constructed [`CertificateParams`] and the [`KeyPair`]
213+
/// By providing the constructed [`CertificateParams`] and the [`SigningKey`]
214214
/// associated with your existing `ca_cert` you can use [`CertificateParams::signed_by()`]
215215
/// or [`crate::CertificateSigningRequestParams::signed_by()`] to issue new certificates
216216
/// using the CA cert.
@@ -541,7 +541,7 @@ impl CertificateParams {
541541
/// same output.
542542
pub fn serialize_request(
543543
&self,
544-
subject_key: &KeyPair,
544+
subject_key: &impl SigningKey,
545545
) -> Result<CertificateSigningRequest, Error> {
546546
self.serialize_request_with_attributes(subject_key, Vec::new())
547547
}
@@ -559,7 +559,7 @@ impl CertificateParams {
559559
/// [RFC 2986]: <https://datatracker.ietf.org/doc/html/rfc2986#section-4>
560560
pub fn serialize_request_with_attributes(
561561
&self,
562-
subject_key: &KeyPair,
562+
subject_key: &impl SigningKey,
563563
attrs: Vec<Attribute>,
564564
) -> Result<CertificateSigningRequest, Error> {
565565
// No .. pattern, we use this to ensure every field is used
@@ -643,7 +643,7 @@ impl CertificateParams {
643643
pub(crate) fn serialize_der_with_signer<K: PublicKeyData>(
644644
&self,
645645
pub_key: &K,
646-
issuer: Issuer<'_>,
646+
issuer: Issuer<'_, impl SigningKey>,
647647
) -> Result<CertificateDer<'static>, Error> {
648648
let der = sign_der(issuer.key_pair, |writer| {
649649
let pub_key_spki = pub_key.subject_public_key_info();
@@ -669,7 +669,7 @@ impl CertificateParams {
669669
}
670670
};
671671
// Write signature algorithm
672-
issuer.key_pair.alg.write_alg_ident(writer.next());
672+
issuer.key_pair.algorithm().write_alg_ident(writer.next());
673673
// Write issuer name
674674
write_distinguished_name(writer.next(), &issuer.distinguished_name);
675675
// Write validity
@@ -1233,6 +1233,8 @@ pub enum BasicConstraints {
12331233
mod tests {
12341234
#[cfg(feature = "pem")]
12351235
use super::*;
1236+
#[cfg(feature = "crypto")]
1237+
use crate::KeyPair;
12361238

12371239
#[cfg(feature = "crypto")]
12381240
#[test]

rcgen/src/crl.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::ENCODE_CONFIG;
1111
use crate::{
1212
oid, write_distinguished_name, write_dt_utc_or_generalized,
1313
write_x509_authority_key_identifier, write_x509_extension, Certificate, Error, Issuer,
14-
KeyIdMethod, KeyPair, KeyUsagePurpose, PublicKeyData, SerialNumber,
14+
KeyIdMethod, KeyUsagePurpose, SerialNumber, SigningKey,
1515
};
1616

1717
/// A certificate revocation list (CRL)
@@ -192,7 +192,7 @@ impl CertificateRevocationListParams {
192192
pub fn signed_by(
193193
self,
194194
issuer: &Certificate,
195-
issuer_key: &KeyPair,
195+
issuer_key: &impl SigningKey,
196196
) -> Result<CertificateRevocationList, Error> {
197197
if self.next_update.le(&self.this_update) {
198198
return Err(Error::InvalidCrlNextUpdate);
@@ -210,12 +210,12 @@ impl CertificateRevocationListParams {
210210
}
211211

212212
Ok(CertificateRevocationList {
213-
der: self.serialize_der(issuer)?.into(),
213+
der: self.serialize_der(&issuer)?.into(),
214214
params: self,
215215
})
216216
}
217217

218-
fn serialize_der(&self, issuer: Issuer) -> Result<Vec<u8>, Error> {
218+
fn serialize_der(&self, issuer: &Issuer<'_, impl SigningKey>) -> Result<Vec<u8>, Error> {
219219
sign_der(issuer.key_pair, |writer| {
220220
// Write CRL version.
221221
// RFC 5280 §5.1.2.1:
@@ -232,7 +232,7 @@ impl CertificateRevocationListParams {
232232
// RFC 5280 §5.1.2.2:
233233
// This field MUST contain the same algorithm identifier as the
234234
// signatureAlgorithm field in the sequence CertificateList
235-
issuer.key_pair.alg.write_alg_ident(writer.next());
235+
issuer.key_pair.algorithm().write_alg_ident(writer.next());
236236

237237
// Write issuer.
238238
// RFC 5280 §5.1.2.3:

rcgen/src/csr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use pki_types::CertificateSigningRequestDer;
77
#[cfg(feature = "pem")]
88
use crate::ENCODE_CONFIG;
99
use crate::{
10-
Certificate, CertificateParams, Error, Issuer, KeyPair, PublicKeyData, SignatureAlgorithm,
10+
Certificate, CertificateParams, Error, Issuer, PublicKeyData, SignatureAlgorithm, SigningKey,
1111
};
1212
#[cfg(feature = "x509-parser")]
1313
use crate::{DistinguishedName, SanType};
@@ -203,7 +203,7 @@ impl CertificateSigningRequestParams {
203203
pub fn signed_by(
204204
self,
205205
issuer: &Certificate,
206-
issuer_key: &KeyPair,
206+
issuer_key: &impl SigningKey,
207207
) -> Result<Certificate, Error> {
208208
let issuer = Issuer {
209209
distinguished_name: &issuer.params.distinguished_name,

rcgen/src/key_pair.rs

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#[cfg(feature = "crypto")]
12
use std::fmt;
23

34
#[cfg(feature = "pem")]
@@ -29,30 +30,23 @@ use crate::{sign_algo::SignatureAlgorithm, Error};
2930

3031
/// A key pair variant
3132
#[allow(clippy::large_enum_variant)]
33+
#[cfg(feature = "crypto")]
3234
pub(crate) enum KeyPairKind {
3335
/// A Ecdsa key pair
34-
#[cfg(feature = "crypto")]
3536
Ec(EcdsaKeyPair),
3637
/// A Ed25519 key pair
37-
#[cfg(feature = "crypto")]
3838
Ed(Ed25519KeyPair),
3939
/// A RSA key pair
40-
#[cfg(feature = "crypto")]
4140
Rsa(RsaKeyPair, &'static dyn RsaEncoding),
42-
/// A remote key pair
43-
Remote(Box<dyn SigningKey + Send + Sync>),
4441
}
4542

43+
#[cfg(feature = "crypto")]
4644
impl fmt::Debug for KeyPairKind {
4745
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4846
match self {
49-
#[cfg(feature = "crypto")]
5047
Self::Ec(key_pair) => write!(f, "{:?}", key_pair),
51-
#[cfg(feature = "crypto")]
5248
Self::Ed(key_pair) => write!(f, "{:?}", key_pair),
53-
#[cfg(feature = "crypto")]
5449
Self::Rsa(key_pair, _) => write!(f, "{:?}", key_pair),
55-
Self::Remote(_) => write!(f, "Box<dyn RemotePrivateKey>"),
5650
}
5751
}
5852
}
@@ -64,12 +58,14 @@ impl fmt::Debug for KeyPairKind {
6458
/// `openssl genrsa` doesn't work. See ring's [documentation](ring::signature::RsaKeyPair::from_pkcs8)
6559
/// for how to generate RSA keys in the wanted format
6660
/// and conversion between the formats.
61+
#[cfg(feature = "crypto")]
6762
pub struct KeyPair {
6863
pub(crate) kind: KeyPairKind,
6964
pub(crate) alg: &'static SignatureAlgorithm,
7065
pub(crate) serialized_der: Vec<u8>,
7166
}
7267

68+
#[cfg(feature = "crypto")]
7369
impl fmt::Debug for KeyPair {
7470
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7571
f.debug_struct("KeyPair")
@@ -80,6 +76,7 @@ impl fmt::Debug for KeyPair {
8076
}
8177
}
8278

79+
#[cfg(feature = "crypto")]
8380
impl KeyPair {
8481
/// Generate a new random [`PKCS_ECDSA_P256_SHA256`] key pair
8582
#[cfg(feature = "crypto")]
@@ -187,15 +184,6 @@ impl KeyPair {
187184
Self::try_from(private_key.contents())
188185
}
189186

190-
/// Obtains the key pair from a raw public key and a remote private key
191-
pub fn from_remote(key_pair: Box<dyn SigningKey + Send + Sync>) -> Result<Self, Error> {
192-
Ok(Self {
193-
alg: key_pair.algorithm(),
194-
kind: KeyPairKind::Remote(key_pair),
195-
serialized_der: Vec::new(),
196-
})
197-
}
198-
199187
/// Obtains the key pair from a DER formatted key
200188
/// using the specified [`SignatureAlgorithm`]
201189
///
@@ -422,11 +410,6 @@ impl KeyPair {
422410
///
423411
/// Panics if called on a remote key pair.
424412
pub fn serialize_der(&self) -> Vec<u8> {
425-
#[cfg_attr(not(feature = "crypto"), allow(irrefutable_let_patterns))]
426-
if let KeyPairKind::Remote(_) = self.kind {
427-
panic!("Serializing a remote key pair is not supported")
428-
}
429-
430413
self.serialized_der.clone()
431414
}
432415

@@ -435,24 +418,9 @@ impl KeyPair {
435418
///
436419
/// Panics if called on a remote key pair.
437420
pub fn serialized_der(&self) -> &[u8] {
438-
#[cfg_attr(not(feature = "crypto"), allow(irrefutable_let_patterns))]
439-
if let KeyPairKind::Remote(_) = self.kind {
440-
panic!("Serializing a remote key pair is not supported")
441-
}
442-
443421
&self.serialized_der
444422
}
445423

446-
/// Access the remote key pair if it is a remote one
447-
pub fn as_remote(&self) -> Option<&(dyn SigningKey + Send + Sync)> {
448-
#[cfg_attr(not(feature = "crypto"), allow(irrefutable_let_patterns))]
449-
if let KeyPairKind::Remote(remote) = &self.kind {
450-
Some(remote.as_ref())
451-
} else {
452-
None
453-
}
454-
}
455-
456424
/// Serializes the key pair (including the private key) in PKCS#8 format in PEM
457425
#[cfg(feature = "pem")]
458426
pub fn serialize_pem(&self) -> String {
@@ -479,21 +447,17 @@ impl SigningKey for KeyPair {
479447
._err()?;
480448
signature
481449
},
482-
KeyPairKind::Remote(kp) => kp.sign(msg)?,
483450
})
484451
}
485452
}
486453

454+
#[cfg(feature = "crypto")]
487455
impl PublicKeyData for KeyPair {
488456
fn der_bytes(&self) -> &[u8] {
489457
match &self.kind {
490-
#[cfg(feature = "crypto")]
491458
KeyPairKind::Ec(kp) => kp.public_key().as_ref(),
492-
#[cfg(feature = "crypto")]
493459
KeyPairKind::Ed(kp) => kp.public_key().as_ref(),
494-
#[cfg(feature = "crypto")]
495460
KeyPairKind::Rsa(kp, _) => kp.public_key().as_ref(),
496-
KeyPairKind::Remote(kp) => kp.der_bytes(),
497461
}
498462
}
499463

@@ -647,9 +611,6 @@ pub(crate) fn sign_der(
647611
}
648612

649613
/// A private key that is not directly accessible, but can be used to sign messages
650-
///
651-
/// Trait objects based on this trait can be passed to the [`KeyPair::from_remote`] function for generating certificates
652-
/// from a remote and raw private key, for example an HSM.
653614
pub trait SigningKey: PublicKeyData {
654615
/// Signs `msg` using the selected algorithm
655616
fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error>;

rcgen/src/lib.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ pub use crl::{
5757
};
5858
pub use csr::{CertificateSigningRequest, CertificateSigningRequestParams, PublicKey};
5959
pub use error::{Error, InvalidAsn1String};
60+
#[cfg(feature = "crypto")]
61+
pub use key_pair::KeyPair;
6062
pub use key_pair::PublicKeyData;
6163
#[cfg(all(feature = "crypto", feature = "aws_lc_rs"))]
6264
pub use key_pair::RsaKeySize;
63-
pub use key_pair::{KeyPair, SigningKey, SubjectPublicKeyInfo};
65+
pub use key_pair::{SigningKey, SubjectPublicKeyInfo};
6466
#[cfg(feature = "crypto")]
6567
use ring_like::digest;
6668
pub use sign_algo::algo::*;
@@ -84,11 +86,11 @@ mod string_types;
8486
pub type RcgenError = Error;
8587

8688
/// An issued certificate, together with the subject keypair.
87-
pub struct CertifiedKey {
89+
pub struct CertifiedKey<S: SigningKey> {
8890
/// An issued certificate.
8991
pub cert: Certificate,
9092
/// The certificate's subject key pair.
91-
pub key_pair: KeyPair,
93+
pub key_pair: S,
9294
}
9395

9496
/**
@@ -123,17 +125,17 @@ println!("{}", key_pair.serialize_pem());
123125
)]
124126
pub fn generate_simple_self_signed(
125127
subject_alt_names: impl Into<Vec<String>>,
126-
) -> Result<CertifiedKey, Error> {
128+
) -> Result<CertifiedKey<KeyPair>, Error> {
127129
let key_pair = KeyPair::generate()?;
128130
let cert = CertificateParams::new(subject_alt_names)?.self_signed(&key_pair)?;
129131
Ok(CertifiedKey { cert, key_pair })
130132
}
131133

132-
struct Issuer<'a> {
134+
struct Issuer<'a, S> {
133135
distinguished_name: &'a DistinguishedName,
134136
key_identifier_method: &'a KeyIdMethod,
135137
key_usages: &'a [KeyUsagePurpose],
136-
key_pair: &'a KeyPair,
138+
key_pair: &'a S,
137139
}
138140

139141
// https://tools.ietf.org/html/rfc5280#section-4.1.1

rcgen/tests/webpki.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ fn sign_msg_rsa(key_pair: &KeyPair, msg: &[u8], encoding: &'static dyn RsaEncodi
5252
signature
5353
}
5454

55-
fn check_cert<'a, 'b>(
55+
fn check_cert<'a, 'b, S: SigningKey + 'a>(
5656
cert_der: &CertificateDer<'_>,
5757
cert: &'a Certificate,
58-
cert_key: &'a KeyPair,
58+
cert_key: &'a S,
5959
alg: &dyn SignatureVerificationAlgorithm,
60-
sign_fn: impl FnOnce(&'a KeyPair, &'b [u8]) -> Vec<u8>,
60+
sign_fn: impl FnOnce(&'a S, &'b [u8]) -> Vec<u8>,
6161
) {
6262
#[cfg(feature = "pem")]
6363
{
@@ -66,13 +66,13 @@ fn check_cert<'a, 'b>(
6666
check_cert_ca(cert_der, cert_key, cert_der, alg, alg, sign_fn);
6767
}
6868

69-
fn check_cert_ca<'a, 'b>(
69+
fn check_cert_ca<'a, 'b, S: SigningKey + 'a>(
7070
cert_der: &CertificateDer<'_>,
71-
cert_key: &'a KeyPair,
71+
cert_key: &'a S,
7272
ca_der: &CertificateDer<'_>,
7373
cert_alg: &dyn SignatureVerificationAlgorithm,
7474
ca_alg: &dyn SignatureVerificationAlgorithm,
75-
sign_fn: impl FnOnce(&'a KeyPair, &'b [u8]) -> Vec<u8>,
75+
sign_fn: impl FnOnce(&'a S, &'b [u8]) -> Vec<u8>,
7676
) {
7777
let trust_anchor = anchor_from_trusted_cert(ca_der).unwrap();
7878
let trust_anchor_list = &[trust_anchor];
@@ -352,7 +352,7 @@ fn from_remote() {
352352
&rng,
353353
)
354354
.unwrap();
355-
let remote = KeyPair::from_remote(Box::new(Remote(remote))).unwrap();
355+
let remote = Remote(remote);
356356

357357
let (params, _) = util::default_params();
358358
let cert = params.self_signed(&remote).unwrap();

0 commit comments

Comments
 (0)