Skip to content

Commit 4cc7cad

Browse files
committed
bump rcgen to 0.14.2
Recent versions of rcgen contain nice features, so I decided to bump the crate and fix all breaking changes first before our usage of it is expanded by the pkcs11 create key PR. Relevant features: - `0.13.0` - P521 support - only supports RSA PKCS#1 v1.5, which is vulnerable to [Marvin Attack](https://people.redhat.com/~hkario/marvin/), new versions of `rcgen` might have RSA PSS signatures added in the future - The API used to create/issue key pairs, certificates, certificate signing requests (CSRs), and certificate revocation lists (CRLs) has been restructured to emphasize consistency and avoid common errors with serialization. (better to fix breaking changes ASAP) - Support for using `aws-lc-rs` in `fips` mode - `0.13.1` - Several improvements to the capabilities available when working with certificate signing requests - Enable signing without private key - `0.14.0` - better remote signing API (`RemoteKeyPair` changed to `SigningKey`) Signed-off-by: Marcel Guzik <marcel.guzik@cumulocity.com>
1 parent fc0f092 commit 4cc7cad

File tree

10 files changed

+134
-104
lines changed

10 files changed

+134
-104
lines changed

Cargo.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ quote = "1"
159159
rand = "0.8"
160160
rasn = "0.18" # Not using the latest version which requires rust 1.85
161161
rasn-cms = "0.18" # Not using the latest version which requires rust 1.85
162-
rcgen = { version = "0.12", features = ["pem", "zeroize"] }
162+
rcgen = { version = "0.14", features = ["pem", "zeroize"] }
163163
regex = "1.4"
164164
reqwest = { version = "0.12", default-features = false }
165165
ron = "0.8"

crates/common/axum_tls/src/acceptor.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,7 @@ mod tests {
175175
let permitted_certificate =
176176
rcgen::generate_simple_self_signed(vec!["not-my-client".into()]).unwrap();
177177
let mut roots = RootCertStore::empty();
178-
roots
179-
.add(permitted_certificate.serialize_der().unwrap().into())
180-
.unwrap();
178+
roots.add(permitted_certificate.cert.der().clone()).unwrap();
181179
let server = Server::with_trusted_roots(roots);
182180
let client = Client::builder()
183181
.add_root_certificate(server.certificate.clone())
@@ -198,9 +196,7 @@ mod tests {
198196
let permitted_certificate =
199197
rcgen::generate_simple_self_signed(vec!["not-my-client".into()]).unwrap();
200198
let mut roots = RootCertStore::empty();
201-
roots
202-
.add(permitted_certificate.serialize_der().unwrap().into())
203-
.unwrap();
199+
roots.add(permitted_certificate.cert.der().clone()).unwrap();
204200
let server = Server::with_trusted_roots(roots);
205201
let client = Client::builder()
206202
.add_root_certificate(server.certificate.clone())
@@ -223,9 +219,8 @@ mod tests {
223219
let client_cert = rcgen::generate_simple_self_signed(["my-client".into()]).unwrap();
224220
let identity = identity_from(&client_cert);
225221
let mut cert_store = RootCertStore::empty();
226-
cert_store.add_parsable_certificates([CertificateDer::from(
227-
client_cert.serialize_der().unwrap(),
228-
)]);
222+
cert_store
223+
.add_parsable_certificates([CertificateDer::from(client_cert.cert.der().as_ref())]);
229224

230225
let server = Server::with_trusted_roots(cert_store);
231226
let client = Client::builder()
@@ -253,9 +248,9 @@ mod tests {
253248
identity_from(&client_cert)
254249
}
255250

256-
fn identity_from(cert: &rcgen::Certificate) -> Identity {
257-
let mut pem = cert.serialize_private_key_pem().into_bytes();
258-
pem.append(&mut cert.serialize_pem().unwrap().into_bytes());
251+
fn identity_from(cert: &rcgen::CertifiedKey<rcgen::KeyPair>) -> Identity {
252+
let mut pem = cert.signing_key.serialize_pem().into_bytes();
253+
pem.append(&mut cert.cert.pem().into_bytes());
259254
Identity::from_pem(&pem).unwrap()
260255
}
261256

@@ -293,9 +288,9 @@ mod tests {
293288
port += 1;
294289
};
295290
let certificate = rcgen::generate_simple_self_signed(["localhost".to_owned()]).unwrap();
296-
let certificate_der = CertificateDer::from(certificate.serialize_der().unwrap());
291+
let certificate_der = certificate.cert.der().clone();
297292
let private_key_der =
298-
PrivateKeyDer::from_pem_slice(certificate.serialize_private_key_pem().as_bytes())
293+
PrivateKeyDer::from_pem_slice(certificate.signing_key.serialize_pem().as_bytes())
299294
.unwrap();
300295
let certificate = reqwest::Certificate::from_der(&certificate_der).unwrap();
301296
let config = ssl_config(vec![certificate_der], private_key_der, trusted_roots).unwrap();

crates/common/axum_tls/src/config.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ use yansi::Paint;
4949
/// use tedge_config::{OptionalConfig, TEdgeConfig};
5050
///
5151
/// let cert = rcgen::generate_simple_self_signed(["localhost".to_owned()]).unwrap();
52-
/// let cert_pem = cert.serialize_pem().unwrap();
53-
/// let key_pem = cert.serialize_private_key_pem();
52+
/// let cert_pem = cert.cert.pem();
53+
/// let key_pem = cert.signing_key.serialize_pem();
5454
///
5555
/// let config = load_ssl_config(
5656
/// OptionalConfig::present(InjectedValue(cert_pem), "http.cert_path"),
@@ -147,7 +147,7 @@ pub trait TrustStoreLoader {
147147
/// use axum_tls::config::InjectedValue;
148148
/// use axum_tls::load_cert;
149149
/// let cert = rcgen::generate_simple_self_signed(["localhost".to_owned()]).unwrap();
150-
/// let pem_data = cert.serialize_pem().unwrap();
150+
/// let pem_data = cert.cert.pem();
151151
///
152152
/// let loaded_chain = load_cert(&InjectedValue(pem_data)).unwrap();
153153
///

crates/common/certificate/src/lib.rs

Lines changed: 88 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use anyhow::Context;
22
use camino::Utf8Path;
33
use device_id::DeviceIdError;
4-
use rcgen::Certificate;
54
use rcgen::CertificateParams;
65
use rcgen::KeyPair;
76
use sha1::Digest;
@@ -224,17 +223,17 @@ pub struct RemoteKeyPair {
224223
algorithm: &'static rcgen::SignatureAlgorithm,
225224
}
226225

227-
impl RemoteKeyPair {
228-
pub fn to_key_pair(&self) -> Result<KeyPair, CertificateError> {
229-
Ok(KeyPair::from_remote(Box::new(self.clone()))?)
226+
impl rcgen::PublicKeyData for RemoteKeyPair {
227+
fn der_bytes(&self) -> &[u8] {
228+
&self.public_key_raw
230229
}
231-
}
232230

233-
impl rcgen::RemoteKeyPair for RemoteKeyPair {
234-
fn public_key(&self) -> &[u8] {
235-
&self.public_key_raw
231+
fn algorithm(&self) -> &'static rcgen::SignatureAlgorithm {
232+
self.algorithm
236233
}
234+
}
237235

236+
impl rcgen::SigningKey for RemoteKeyPair {
238237
fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, rcgen::Error> {
239238
// the error here is not PEM-related, but we need to return a foreign error type, and there
240239
// are no other better variants that could let us return context, so we'll have to use this
@@ -245,14 +244,43 @@ impl rcgen::RemoteKeyPair for RemoteKeyPair {
245244
.sign(msg)
246245
.map_err(|e| rcgen::Error::PemError(e.to_string()))
247246
}
247+
}
248+
249+
pub struct KeyCertPair {
250+
certificate: rcgen::Certificate,
251+
// in rcgen 0.14 params are necessary to generate the CSR
252+
params: rcgen::CertificateParams,
253+
signing_key: SigningKeyWrapper,
254+
}
255+
256+
enum SigningKeyWrapper {
257+
Local(Zeroizing<rcgen::KeyPair>),
258+
Remote(RemoteKeyPair),
259+
}
260+
261+
impl rcgen::PublicKeyData for SigningKeyWrapper {
262+
fn der_bytes(&self) -> &[u8] {
263+
match self {
264+
Self::Local(k) => k.der_bytes(),
265+
Self::Remote(k) => k.der_bytes(),
266+
}
267+
}
248268

249269
fn algorithm(&self) -> &'static rcgen::SignatureAlgorithm {
250-
self.algorithm
270+
match self {
271+
Self::Local(k) => k.algorithm(),
272+
Self::Remote(k) => k.algorithm(),
273+
}
251274
}
252275
}
253276

254-
pub struct KeyCertPair {
255-
certificate: Zeroizing<rcgen::Certificate>,
277+
impl rcgen::SigningKey for SigningKeyWrapper {
278+
fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, rcgen::Error> {
279+
match self {
280+
Self::Local(k) => k.sign(msg),
281+
Self::Remote(k) => k.sign(msg),
282+
}
283+
}
256284
}
257285

258286
impl KeyCertPair {
@@ -263,11 +291,13 @@ impl KeyCertPair {
263291
) -> Result<KeyCertPair, CertificateError> {
264292
let today = OffsetDateTime::now_utc();
265293
let not_before = today - Duration::days(1); // Ensure the certificate is valid today
266-
let params =
294+
let (params, signing_key) =
267295
Self::create_selfsigned_certificate_parameters(config, id, key_kind, not_before)?;
268296

269297
Ok(KeyCertPair {
270-
certificate: Zeroizing::new(Certificate::from_params(params)?),
298+
certificate: params.self_signed(&signing_key)?,
299+
signing_key,
300+
params,
271301
})
272302
}
273303

@@ -278,11 +308,14 @@ impl KeyCertPair {
278308
) -> Result<KeyCertPair, CertificateError> {
279309
// Create Certificate without `not_before` and `not_after` fields
280310
// as rcgen library will not parse it for certificate signing request
281-
let params = Self::create_csr_parameters(config, id, key_kind)?;
311+
let (params, signing_key) = Self::create_csr_parameters(config, id, key_kind)?;
312+
let issuer = rcgen::Issuer::from_params(&params, &signing_key);
282313
Ok(KeyCertPair {
283-
certificate: Zeroizing::new(
284-
Certificate::from_params(params).context("Failed to create CSR")?,
285-
),
314+
certificate: params
315+
.signed_by(&signing_key, &issuer)
316+
.context("Failed to create CSR")?,
317+
signing_key,
318+
params,
286319
})
287320
}
288321

@@ -291,8 +324,8 @@ impl KeyCertPair {
291324
id: &str,
292325
key_kind: &KeyKind,
293326
not_before: OffsetDateTime,
294-
) -> Result<CertificateParams, CertificateError> {
295-
let mut params = Self::create_csr_parameters(config, id, key_kind)?;
327+
) -> Result<(CertificateParams, SigningKeyWrapper), CertificateError> {
328+
let (mut params, signing_key) = Self::create_csr_parameters(config, id, key_kind)?;
296329

297330
let not_after = not_before + Duration::days(config.validity_period_days.into());
298331
params.not_before = not_before;
@@ -301,14 +334,14 @@ impl KeyCertPair {
301334
// IsCa::SelfSignedOnly is rejected by C8Y with "422 Unprocessable Entity"
302335
params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
303336

304-
Ok(params)
337+
Ok((params, signing_key))
305338
}
306339

307340
fn create_csr_parameters(
308341
config: &CsrTemplate,
309342
id: &str,
310343
key_kind: &KeyKind,
311-
) -> Result<CertificateParams, CertificateError> {
344+
) -> Result<(CertificateParams, SigningKeyWrapper), CertificateError> {
312345
KeyCertPair::check_identifier(id, config.max_cn_size)?;
313346
let mut distinguished_name = rcgen::DistinguishedName::new();
314347
distinguished_name.push(rcgen::DnType::CommonName, id);
@@ -321,38 +354,38 @@ impl KeyCertPair {
321354
let mut params = CertificateParams::default();
322355
params.distinguished_name = distinguished_name;
323356

324-
match key_kind {
357+
let signing_key: SigningKeyWrapper = match key_kind {
325358
KeyKind::New => {
326359
// ECDSA signing using the P-256 curves and SHA-256 hashing as per RFC 5758
327-
params.alg = &rcgen::PKCS_ECDSA_P256_SHA256;
360+
SigningKeyWrapper::Local(Zeroizing::new(KeyPair::generate_for(
361+
&rcgen::PKCS_ECDSA_P256_SHA256,
362+
)?))
328363
}
329364
KeyKind::Reuse { keypair_pem } => {
330365
// Use the same signing algorithm as the existing key
331366
// Failing to do so leads to an error telling the algorithm is not compatible
332-
let key_pair = KeyPair::from_pem(keypair_pem)?;
333-
params.alg = key_pair.algorithm();
334-
params.key_pair = Some(key_pair);
335-
}
336-
KeyKind::ReuseRemote(key_pair) => {
337-
let key_pair = key_pair.to_key_pair()?;
338-
params.alg = key_pair.algorithm();
339-
params.key_pair = Some(key_pair)
367+
SigningKeyWrapper::Local(Zeroizing::new(KeyPair::from_pem(keypair_pem)?))
340368
}
341-
}
369+
KeyKind::ReuseRemote(remote) => SigningKeyWrapper::Remote(remote.clone()),
370+
};
342371

343-
Ok(params)
372+
Ok((params, signing_key))
344373
}
345374

346375
pub fn certificate_pem_string(&self) -> Result<String, CertificateError> {
347-
Ok(self.certificate.serialize_pem()?)
376+
Ok(self.certificate.pem())
348377
}
349378

350379
pub fn private_key_pem_string(&self) -> Result<Zeroizing<String>, CertificateError> {
351-
Ok(Zeroizing::new(self.certificate.serialize_private_key_pem()))
380+
if let SigningKeyWrapper::Local(keypair) = &self.signing_key {
381+
Ok(Zeroizing::new(keypair.serialize_pem()))
382+
} else {
383+
Err(anyhow::anyhow!("Can't serialize private key PEM for remote private key").into())
384+
}
352385
}
353386

354387
pub fn certificate_signing_request_string(&self) -> Result<String, CertificateError> {
355-
Ok(self.certificate.serialize_request_pem()?)
388+
Ok(self.params.serialize_request(&self.signing_key)?.pem()?)
356389
}
357390

358391
fn check_identifier(id: &str, max_cn_size: usize) -> Result<(), CertificateError> {
@@ -555,7 +588,7 @@ mod tests {
555588
let id = "some-id";
556589
let birthdate = datetime!(2021-03-31 16:39:57 +01:00);
557590

558-
let params = KeyCertPair::create_selfsigned_certificate_parameters(
591+
let (params, signing_key) = KeyCertPair::create_selfsigned_certificate_parameters(
559592
&config,
560593
id,
561594
&KeyKind::New,
@@ -564,9 +597,11 @@ mod tests {
564597
.expect("Fail to get a certificate parameters");
565598

566599
let keypair = KeyCertPair {
567-
certificate: Zeroizing::new(
568-
Certificate::from_params(params).expect("Fail to create a certificate"),
569-
),
600+
certificate: params
601+
.self_signed(&signing_key)
602+
.expect("Fail to create a certificate"),
603+
params,
604+
signing_key,
570605
};
571606

572607
// Check the not_before date
@@ -587,7 +622,7 @@ mod tests {
587622
let id = "some-id";
588623
let birthdate = datetime!(2021-03-31 16:39:57 +01:00);
589624

590-
let params = KeyCertPair::create_selfsigned_certificate_parameters(
625+
let (params, signing_key) = KeyCertPair::create_selfsigned_certificate_parameters(
591626
&config,
592627
id,
593628
&KeyKind::New,
@@ -596,9 +631,11 @@ mod tests {
596631
.expect("Fail to get a certificate parameters");
597632

598633
let keypair = KeyCertPair {
599-
certificate: Zeroizing::new(
600-
Certificate::from_params(params).expect("Fail to create a certificate"),
601-
),
634+
certificate: params
635+
.self_signed(&signing_key)
636+
.expect("Fail to create a certificate"),
637+
params,
638+
signing_key,
602639
};
603640

604641
// Check the not_after date
@@ -613,13 +650,16 @@ mod tests {
613650
let config = CsrTemplate::default();
614651
let id = "some-id";
615652

616-
let params = KeyCertPair::create_csr_parameters(&config, id, &KeyKind::New)
653+
let (params, signing_key) = KeyCertPair::create_csr_parameters(&config, id, &KeyKind::New)
617654
.expect("Fail to get a certificate parameters");
618655

656+
let issuer = rcgen::Issuer::from_params(&params, &signing_key);
619657
let keypair = KeyCertPair {
620-
certificate: Zeroizing::new(
621-
Certificate::from_params(params).expect("Fail to create a certificate"),
622-
),
658+
certificate: params
659+
.signed_by(&signing_key, &issuer)
660+
.expect("Fail to create a certificate"),
661+
params,
662+
signing_key,
623663
};
624664

625665
// Check the subject

crates/common/download/src/download.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,6 @@ mod tests {
466466
use axum::Router;
467467
use hyper::header::AUTHORIZATION;
468468
use rustls::pki_types::pem::PemObject;
469-
use rustls::pki_types::CertificateDer;
470469
use rustls::pki_types::PrivateKeyDer;
471470
use rustls::RootCertStore;
472471
use std::io::Write;
@@ -970,8 +969,8 @@ mod tests {
970969
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
971970
let port = listener.local_addr().unwrap().port();
972971
let server_cert = rcgen::generate_simple_self_signed(["localhost".into()]).unwrap();
973-
let cert = CertificateDer::from(server_cert.serialize_der().unwrap());
974-
let key = PrivateKeyDer::from_pem_slice(server_cert.serialize_private_key_pem().as_bytes())
972+
let cert = server_cert.cert.der().clone();
973+
let key = PrivateKeyDer::from_pem_slice(server_cert.signing_key.serialize_pem().as_bytes())
975974
.unwrap();
976975
let mut accepted_certs = RootCertStore::empty();
977976
accepted_certs.add(cert.clone()).unwrap();

0 commit comments

Comments
 (0)