Skip to content

Commit

Permalink
Add support for reading and writing V1 and V2 TbsCertificate versions…
Browse files Browse the repository at this point in the history
…, in addition to V3
  • Loading branch information
Pagten committed Dec 2, 2022
1 parent ee20d14 commit 7772f32
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 70 deletions.
3 changes: 2 additions & 1 deletion examples/fakecert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
extern crate pkix;

use pkix::pem::{der_to_pem, PEM_CERTIFICATE};
use pkix::x509::TBS_CERTIFICATE_V3;

#[path="../tests/fakes.rs"]
pub mod fakes;

fn main() {
let cert = fakes::cert_der(fakes::random_printable_string);
let cert = fakes::cert_der(fakes::random_printable_string, TBS_CERTIFICATE_V3);

println!("{}", der_to_pem(&cert, PEM_CERTIFICATE));
}
40 changes: 32 additions & 8 deletions src/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl<T: BERDecodable, A: SignatureAlgorithm + BERDecodable, S: BERDecodable> BER

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct TbsCertificate<S: Integer, A: SignatureAlgorithm, K> {
// version: v3
pub version: u8,
pub serial: S,
pub sigalg: A,
pub issuer: Name,
Expand All @@ -76,13 +76,17 @@ impl<S: Integer, A: SignatureAlgorithm, K> TbsCertificate<S, A, K> {
}
}

const TBS_CERTIFICATE_V3: u8 = 2;
pub const TBS_CERTIFICATE_V1: u8 = 0;
pub const TBS_CERTIFICATE_V2: u8 = 1;
pub const TBS_CERTIFICATE_V3: u8 = 2;

impl<S: DerWrite + Integer, A: DerWrite + SignatureAlgorithm, K: DerWrite> DerWrite
for TbsCertificate<S, A, K> {
fn write(&self, writer: DERWriter) {
writer.write_sequence(|writer| {
writer.next().write_tagged(Tag::context(0), |w| TBS_CERTIFICATE_V3.write(w));
if self.version != TBS_CERTIFICATE_V1 { // default value
writer.next().write_tagged(Tag::context(0), |w| self.version.write(w));
}
self.serial.write(writer.next());
self.sigalg.write(writer.next());
self.issuer.write(writer.next());
Expand All @@ -108,10 +112,11 @@ impl<S: DerWrite + Integer, A: DerWrite + SignatureAlgorithm, K: DerWrite> DerWr
impl<S: BERDecodable + Integer, A: BERDecodable + SignatureAlgorithm, K: BERDecodable> BERDecodable for TbsCertificate<S, A, K> {
fn decode_ber<'a, 'b>(reader: BERReader<'a, 'b>) -> ASN1Result<Self> {
reader.read_sequence(|r| {
let version = r.next().read_tagged(Tag::context(0), |r| r.read_u8())?;
if version != TBS_CERTIFICATE_V3 {
return Err(ASN1Error::new(ASN1ErrorKind::Invalid));
}
let version = r.read_optional(|r| r.read_tagged(Tag::context(0), |r| r.read_u8()))?.unwrap_or(0);
match version {
TBS_CERTIFICATE_V1 | TBS_CERTIFICATE_V2 | TBS_CERTIFICATE_V3 => { /* known version */ }
_ => { return Err(ASN1Error::new(ASN1ErrorKind::Invalid)); }
};
let serial = S::decode_ber(r.next())?;
let sigalg = A::decode_ber(r.next())?;
let issuer = Name::decode_ber(r.next())?;
Expand All @@ -123,6 +128,9 @@ impl<S: BERDecodable + Integer, A: BERDecodable + SignatureAlgorithm, K: BERDeco
let subject = Name::decode_ber(r.next())?;
let spki = K::decode_ber(r.next())?;
let extensions = r.read_optional(|r| {
if version != TBS_CERTIFICATE_V3 {
return Err(ASN1Error::new(ASN1ErrorKind::Invalid));
}
r.read_tagged(Tag::context(3), |r| {
r.read_sequence(|r| {
let mut extensions = Vec::<Extension>::new();
Expand All @@ -143,7 +151,7 @@ impl<S: BERDecodable + Integer, A: BERDecodable + SignatureAlgorithm, K: BERDeco
})
})?.unwrap_or(vec![]);

Ok(TbsCertificate { serial, sigalg, issuer, validity_notbefore, validity_notafter,
Ok(TbsCertificate { version, serial, sigalg, issuer, validity_notbefore, validity_notafter,
subject, spki, extensions })
})
}
Expand Down Expand Up @@ -283,4 +291,20 @@ mod tests {
test_encode_decode(&subject_alt_name, der);
test_encode_decode(&issuer_alt_name, der);
}

#[test]
fn parse_v1_cert() {
let der = include_bytes!("../tests/data/v1_cert.der");
let cert = yasna::parse_der(der, |r| GenericCertificate::decode_ber(r)).unwrap();
assert_eq!(cert.tbscert.version, TBS_CERTIFICATE_V1);
assert_eq!(yasna::construct_der(|w| cert.write(w)), der);
}

#[test]
fn parse_v3_cert() {
let der = include_bytes!("../tests/data/v3_cert.der");
let cert = yasna::parse_der(der, |r| GenericCertificate::decode_ber(r)).unwrap();
assert_eq!(cert.tbscert.version, TBS_CERTIFICATE_V3);
assert_eq!(yasna::construct_der(|w| cert.write(w)), der);
}
}
Binary file added tests/data/v1_cert.der
Binary file not shown.
Binary file added tests/data/v3_cert.der
Binary file not shown.
181 changes: 120 additions & 61 deletions tests/fakes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use self::yasna::tags::{TAG_UTF8STRING, TAG_PRINTABLESTRING};
use self::pkix::types::{DateTime, DerSequence, Attribute, Extension, RsaPkcs15, Sha256};
use self::pkix::{DerWrite, oid};
use self::pkix::pkcs10::{CertificationRequest, CertificationRequestInfo};
use self::pkix::x509::{Certificate, TbsCertificate};
use self::pkix::x509::{Certificate, TbsCertificate, TBS_CERTIFICATE_V3};
use self::pkix::cms::*;
use self::pkix::algorithms::*;

Expand Down Expand Up @@ -64,37 +64,37 @@ pub fn csr(get_random_printable_string: fn(usize) -> Vec<u8>)
}));

CertificationRequest {
reqinfo: CertificationRequestInfo {
subject:
vec![(oid::description.clone(),
TaggedDerValue::from_tag_and_bytes(TAG_UTF8STRING, b"Known keys only".to_vec())),
(oid::dnQualifier.clone(),
TaggedDerValue::from_tag_and_bytes(TAG_PRINTABLESTRING, get_random_printable_string(42)))].into(),
spki: yasna::construct_der(|w|
w.write_sequence(|writer| {
writer.next().write_sequence(|writer| {
oid_rsa_encryption.write(writer.next());
writer.next().write_null();
});
BitVec::from_bytes(&rsapubkey).write(writer.next());
})
).into(),
attributes: vec![Attribute {
oid: oid::extensionRequest.clone(),
value: vec![exts.into()],
}],
},
sigalg: RsaPkcs15(Sha256),
sig: BitVec::from_elem(8, false),
}
reqinfo: CertificationRequestInfo {
subject:
vec![(oid::description.clone(),
TaggedDerValue::from_tag_and_bytes(TAG_UTF8STRING, b"Known keys only".to_vec())),
(oid::dnQualifier.clone(),
TaggedDerValue::from_tag_and_bytes(TAG_PRINTABLESTRING, get_random_printable_string(42)))].into(),
spki: yasna::construct_der(|w|
w.write_sequence(|writer| {
writer.next().write_sequence(|writer| {
oid_rsa_encryption.write(writer.next());
writer.next().write_null();
});
BitVec::from_bytes(&rsapubkey).write(writer.next());
})
).into(),
attributes: vec![Attribute {
oid: oid::extensionRequest.clone(),
value: vec![exts.into()],
}],
},
sigalg: RsaPkcs15(Sha256),
sig: BitVec::from_elem(8, false),
}
}

pub fn csr_der(get_random_printable_string: fn(usize) -> Vec<u8>) -> Vec<u8> {
yasna::construct_der(|w| csr(get_random_printable_string).write(w))
}


pub fn cert(get_random_printable_string: fn(usize) -> Vec<u8>)
pub fn cert(get_random_printable_string: fn(usize) -> Vec<u8>, version: u8)
-> Certificate<TbsCertificate<i64, RsaPkcs15<Sha256>, DerSequence<'static>>, RsaPkcs15<Sha256>, BitVec>
{
let oid_rsa_encryption = ObjectIdentifier::from(vec![1, 2, 840, 113549, 1, 1, 1]);
Expand All @@ -108,42 +108,49 @@ pub fn cert(get_random_printable_string: fn(usize) -> Vec<u8>)
})
});

let extensions = if version == TBS_CERTIFICATE_V3 {
vec![Extension {
oid: oid::basicConstraints.clone(),
critical: true,
value: vec![0x30, 0],
}]
} else {
vec![]
};

Certificate {
tbscert: TbsCertificate {
serial: 0,
sigalg: RsaPkcs15(Sha256),
issuer:
vec![(oid::dnQualifier.clone(),
TaggedDerValue::from_tag_and_bytes(TAG_PRINTABLESTRING, get_random_printable_string(42)))].into(),
validity_notbefore: DateTime::new(1970, 1, 1, 0, 0, 0).unwrap(),
validity_notafter: DateTime::new(1970, 1, 1, 0, 0, 0).unwrap(),
subject:
vec![(oid::description.clone(),
TaggedDerValue::from_tag_and_bytes(TAG_UTF8STRING, b"Known keys only".to_vec())),
(oid::dnQualifier.clone(),
TaggedDerValue::from_tag_and_bytes(TAG_PRINTABLESTRING, get_random_printable_string(42)))].into(),
spki: yasna::construct_der(|w|
w.write_sequence(|writer| {
writer.next().write_sequence(|writer| {
oid_rsa_encryption.write(writer.next());
writer.next().write_null();
});
BitVec::from_bytes(&rsapubkey).write(writer.next());
})
).into(),
extensions: vec![Extension {
oid: oid::basicConstraints.clone(),
critical: true,
value: vec![0x30, 0],
}],
},
tbscert: TbsCertificate {
version,
serial: 0,
sigalg: RsaPkcs15(Sha256),
sig: BitVec::from_elem(8, false),
}
issuer:
vec![(oid::dnQualifier.clone(),
TaggedDerValue::from_tag_and_bytes(TAG_PRINTABLESTRING, get_random_printable_string(42)))].into(),
validity_notbefore: DateTime::new(1970, 1, 1, 0, 0, 0).unwrap(),
validity_notafter: DateTime::new(1970, 1, 1, 0, 0, 0).unwrap(),
subject:
vec![(oid::description.clone(),
TaggedDerValue::from_tag_and_bytes(TAG_UTF8STRING, b"Known keys only".to_vec())),
(oid::dnQualifier.clone(),
TaggedDerValue::from_tag_and_bytes(TAG_PRINTABLESTRING, get_random_printable_string(42)))].into(),
spki: yasna::construct_der(|w|
w.write_sequence(|writer| {
writer.next().write_sequence(|writer| {
oid_rsa_encryption.write(writer.next());
writer.next().write_null();
});
BitVec::from_bytes(&rsapubkey).write(writer.next());
})
).into(),
extensions,
},
sigalg: RsaPkcs15(Sha256),
sig: BitVec::from_elem(8, false),
}
}

pub fn cert_der(get_random_printable_string: fn(usize) -> Vec<u8>) -> Vec<u8> {
yasna::construct_der(|w| cert(get_random_printable_string).write(w))
pub fn cert_der(get_random_printable_string: fn(usize) -> Vec<u8>, version: u8) -> Vec<u8> {
yasna::construct_der(|w| cert(get_random_printable_string, version).write(w))
}

pub fn enveloped_data_v2() -> EnvelopedDataV2 {
Expand Down Expand Up @@ -171,7 +178,7 @@ pub fn fake_callback(_: &[u8]) -> Result<Vec<u8>, ()> {
pub fn signed_data_v3(get_random_printable_string: fn(usize) -> Vec<u8>) -> SignedDataV3 {
let enveloped_data: EnvelopedData = enveloped_data_v2().into();
let encapsulated_content: EncapsulatedContentInfo = enveloped_data.into();
let cert = cert(get_random_printable_string);
let cert = cert(get_random_printable_string, TBS_CERTIFICATE_V3);
let cert = yasna::construct_der(|w| cert.write(w));
let signer_key_id = vec![0; 20];

Expand Down Expand Up @@ -230,9 +237,61 @@ fn fake_csr() {
assert_eq!(yasna::construct_der(|w| csr.write(w)), der);
assert_eq!(yasna::parse_der(&der, |r| CertificationRequest::decode_ber(r)).unwrap(), csr);
}
#[test]
fn fake_cert_v1() {
use yasna::BERDecodable;

let der = vec![
0x30, 0x81, 0xfc, 0x30, 0x81, 0xe6, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x35, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04,
0x2e, 0x13, 0x2a, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65,
0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73,
0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x37, 0x30,
0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31,
0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4f, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
0x55, 0x04, 0x0d, 0x0c, 0x0f, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x20, 0x6f,
0x6e, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x2e, 0x13, 0x2a, 0x74, 0x65, 0x73,
0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74,
0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74,
0x65, 0x73, 0x74, 0x74, 0x65, 0x30, 0x2a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x19, 0x00, 0x30, 0x16, 0x02, 0x11, 0x00, 0xa6, 0xe0, 0xd7, 0xc4,
0xc4, 0xbf, 0xcf, 0x69, 0x63, 0x60, 0xca, 0x77, 0x3d, 0x00, 0xa2, 0xb1, 0x02, 0x01, 0x03, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x02, 0x00, 0x00];

let cert = cert(deterministic_printable_string, pkix::x509::TBS_CERTIFICATE_V1);
assert_eq!(yasna::construct_der(|w| cert.write(w)), der);
assert_eq!(yasna::parse_der(&der, |r| Certificate::decode_ber(r)).unwrap(), cert);
}

#[test]
fn fake_cert_v2() {
use yasna::BERDecodable;

let der = vec![
0x30, 0x82, 0x01, 0x01, 0x30, 0x81, 0xeb, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x35, 0x31, 0x33,
0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x2e, 0x13, 0x2a, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74,
0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74,
0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65,
0x30, 0x1e, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4f,
0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0d, 0x0c, 0x0f, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x20,
0x6b, 0x65, 0x79, 0x73, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04,
0x2e, 0x13, 0x2a, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65,
0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73,
0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x30, 0x2a, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x19, 0x00, 0x30, 0x16, 0x02,
0x11, 0x00, 0xa6, 0xe0, 0xd7, 0xc4, 0xc4, 0xbf, 0xcf, 0x69, 0x63, 0x60, 0xca, 0x77, 0x3d, 0x00, 0xa2,
0xb1, 0x02, 0x01, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
0x05, 0x00, 0x03, 0x02, 0x00, 0x00];

let cert = cert(deterministic_printable_string, pkix::x509::TBS_CERTIFICATE_V2);
assert_eq!(yasna::construct_der(|w| cert.write(w)), der);
assert_eq!(yasna::parse_der(&der, |r| Certificate::decode_ber(r)).unwrap(), cert);
}

#[test]
fn fake_cert() {
fn fake_cert_v3() {
use yasna::BERDecodable;

let der = vec![
Expand All @@ -254,7 +313,7 @@ fn fake_cert() {
0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x0b, 0x05, 0x00, 0x03, 0x02, 0x00, 0x00];

let cert = cert(deterministic_printable_string);
let cert = cert(deterministic_printable_string, TBS_CERTIFICATE_V3);
assert_eq!(yasna::construct_der(|w| cert.write(w)), der);
assert_eq!(yasna::parse_der(&der, |r| Certificate::decode_ber(r)).unwrap(), cert);
}
Expand All @@ -263,7 +322,7 @@ fn fake_cert() {
fn no_extensions() {
use yasna::BERDecodable;

let mut cert = cert(deterministic_printable_string);
let mut cert = cert(deterministic_printable_string, TBS_CERTIFICATE_V3);
cert.tbscert.extensions = vec![];

let der = yasna::construct_der(|w| cert.write(w));
Expand Down

0 comments on commit 7772f32

Please sign in to comment.