Skip to content

Commit

Permalink
Parse v1 implicit certs for trust_anchor_util
Browse files Browse the repository at this point in the history
This is needed to make the previous netflix integration test work.
We fall back to parsing as v1 only if v3 fails, and even then don't
discard the v3 error.
  • Loading branch information
ctz committed Jun 8, 2016
1 parent c79b35d commit 4763aac
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 2 deletions.
72 changes: 72 additions & 0 deletions src/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,78 @@ pub struct Cert<'a> {
pub subject_alt_name: Option<untrusted::Input<'a>>,
}

pub fn parse_root_cert_v1<'a>(cert_der: untrusted::Input<'a>)
-> Result<Cert<'a>, Error> {
// We don't return a cert with a valid signed_data, because there's
// not much reason to verify a root.
let empty_slice = &cert_der.as_slice_less_safe()[0..0];
let invalid_signed_data = SignedData {
data: Input::new(empty_slice).unwrap(),
algorithm: Input::new(empty_slice).unwrap(),
signature: Input::new(empty_slice).unwrap()
};

/* The top level is a:
*
* Certificate ::= SEQUENCE {
* certificateInfo CertificateInfo,
* signatureAlgorithm AlgorithmIdentifier,
* signature BIT STRING }
*
* CertificateInfo ::= SEQUENCE {
* version [0] Version DEFAULT v1988,
* serialNumber CertificateSerialNumber,
* signature AlgorithmIdentifier,
* issuer Name,
* validity Validity,
* subject Name,
* subjectPublicKeyInfo SubjectPublicKeyInfo }
*/

read_all(cert_der, Error::BadDER, |cert_der| {
der::nested(cert_der, der::Tag::Sequence, Error::BadDER,
|cert_inf| {
let cert = der::nested(cert_inf, der::Tag::Sequence, Error::BadDER,
|inf| {
// serial number should not appear in v1
try!(certificate_serial_number(inf));
try!(der::expect_tag_and_get_input(inf, der::Tag::Sequence)); // sigalg
let issuer =
try!(der::expect_tag_and_get_input(inf, der::Tag::Sequence));
let validity =
try!(der::expect_tag_and_get_input(inf, der::Tag::Sequence));
let subject =
try!(der::expect_tag_and_get_input(inf, der::Tag::Sequence));
let spki =
try!(der::expect_tag_and_get_input(inf, der::Tag::Sequence));

let cert: Cert<'a> = Cert {
ee_or_ca: EndEntityOrCA::EndEntity,

signed_data: invalid_signed_data,

issuer: issuer,
validity: validity,
subject: subject,
spki: spki,

basic_constraints: None,
eku: None,
name_constraints: None,
subject_alt_name: None,
};

Ok(cert)
});

// read and discard signatureAlgorithm + signature
try!(der::expect_tag_and_get_input(cert_inf, der::Tag::Sequence));
try!(der::expect_tag_and_get_input(cert_inf, der::Tag::BitString));
cert
})
})
}

pub fn parse_cert<'a>(cert_der: untrusted::Input<'a>,
ee_or_ca: EndEntityOrCA<'a>) -> Result<Cert<'a>, Error> {
let (tbs, signed_data) = try!(cert_der.read_all(Error::BadDER, |cert_der| {
Expand Down
6 changes: 4 additions & 2 deletions src/trust_anchor_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

use std;
use super::{Error, TrustAnchor};
use super::cert::{EndEntityOrCA, parse_cert};
use super::cert::{EndEntityOrCA, parse_cert, parse_root_cert_v1};
use untrusted;

/// Interprets the given DER-encoded certificate as a `TrustAnchor`. The
Expand All @@ -28,7 +28,9 @@ pub fn cert_der_as_trust_anchor<'a>(cert_der: untrusted::Input<'a>)
// XXX: `EndEntityOrCA::EndEntity` is used instead of `EndEntityOrCA::CA`
// because we don't have a refernce to a child cert, which is needed for
// `EndEntityOrCA::CA`. For this purpose, it doesn't matter.
let cert = try!(parse_cert(cert_der, EndEntityOrCA::EndEntity));
let cert = try!(parse_cert(cert_der, EndEntityOrCA::EndEntity).
or_else(|err| parse_root_cert_v1(cert_der)
.or(Err(err))));
Ok(TrustAnchor {
subject: cert.subject.as_slice_less_safe(),
spki: cert.spki.as_slice_less_safe(),
Expand Down

0 comments on commit 4763aac

Please sign in to comment.