Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support compiling without cryptography primitives #208

Merged
merged 2 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
matrix:
features:
- --all-features
- --no-default-features
- --no-default-features --features ring
- --no-default-features --features aws_lc_rs
- --no-default-features --features aws_lc_rs,pem
Expand Down Expand Up @@ -137,6 +138,8 @@ jobs:
run: cargo test --verbose --features x509-parser --all-targets
- name: Run the tests with aws_lc_rs backend enabled
run: cargo test --verbose --no-default-features --features aws_lc_rs,pem --all-targets
- name: Run the tests with no features enabled
run: cargo test --verbose --no-default-features --all-targets

build:
strategy:
Expand Down
11 changes: 8 additions & 3 deletions rcgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ required-features = ["pem"]
name = "sign-leaf-with-ca"
required-features = ["pem", "x509-parser"]

[[example]]
name = "simple"
required-features = ["crypto"]

[dependencies]
aws-lc-rs = { version = "1.0.0", optional = true }
yasna = { version = "0.5.2", features = ["time", "std"] }
Expand All @@ -31,9 +35,10 @@ x509-parser = { workspace = true, features = ["verify"], optional = true }
zeroize = { version = "1.2", optional = true }

[features]
default = ["pem", "ring"]
aws_lc_rs = ["dep:aws-lc-rs"]
ring = ["dep:ring"]
default = ["crypto", "pem", "ring"]
crypto = []
est31 marked this conversation as resolved.
Show resolved Hide resolved
aws_lc_rs = ["crypto", "dep:aws-lc-rs"]
ring = ["crypto", "dep:ring"]


[package.metadata.docs.rs]
Expand Down
19 changes: 18 additions & 1 deletion rcgen/src/crl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,26 @@ use crate::{Certificate, Error, KeyIdMethod, KeyUsagePurpose, SerialNumber};
/// extern crate rcgen;
/// use rcgen::*;
///
/// #[cfg(not(feature = "crypto"))]
/// struct MyKeyPair { public_key: Vec<u8> }
/// #[cfg(not(feature = "crypto"))]
/// impl RemoteKeyPair for MyKeyPair {
/// fn public_key(&self) -> &[u8] { &self.public_key }
/// fn sign(&self, _: &[u8]) -> Result<Vec<u8>, rcgen::Error> { Ok(vec![]) }
/// fn algorithm(&self) -> &'static SignatureAlgorithm { &PKCS_ED25519 }
/// }
/// # fn main () {
/// // Generate a CRL issuer.
/// let mut issuer_params = CertificateParams::new(vec!["crl.issuer.example.com".to_string()]);
/// let mut issuer_params = CertificateParams::new(vec!["crl.issuer.example.com".to_string()]).unwrap();
/// issuer_params.serial_number = Some(SerialNumber::from(9999));
/// issuer_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
/// issuer_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::DigitalSignature, KeyUsagePurpose::CrlSign];
/// #[cfg(feature = "crypto")]
/// let key_pair = KeyPair::generate().unwrap();
/// #[cfg(not(feature = "crypto"))]
/// let remote_key_pair = MyKeyPair { public_key: vec![] };
/// #[cfg(not(feature = "crypto"))]
/// let key_pair = KeyPair::from_remote(Box::new(remote_key_pair)).unwrap();
/// let issuer = Certificate::generate_self_signed(issuer_params, &key_pair).unwrap();
/// // Describe a revoked certificate.
/// let revoked_cert = RevokedCertParams{
Expand All @@ -42,7 +56,10 @@ use crate::{Certificate, Error, KeyIdMethod, KeyUsagePurpose, SerialNumber};
/// crl_number: SerialNumber::from(1234),
/// issuing_distribution_point: None,
/// revoked_certs: vec![revoked_cert],
/// #[cfg(feature = "crypto")]
/// key_identifier_method: KeyIdMethod::Sha256,
/// #[cfg(not(feature = "crypto"))]
/// key_identifier_method: KeyIdMethod::PreSpecified(vec![]),
/// };
/// let crl = CertificateRevocationList::from_params(crl).unwrap();
///# }
Expand Down
5 changes: 5 additions & 0 deletions rcgen/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ pub enum Error {
InvalidCrlNextUpdate,
/// CRL issuer specifies Key Usages that don't include cRLSign.
IssuerNotCrlSigner,
#[cfg(not(feature = "crypto"))]
/// Missing serial number
MissingSerialNumber,
}

impl fmt::Display for Error {
Expand Down Expand Up @@ -86,6 +89,8 @@ impl fmt::Display for Error {
f,
"CRL issuer must specify no key usage, or key usage including cRLSign"
)?,
#[cfg(not(feature = "crypto"))]
MissingSerialNumber => write!(f, "A serial number must be specified")?,
};
Ok(())
}
Expand Down
58 changes: 46 additions & 12 deletions rcgen/src/key_pair.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
#[cfg(feature = "pem")]
use pem::Pem;
#[cfg(feature = "crypto")]
use std::convert::TryFrom;
use std::fmt;
use yasna::DERWriter;

#[cfg(any(feature = "crypto", feature = "pem"))]
use crate::error::ExternalError;
use crate::ring_like::error as ring_error;
use crate::ring_like::rand::SystemRandom;
use crate::ring_like::signature::{
self, EcdsaKeyPair, Ed25519KeyPair, KeyPair as RingKeyPair, RsaEncoding, RsaKeyPair,
#[cfg(feature = "crypto")]
djc marked this conversation as resolved.
Show resolved Hide resolved
use crate::ring_like::{
error as ring_error,
rand::SystemRandom,
signature::{
self, EcdsaKeyPair, Ed25519KeyPair, KeyPair as RingKeyPair, RsaEncoding, RsaKeyPair,
},
{ecdsa_from_pkcs8, rsa_key_pair_public_modulus_len},
};
use crate::ring_like::{ecdsa_from_pkcs8, rsa_key_pair_public_modulus_len};
use crate::sign_algo::algo::*;
use crate::sign_algo::SignAlgo;
#[cfg(feature = "crypto")]
use crate::sign_algo::{algo::*, SignAlgo};
#[cfg(feature = "pem")]
use crate::ENCODE_CONFIG;
use crate::{Error, SignatureAlgorithm};
use crate::{sign_algo::SignatureAlgorithm, Error};

/// A key pair variant
#[allow(clippy::large_enum_variant)]
pub(crate) enum KeyPairKind {
/// A Ecdsa key pair
#[cfg(feature = "crypto")]
Ec(EcdsaKeyPair),
/// A Ed25519 key pair
#[cfg(feature = "crypto")]
Ed(Ed25519KeyPair),
/// A RSA key pair
#[cfg(feature = "crypto")]
Rsa(RsaKeyPair, &'static dyn RsaEncoding),
/// A remote key pair
Remote(Box<dyn RemoteKeyPair + Send + Sync>),
Expand All @@ -33,8 +41,11 @@
impl fmt::Debug for KeyPairKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
#[cfg(feature = "crypto")]
Self::Ec(key_pair) => write!(f, "{:?}", key_pair),
#[cfg(feature = "crypto")]
Self::Ed(key_pair) => write!(f, "{:?}", key_pair),
#[cfg(feature = "crypto")]
Self::Rsa(key_pair, _) => write!(f, "{:?}", key_pair),
Self::Remote(_) => write!(f, "Box<dyn RemotePrivateKey>"),
}
Expand All @@ -57,13 +68,15 @@

impl KeyPair {
/// Generate a new random [`PKCS_ECDSA_P256_SHA256`] key pair
#[cfg(feature = "crypto")]
pub fn generate() -> Result<Self, Error> {
Self::generate_for(&PKCS_ECDSA_P256_SHA256)
}

/// Generate a new random key pair for the specified signature algorithm
///
/// If you're not sure which algorithm to use, [`PKCS_ECDSA_P256_SHA256`] is a good choice.
#[cfg(feature = "crypto")]
pub fn generate_for(alg: &'static SignatureAlgorithm) -> Result<Self, Error> {
let rng = &SystemRandom::new();

Expand Down Expand Up @@ -102,6 +115,7 @@
/// Parses the key pair from the DER format
///
/// Equivalent to using the [`TryFrom`] implementation.
#[cfg(feature = "crypto")]
pub fn from_der(der: &[u8]) -> Result<Self, Error> {
Ok(der.try_into()?)
}
Expand All @@ -112,7 +126,7 @@
}

/// Parses the key pair from the ASCII PEM format
#[cfg(feature = "pem")]
#[cfg(all(feature = "pem", feature = "crypto"))]
pub fn from_pem(pem_str: &str) -> Result<Self, Error> {
let private_key = pem::parse(pem_str)._err()?;
let private_key_der: &[_] = private_key.contents();
Expand All @@ -132,7 +146,7 @@
/// using the specified [`SignatureAlgorithm`]
///
/// Same as [from_pem_and_sign_algo](Self::from_pem_and_sign_algo).
#[cfg(feature = "pem")]
#[cfg(all(feature = "pem", feature = "crypto"))]
pub fn from_pem_and_sign_algo(
pem_str: &str,
alg: &'static SignatureAlgorithm,
Expand All @@ -151,6 +165,7 @@
/// key pair. However, sometimes multiple signature algorithms fit for the
/// same der key. In that instance, you can use this function to precisely
/// specify the `SignatureAlgorithm`.
#[cfg(feature = "crypto")]
pub fn from_der_and_sign_algo(
pkcs8: &[u8],
alg: &'static SignatureAlgorithm,
Expand Down Expand Up @@ -195,6 +210,7 @@
})
}

#[cfg(feature = "crypto")]
pub(crate) fn from_raw(
pkcs8: &[u8],
) -> Result<(KeyPairKind, &'static SignatureAlgorithm), Error> {
Expand Down Expand Up @@ -242,17 +258,20 @@

pub(crate) fn sign(&self, msg: &[u8], writer: DERWriter) -> Result<(), Error> {
match &self.kind {
#[cfg(feature = "crypto")]
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);
},
#[cfg(feature = "crypto")]
KeyPairKind::Ed(kp) => {
let signature = kp.sign(msg);
let sig = &signature.as_ref();
writer.write_bitvec_bytes(&sig, &sig.len() * 8);
},
#[cfg(feature = "crypto")]
KeyPairKind::Rsa(kp, padding_alg) => {
let system_random = SystemRandom::new();
let mut signature = vec![0; rsa_key_pair_public_modulus_len(kp)];
Expand Down Expand Up @@ -292,6 +311,7 @@
///
/// Panics if called on a remote key pair.
pub fn serialize_der(&self) -> Vec<u8> {
#[cfg_attr(not(feature = "crypto"), allow(irrefutable_let_patterns))]
if let KeyPairKind::Remote(_) = self.kind {
panic!("Serializing a remote key pair is not supported")
}
Expand All @@ -304,6 +324,7 @@
///
/// Panics if called on a remote key pair.
pub fn serialized_der(&self) -> &[u8] {
#[cfg_attr(not(feature = "crypto"), allow(irrefutable_let_patterns))]

Check warning on line 327 in rcgen/src/key_pair.rs

View check run for this annotation

Codecov / codecov/patch

rcgen/src/key_pair.rs#L327

Added line #L327 was not covered by tests
if let KeyPairKind::Remote(_) = self.kind {
panic!("Serializing a remote key pair is not supported")
}
Expand All @@ -313,6 +334,7 @@

/// Access the remote key pair if it is a remote one
pub fn as_remote(&self) -> Option<&(dyn RemoteKeyPair + Send + Sync)> {
#[cfg_attr(not(feature = "crypto"), allow(irrefutable_let_patterns))]
if let KeyPairKind::Remote(remote) = &self.kind {
Some(remote.as_ref())
} else {
Expand All @@ -329,6 +351,7 @@
}
}

#[cfg(feature = "crypto")]
impl TryFrom<&[u8]> for KeyPair {
type Error = Error;

Expand All @@ -342,6 +365,7 @@
}
}

#[cfg(feature = "crypto")]
impl TryFrom<Vec<u8>> for KeyPair {
type Error = Error;

Expand All @@ -361,8 +385,11 @@
}
fn raw_bytes(&self) -> &[u8] {
match &self.kind {
#[cfg(feature = "crypto")]
KeyPairKind::Ec(kp) => kp.public_key().as_ref(),
#[cfg(feature = "crypto")]
KeyPairKind::Ed(kp) => kp.public_key().as_ref(),
#[cfg(feature = "crypto")]
KeyPairKind::Rsa(kp, _) => kp.public_key().as_ref(),
KeyPairKind::Remote(kp) => kp.public_key(),
}
Expand All @@ -384,12 +411,14 @@
fn algorithm(&self) -> &'static SignatureAlgorithm;
}

#[cfg(feature = "crypto")]
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()))
}
}

#[cfg(feature = "crypto")]
impl<T> ExternalError<T> for Result<T, ring_error::Unspecified> {
fn _err(self) -> Result<T, Error> {
self.map_err(|_| Error::RingUnspecified)
Expand Down Expand Up @@ -419,11 +448,16 @@

#[cfg(test)]
mod test {
#[cfg(crypto)]
use super::*;

use crate::ring_like::rand::SystemRandom;
use crate::ring_like::signature::{EcdsaKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING};
#[cfg(crypto)]
use crate::ring_like::{
rand::SystemRandom,
signature::{EcdsaKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING},
};

#[cfg(crypto)]
#[test]
fn test_algorithm() {
let rng = SystemRandom::new();
Expand Down
Loading