Skip to content

Commit

Permalink
borrowed-remote-key
Browse files Browse the repository at this point in the history
  • Loading branch information
corrideat committed Jan 17, 2024
1 parent 30489d7 commit ccdfaf3
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 51 deletions.
6 changes: 3 additions & 3 deletions rcgen/src/csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ impl PublicKeyData for PublicKey {
}

/// Parameters for a certificate signing request
pub struct CertificateSigningRequestParams {
pub struct CertificateSigningRequestParams<'a> {
/// Parameters for the certificate to be signed.
pub params: CertificateParams,
pub params: CertificateParams<'a>,
/// Public key to include in the certificate signing request.
pub public_key: PublicKey,
}

impl CertificateSigningRequestParams {
impl CertificateSigningRequestParams<'_> {
/// Parse a certificate signing request from the ASCII PEM format
///
/// See [`from_der`](Self::from_der) for more details.
Expand Down
96 changes: 69 additions & 27 deletions rcgen/src/key_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ use crate::{Error, SignatureAlgorithm};

/// A key pair variant
#[allow(clippy::large_enum_variant)]
pub(crate) enum KeyPairKind {
pub(crate) enum KeyPairKind<'a> {
/// A Ecdsa key pair
Ec(EcdsaKeyPair),
/// A Ed25519 key pair
Ed(Ed25519KeyPair),
/// A RSA key pair
Rsa(RsaKeyPair, &'static dyn RsaEncoding),
/// A remote key pair
Remote(Box<dyn RemoteKeyPair + Send + Sync>),
Remote(&'a (dyn RemoteKeyPair + Send + Sync)),
}

impl fmt::Debug for KeyPairKind {
impl fmt::Debug for KeyPairKind<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Ec(key_pair) => write!(f, "{:?}", key_pair),
Expand All @@ -49,13 +49,13 @@ impl fmt::Debug for KeyPairKind {
/// for how to generate RSA keys in the wanted format
/// and conversion between the formats.
#[derive(Debug)]
pub struct KeyPair {
pub(crate) kind: KeyPairKind,
pub struct KeyPair<'a> {
pub(crate) kind: KeyPairKind<'a>,
pub(crate) alg: &'static SignatureAlgorithm,
pub(crate) serialized_der: Vec<u8>,
}

impl KeyPair {
impl<'a> KeyPair<'a> {
/// Parses the key pair from the DER format
///
/// Equivalent to using the [`TryFrom`] implementation.
Expand All @@ -77,7 +77,7 @@ impl KeyPair {
}

/// Obtains the key pair from a raw public key and a remote private key
pub fn from_remote(key_pair: Box<dyn RemoteKeyPair + Send + Sync>) -> Result<Self, Error> {
pub fn from_remote(key_pair: &'a (dyn RemoteKeyPair + Send + Sync)) -> Result<Self, Error> {
Ok(Self {
alg: key_pair.algorithm(),
kind: KeyPairKind::Remote(key_pair),
Expand Down Expand Up @@ -154,7 +154,7 @@ impl KeyPair {

pub(crate) fn from_raw(
pkcs8: &[u8],
) -> Result<(KeyPairKind, &'static SignatureAlgorithm), Error> {
) -> Result<(KeyPairKind<'a>, &'static SignatureAlgorithm), Error> {
let rng = SystemRandom::new();
let (kind, alg) = if let Ok(edkp) = Ed25519KeyPair::from_pkcs8_maybe_unchecked(pkcs8) {
(KeyPairKind::Ed(edkp), &PKCS_ED25519)
Expand Down Expand Up @@ -219,7 +219,7 @@ impl KeyPair {
/// If `None` is provided for `existing_key_pair` a new key pair compatible with `sig_alg`
/// is generated from scratch.
pub(crate) fn validate_or_generate(
existing_key_pair: &mut Option<KeyPair>,
existing_key_pair: &mut Option<KeyPair<'a>>,
sig_alg: &'static SignatureAlgorithm,
) -> Result<Self, Error> {
match existing_key_pair.take() {
Expand Down Expand Up @@ -251,32 +251,39 @@ impl KeyPair {
std::iter::once(self.alg)
}

pub(crate) fn sign(&self, msg: &[u8], writer: DERWriter) -> Result<(), Error> {
match &self.kind {
fn sign_raw(&self, msg: &[u8]) -> Result<Vec<u8>, Error> {
let signature = match &self.kind {
KeyPairKind::Ec(kp) => {
let system_random = SystemRandom::new();
let signature = kp.sign(&system_random, msg)._err()?;
let sig = &signature.as_ref();
writer.write_bitvec_bytes(&sig, &sig.len() * 8);

signature.as_ref().to_vec()
},
KeyPairKind::Ed(kp) => {
let signature = kp.sign(msg);
let sig = &signature.as_ref();
writer.write_bitvec_bytes(&sig, &sig.len() * 8);

signature.as_ref().to_vec()
},
KeyPairKind::Rsa(kp, padding_alg) => {
let system_random = SystemRandom::new();
let mut signature = vec![0; rsa_key_pair_public_modulus_len(kp)];
kp.sign(*padding_alg, &system_random, msg, &mut signature)
._err()?;
let sig = &signature.as_ref();
writer.write_bitvec_bytes(&sig, &sig.len() * 8);

signature
},
KeyPairKind::Remote(kp) => {
let signature = kp.sign(msg)?;
writer.write_bitvec_bytes(&signature, &signature.len() * 8);

signature
},
}
};
Ok(signature)
}

pub(crate) fn sign(&self, msg: &[u8], writer: DERWriter) -> Result<(), Error> {
let sig = self.sign_raw(msg)?;
writer.write_bitvec_bytes(&sig, &sig.len() * 8);
Ok(())
}

Expand Down Expand Up @@ -324,8 +331,8 @@ impl KeyPair {

/// Access the remote key pair if it is a remote one
pub fn as_remote(&self) -> Option<&(dyn RemoteKeyPair + Send + Sync)> {
if let KeyPairKind::Remote(remote) = &self.kind {
Some(remote.as_ref())
if let KeyPairKind::Remote(remote) = self.kind {
Some(remote)
} else {
None
}
Expand All @@ -340,23 +347,23 @@ impl KeyPair {
}
}

impl TryFrom<&[u8]> for KeyPair {
impl<'a> TryFrom<&[u8]> for KeyPair<'a> {
type Error = Error;

fn try_from(pkcs8: &[u8]) -> Result<KeyPair, Error> {
fn try_from(pkcs8: &[u8]) -> Result<KeyPair<'a>, Error> {
let (kind, alg) = KeyPair::from_raw(pkcs8)?;
Ok(KeyPair {
kind,
alg,
serialized_der: pkcs8.to_vec(),
serialized_der: pkcs8.to_vec().into(),
})
}
}

impl TryFrom<Vec<u8>> for KeyPair {
impl<'a> TryFrom<Vec<u8>> for KeyPair<'a> {
type Error = Error;

fn try_from(pkcs8: Vec<u8>) -> Result<KeyPair, Error> {
fn try_from(pkcs8: Vec<u8>) -> Result<KeyPair<'a>, Error> {
let (kind, alg) = KeyPair::from_raw(pkcs8.as_slice())?;
Ok(KeyPair {
kind,
Expand All @@ -366,7 +373,7 @@ impl TryFrom<Vec<u8>> for KeyPair {
}
}

impl PublicKeyData for KeyPair {
impl PublicKeyData for KeyPair<'_> {
fn alg(&self) -> &SignatureAlgorithm {
self.alg
}
Expand Down Expand Up @@ -395,6 +402,20 @@ pub trait RemoteKeyPair {
fn algorithm(&self) -> &'static SignatureAlgorithm;
}

impl RemoteKeyPair for KeyPair<'_> {
fn public_key(&self) -> &[u8] {
self.public_key_raw()
}

fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error> {
self.sign_raw(msg)
}

fn algorithm(&self) -> &'static SignatureAlgorithm {
self.alg
}
}

impl<T> ExternalError<T> for Result<T, ring_error::KeyRejected> {
fn _err(self) -> Result<T, Error> {
self.map_err(|e| Error::RingKeyRejected(e.to_string()))
Expand Down Expand Up @@ -432,6 +453,7 @@ pub(crate) trait PublicKeyData {
mod test {
use super::*;

use crate::key_pair;
use crate::ring_like::rand::SystemRandom;
use crate::ring_like::signature::{EcdsaKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING};

Expand All @@ -444,4 +466,24 @@ mod test {
let key_pair = KeyPair::from_der(&der).unwrap();
assert_eq!(key_pair.algorithm(), &PKCS_ECDSA_P256_SHA256);
}

#[test]
fn test_remote_key_pair() {
let key_pair = KeyPair::generate(&PKCS_ECDSA_P256_SHA256).unwrap();
assert_eq!(key_pair.algorithm(), &PKCS_ECDSA_P256_SHA256);
let remote_key1 = KeyPair::from_remote(&key_pair).unwrap();
let remote_key2 = KeyPair::from_remote(&key_pair).unwrap();
assert_eq!(remote_key1.algorithm(), key_pair.algorithm());
assert_eq!(remote_key2.algorithm(), key_pair.algorithm());
assert_eq!(remote_key1.public_key_der(), key_pair.public_key_der());
assert_eq!(remote_key2.public_key_der(), key_pair.public_key_der());
}

#[test]
#[should_panic]
fn test_remote_key_pair() {
let key_pair = KeyPair::generate(&PKCS_ECDSA_P256_SHA256).unwrap();
let remote_key = KeyPair::from_remote(&key_pair).unwrap();
remote_key.serialize_der();
}
}
42 changes: 21 additions & 21 deletions rcgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,16 @@ pub use crate::sign_algo::SignatureAlgorithm;
pub type RcgenError = Error;

/// An issued certificate, together with the subject keypair.
pub struct CertifiedKey {
pub struct CertifiedKey<'a> {
/// An issued certificate.
pub cert: Certificate,
pub cert: Certificate<'a>,
/// The certificate's subject key pair.
pub key_pair: KeyPair,
pub key_pair: KeyPair<'a>,
}

/// An issued certificate together with the parameters used to generate it.
pub struct Certificate {
params: CertificateParams,
pub struct Certificate<'a> {
params: CertificateParams<'a>,
subject_public_key_info: Vec<u8>,
der: Vec<u8>,
}
Expand Down Expand Up @@ -112,9 +112,9 @@ println!("{}", key_pair.serialize_pem());
```
"##
)]
pub fn generate_simple_self_signed(
pub fn generate_simple_self_signed<'a>(
subject_alt_names: impl Into<Vec<String>>,
) -> Result<CertifiedKey, Error> {
) -> Result<CertifiedKey<'a>, Error> {
Certificate::generate_self_signed(CertificateParams::new(subject_alt_names))
}

Expand Down Expand Up @@ -522,7 +522,7 @@ impl<'a> Iterator for DistinguishedNameIterator<'a> {
/// Parameters used for certificate generation
#[allow(missing_docs)]
#[non_exhaustive]
pub struct CertificateParams {
pub struct CertificateParams<'a> {
pub alg: &'static SignatureAlgorithm,
pub not_before: OffsetDateTime,
pub not_after: OffsetDateTime,
Expand All @@ -541,7 +541,7 @@ pub struct CertificateParams {
pub crl_distribution_points: Vec<CrlDistributionPoint>,
pub custom_extensions: Vec<CustomExtension>,
/// The certificate's key pair, a new random key pair will be generated if this is `None`
pub key_pair: Option<KeyPair>,
pub key_pair: Option<KeyPair<'a>>,
/// If `true`, the 'Authority Key Identifier' extension will be added to the generated cert
pub use_authority_key_identifier_extension: bool,
/// Method to generate key identifiers from public keys
Expand All @@ -550,7 +550,7 @@ pub struct CertificateParams {
pub key_identifier_method: KeyIdMethod,
}

impl Default for CertificateParams {
impl Default for CertificateParams<'_> {
fn default() -> Self {
// not_before and not_after set to reasonably long dates
let not_before = date_time_ymd(1975, 01, 01);
Expand All @@ -577,7 +577,7 @@ impl Default for CertificateParams {
}
}

impl CertificateParams {
impl<'a> CertificateParams<'a> {
/// Generate certificate parameters with reasonable defaults
pub fn new(subject_alt_names: impl Into<Vec<String>>) -> Self {
let subject_alt_names = subject_alt_names
Expand All @@ -598,7 +598,7 @@ impl CertificateParams {
///
/// See [`from_ca_cert_der`](Self::from_ca_cert_der) for more details.
#[cfg(all(feature = "pem", feature = "x509-parser"))]
pub fn from_ca_cert_pem(pem_str: &str, key_pair: KeyPair) -> Result<Self, Error> {
pub fn from_ca_cert_pem(pem_str: &str, key_pair: KeyPair<'a>) -> Result<Self, Error> {
let certificate = pem::parse(pem_str).or(Err(Error::CouldNotParseCertificate))?;
Self::from_ca_cert_der(certificate.contents(), key_pair)
}
Expand All @@ -619,7 +619,7 @@ impl CertificateParams {
/// for the presence of the `BasicConstraints` extension, or perform any other
/// validation.
#[cfg(feature = "x509-parser")]
pub fn from_ca_cert_der(ca_cert: &[u8], key_pair: KeyPair) -> Result<Self, Error> {
pub fn from_ca_cert_der(ca_cert: &[u8], key_pair: KeyPair<'a>) -> Result<Self, Error> {
let (_remainder, x509) = x509_parser::parse_x509_certificate(ca_cert)
.or(Err(Error::CouldNotParseCertificate))?;

Expand Down Expand Up @@ -1510,7 +1510,7 @@ fn write_general_subtrees(writer: DERWriter, tag: u64, general_subtrees: &[Gener
});
}

impl Certificate {
impl<'a> Certificate<'a> {
/// Generates a new self-signed certificate from the given parameters.
///
/// If [`CertificateParams::key_pair`] is not set to a pre-generated key, a new key pair
Expand Down Expand Up @@ -1553,10 +1553,10 @@ impl Certificate {
/// [`Certificate::pem`]. Similarly the private key of the returned [`KeyPair`] may be
/// serialized using [`KeyPair::serialize_der`] and [`KeyPair::serialize_pem`].
pub fn generate(
mut params: CertificateParams,
mut params: CertificateParams<'a>,
issuer: &Certificate,
issuer_key: &KeyPair,
) -> Result<CertifiedKey, Error> {
) -> Result<CertifiedKey<'a>, Error> {
let key_pair = KeyPair::validate_or_generate(&mut params.key_pair, params.alg)?;
let subject_public_key_info = key_pair.public_key_der();
let der = params.serialize_der_with_signer(
Expand Down Expand Up @@ -1587,10 +1587,10 @@ impl Certificate {
/// The returned [`Certificate`] may be serialized using [`Certificate::der`] and
/// [`Certificate::pem`].
pub fn from_request(
request: CertificateSigningRequestParams,
request: CertificateSigningRequestParams<'a>,
issuer: &Certificate,
issuer_key: &KeyPair,
) -> Result<Certificate, Error> {
) -> Result<Certificate<'a>, Error> {
let der = request.params.serialize_der_with_signer(
&request.public_key,
request.params.alg,
Expand Down Expand Up @@ -1722,21 +1722,21 @@ fn write_x509_authority_key_identifier(writer: DERWriter, aki: Vec<u8>) {
}

#[cfg(feature = "zeroize")]
impl zeroize::Zeroize for KeyPair {
impl zeroize::Zeroize for KeyPair<'_> {
fn zeroize(&mut self) {
self.serialized_der.zeroize();
}
}

#[cfg(feature = "zeroize")]
impl zeroize::Zeroize for CertificateSigningRequestParams {
impl zeroize::Zeroize for CertificateSigningRequestParams<'_> {
fn zeroize(&mut self) {
self.params.zeroize();
}
}

#[cfg(feature = "zeroize")]
impl zeroize::Zeroize for CertificateParams {
impl zeroize::Zeroize for CertificateParams<'_> {
fn zeroize(&mut self) {
self.key_pair.zeroize();
}
Expand Down

0 comments on commit ccdfaf3

Please sign in to comment.