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]]
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",
+1 -1
View File
@@ -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"
+20 -6
View File
@@ -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<O: Oid>(
yubikey: &mut YubiKey,
key: SlotId,
serial: impl Into<Serial>,
not_after: Option<DateTime<Utc>>,
subject: String,
subject: &[RelativeDistinguishedName<'_>],
subject_pki: PublicKeyInfo,
extensions: &[x509::Extension<'_, O>],
) -> Result<Self, Error> {
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,
+4 -1
View File
@@ -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());