Improve self-signed certificates (#207)

Adds support for:
- A hierarchical SubjectName field.
- Certificate extensions.
This commit is contained in:
str4d
2021-01-12 04:49:15 +13:00
committed by GitHub
parent 90bc878b21
commit 24b035008c
4 changed files with 27 additions and 10 deletions
Generated
+2 -2
View File
@@ -1047,9 +1047,9 @@ checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]] [[package]]
name = "x509" name = "x509"
version = "0.1.2" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9335b8ff50b6a0de184b3eeb11fdce74224e3af90ca7265012512e73fc999d1a" checksum = "ca3cec94c3999f31341553f358ef55f65fc031291a022cd42ec0ce7219560c76"
dependencies = [ dependencies = [
"chrono", "chrono",
"cookie-factory", "cookie-factory",
+1 -1
View File
@@ -44,7 +44,7 @@ sha-1 = "0.9"
sha2 = "0.9" sha2 = "0.9"
subtle = "2" subtle = "2"
subtle-encoding = "0.5" subtle-encoding = "0.5"
x509 = "0.1.2" x509 = "0.2"
x509-parser = "0.9" x509-parser = "0.9"
zeroize = "1" zeroize = "1"
+20 -6
View File
@@ -49,6 +49,7 @@ use sha2::{Digest, Sha256};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::ops::DerefMut; use std::ops::DerefMut;
use x509::{der::Oid, RelativeDistinguishedName};
use x509_parser::{parse_x509_certificate, x509::SubjectPublicKeyInfo}; use x509_parser::{parse_x509_certificate, x509::SubjectPublicKeyInfo};
use zeroize::Zeroizing; use zeroize::Zeroizing;
@@ -337,19 +338,21 @@ impl<'a> TryFrom<&'a [u8]> for Certificate {
impl Certificate { impl Certificate {
/// Creates a new self-signed certificate for the given key. Writes the resulting /// Creates a new self-signed certificate for the given key. Writes the resulting
/// certificate to the slot before returning it. /// 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<O: Oid>(
yubikey: &mut YubiKey, yubikey: &mut YubiKey,
key: SlotId, key: SlotId,
serial: impl Into<Serial>, serial: impl Into<Serial>,
not_after: Option<DateTime<Utc>>, not_after: Option<DateTime<Utc>>,
subject: String, subject: &[RelativeDistinguishedName<'_>],
subject_pki: PublicKeyInfo, subject_pki: PublicKeyInfo,
extensions: &[x509::Extension<'_, O>],
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let serial = serial.into(); 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 mut tbs_cert = Buffer::new(Vec::with_capacity(CB_OBJ_MAX));
let signature_algorithm = match subject_pki.algorithm() { let signature_algorithm = match subject_pki.algorithm() {
@@ -361,11 +364,13 @@ impl Certificate {
x509::write::tbs_certificate( x509::write::tbs_certificate(
&serial.to_bytes(), &serial.to_bytes(),
&signature_algorithm, &signature_algorithm,
&issuer, // Issuer and subject are the same in self-signed certificates.
&subject,
Utc::now(), Utc::now(),
not_after, not_after,
&subject, &subject,
&subject_pki, &subject_pki,
&extensions,
), ),
tbs_cert.deref_mut(), tbs_cert.deref_mut(),
) )
@@ -425,6 +430,15 @@ impl Certificate {
) )
.expect("can serialize to Vec"); .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 { let cert = Certificate {
serial, serial,
issuer, issuer,
+4 -1
View File
@@ -10,6 +10,7 @@ use rsa::{hash::Hash::SHA2_256, PaddingScheme, PublicKey};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::convert::TryInto; use std::convert::TryInto;
use std::{env, sync::Mutex}; use std::{env, sync::Mutex};
use x509::RelativeDistinguishedName;
use yubikey_piv::{ use yubikey_piv::{
certificate::{Certificate, PublicKeyInfo}, certificate::{Certificate, PublicKeyInfo},
key::{self, AlgorithmId, Key, RetiredSlotId, SlotId}, key::{self, AlgorithmId, Key, RetiredSlotId, SlotId},
@@ -132,13 +133,15 @@ fn generate_self_signed_cert(algorithm: AlgorithmId) -> Certificate {
getrandom(&mut serial).unwrap(); getrandom(&mut serial).unwrap();
// Generate a self-signed certificate for the new key. // Generate a self-signed certificate for the new key.
let extensions: &[x509::Extension<'_, &[u64]>] = &[];
let cert_result = Certificate::generate_self_signed( let cert_result = Certificate::generate_self_signed(
&mut yubikey, &mut yubikey,
slot, slot,
serial, serial,
None, None,
"testSubject".to_owned(), &[RelativeDistinguishedName::common_name("testSubject")],
generated, generated,
extensions,
); );
assert!(cert_result.is_ok()); assert!(cert_result.is_ok());