diff --git a/Cargo.lock b/Cargo.lock index 6409dc6..e1f531b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1047,9 +1047,9 @@ checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" [[package]] name = "x509" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9335b8ff50b6a0de184b3eeb11fdce74224e3af90ca7265012512e73fc999d1a" +checksum = "ca3cec94c3999f31341553f358ef55f65fc031291a022cd42ec0ce7219560c76" dependencies = [ "chrono", "cookie-factory", diff --git a/Cargo.toml b/Cargo.toml index d587bfc..9de6a74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ sha-1 = "0.9" sha2 = "0.9" subtle = "2" subtle-encoding = "0.5" -x509 = "0.1.2" +x509 = "0.2" x509-parser = "0.9" zeroize = "1" diff --git a/src/certificate.rs b/src/certificate.rs index 1d0bc35..4146a26 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -49,6 +49,7 @@ use sha2::{Digest, Sha256}; use std::convert::TryFrom; use std::fmt; use std::ops::DerefMut; +use x509::{der::Oid, RelativeDistinguishedName}; use x509_parser::{parse_x509_certificate, x509::SubjectPublicKeyInfo}; use zeroize::Zeroizing; @@ -337,19 +338,21 @@ impl<'a> TryFrom<&'a [u8]> for Certificate { impl Certificate { /// Creates a new self-signed certificate for the given key. Writes the resulting /// certificate to the slot before returning it. - pub fn generate_self_signed( + /// + /// `extensions` is optional; if empty, no extensions will be included. Due to the + /// need for an `O: Oid` type parameter, users who do not have any extensions should + /// use the workaround `let extensions: &[x509::Extension<'_, &[u64]>] = &[];`. + pub fn generate_self_signed( yubikey: &mut YubiKey, key: SlotId, serial: impl Into, not_after: Option>, - subject: String, + subject: &[RelativeDistinguishedName<'_>], subject_pki: PublicKeyInfo, + extensions: &[x509::Extension<'_, O>], ) -> Result { let serial = serial.into(); - // Issuer and subject are the same in self-signed certificates - let issuer = subject.clone(); - let mut tbs_cert = Buffer::new(Vec::with_capacity(CB_OBJ_MAX)); let signature_algorithm = match subject_pki.algorithm() { @@ -361,11 +364,13 @@ impl Certificate { x509::write::tbs_certificate( &serial.to_bytes(), &signature_algorithm, - &issuer, + // Issuer and subject are the same in self-signed certificates. + &subject, Utc::now(), not_after, &subject, &subject_pki, + &extensions, ), tbs_cert.deref_mut(), ) @@ -425,6 +430,15 @@ impl Certificate { ) .expect("can serialize to Vec"); + let (issuer, subject) = parse_x509_certificate(&data) + .map(|(_, cert)| { + ( + cert.tbs_certificate.issuer.to_string(), + cert.tbs_certificate.subject.to_string(), + ) + }) + .expect("We just serialized this correctly"); + let cert = Certificate { serial, issuer, diff --git a/tests/integration.rs b/tests/integration.rs index 43959b4..9c365fe 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -10,6 +10,7 @@ use rsa::{hash::Hash::SHA2_256, PaddingScheme, PublicKey}; use sha2::{Digest, Sha256}; use std::convert::TryInto; use std::{env, sync::Mutex}; +use x509::RelativeDistinguishedName; use yubikey_piv::{ certificate::{Certificate, PublicKeyInfo}, key::{self, AlgorithmId, Key, RetiredSlotId, SlotId}, @@ -132,13 +133,15 @@ fn generate_self_signed_cert(algorithm: AlgorithmId) -> Certificate { getrandom(&mut serial).unwrap(); // Generate a self-signed certificate for the new key. + let extensions: &[x509::Extension<'_, &[u64]>] = &[]; let cert_result = Certificate::generate_self_signed( &mut yubikey, slot, serial, None, - "testSubject".to_owned(), + &[RelativeDistinguishedName::common_name("testSubject")], generated, + extensions, ); assert!(cert_result.is_ok());