Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ use crate::error::{DerTypeId, Error};
use crate::public_values_eq;
use crate::signed_data::SignedData;
use crate::subject_name::{GeneralName, NameIterator, WildcardDnsNameRef};
use crate::x509::{DistributionPointName, Extension, remember_extension, set_extension_once};
use crate::x509::{
DistributionPointName, Extension, ExtensionOid, remember_extension, set_extension_once,
};

/// A parsed X509 certificate.
pub struct Cert<'a> {
Expand Down Expand Up @@ -263,25 +265,27 @@ fn remember_cert_extension<'a>(
// all policy-related stuff. We assume that the policy-related extensions
// are not marked critical.

use ExtensionOid::*;

remember_extension(extension, |id| {
let out = match id {
// id-ce-keyUsage 2.5.29.15.
15 => &mut cert.key_usage,
Standard(15) => &mut cert.key_usage,

// id-ce-subjectAltName 2.5.29.17
17 => &mut cert.subject_alt_name,
Standard(17) => &mut cert.subject_alt_name,

// id-ce-basicConstraints 2.5.29.19
19 => &mut cert.basic_constraints,
Standard(19) => &mut cert.basic_constraints,

// id-ce-nameConstraints 2.5.29.30
30 => &mut cert.name_constraints,
Standard(30) => &mut cert.name_constraints,

// id-ce-cRLDistributionPoints 2.5.29.31
31 => &mut cert.crl_distribution_points,
Standard(31) => &mut cert.crl_distribution_points,

// id-ce-extKeyUsage 2.5.29.37
37 => &mut cert.eku,
Standard(37) => &mut cert.eku,

// Unsupported extension
_ => return extension.unsupported(),
Expand All @@ -291,7 +295,7 @@ fn remember_cert_extension<'a>(
extension.value.read_all(Error::BadDer, |value| match id {
// Unlike the other extensions we remember KU is a BitString and not a Sequence. We
// read the raw bytes here and parse at the time of use.
15 => Ok(value.read_bytes_to_end()),
Standard(15) => Ok(value.read_bytes_to_end()),
// All other remembered certificate extensions are wrapped in a Sequence.
_ => der::expect_tag(value, Tag::Sequence),
})
Expand Down
20 changes: 13 additions & 7 deletions src/crl/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,12 @@ impl<'a> BorrowedCertRevocationList<'a> {
}

fn remember_extension(&mut self, extension: &Extension<'a>) -> Result<(), Error> {
use crate::x509::ExtensionOid::*;

remember_extension(extension, |id| {
match id {
// id-ce-cRLNumber 2.5.29.20 - RFC 5280 §5.2.3
20 => {
Standard(20) => {
// RFC 5280 §5.2.3:
// CRL verifiers MUST be able to handle CRLNumber values
// up to 20 octets. Conforming CRL issuers MUST NOT use CRLNumber
Expand All @@ -289,17 +291,17 @@ impl<'a> BorrowedCertRevocationList<'a> {

// id-ce-deltaCRLIndicator 2.5.29.27 - RFC 5280 §5.2.4
// We explicitly do not support delta CRLs.
27 => Err(Error::UnsupportedDeltaCrl),
Standard(27) => Err(Error::UnsupportedDeltaCrl),

// id-ce-issuingDistributionPoint 2.5.29.28 - RFC 5280 §5.2.4
// We recognize the extension and retain its value for use.
28 => {
Standard(28) => {
set_extension_once(&mut self.issuing_distribution_point, || Ok(extension.value))
}

// id-ce-authorityKeyIdentifier 2.5.29.35 - RFC 5280 §5.2.1, §4.2.1.1
// We recognize the extension but don't retain its value for use.
35 => Ok(()),
Standard(35) => Ok(()),

// Unsupported extension
_ => extension.unsupported(),
Expand Down Expand Up @@ -758,13 +760,17 @@ impl<'a> BorrowedRevokedCert<'a> {
}

fn remember_extension(&mut self, extension: &Extension<'a>) -> Result<(), Error> {
use crate::x509::ExtensionOid::*;

remember_extension(extension, |id| {
match id {
// id-ce-cRLReasons 2.5.29.21 - RFC 5280 §5.3.1.
21 => set_extension_once(&mut self.reason_code, || der::read_all(extension.value)),
Standard(21) => {
set_extension_once(&mut self.reason_code, || der::read_all(extension.value))
}

// id-ce-invalidityDate 2.5.29.24 - RFC 5280 §5.3.2.
24 => set_extension_once(&mut self.invalidity_date, || {
Standard(24) => set_extension_once(&mut self.invalidity_date, || {
extension.value.read_all(Error::BadDer, UnixTime::from_der)
}),

Expand All @@ -775,7 +781,7 @@ impl<'a> BorrowedRevokedCert<'a> {
// extension.
// We choose not to support indirect CRLs and so turn this into a more specific
// error rather than simply letting it fail as an unsupported critical extension.
29 => Err(Error::UnsupportedIndirectCrl),
Standard(29) => Err(Error::UnsupportedIndirectCrl),

// Unsupported extension
_ => extension.unsupported(),
Expand Down
42 changes: 29 additions & 13 deletions src/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,12 @@ pub(crate) fn set_extension_once<T>(

pub(crate) fn remember_extension(
extension: &Extension<'_>,
mut handler: impl FnMut(u8) -> Result<(), Error>,
mut handler: impl FnMut(ExtensionOid) -> Result<(), Error>,
) -> Result<(), Error> {
// ISO arc for standard certificate and CRL extensions.
// https://www.rfc-editor.org/rfc/rfc5280#appendix-A.2
static ID_CE: [u8; 2] = oid![2, 5, 29];

if extension.id.len() != ID_CE.len() + 1
|| !extension.id.as_slice_less_safe().starts_with(&ID_CE)
{
return extension.unsupported();
match ExtensionOid::lookup(extension.id) {
Some(oid) => handler(oid),
None => extension.unsupported(),
}

// safety: we verify len is non-zero and has the correct prefix above.
let last_octet = *extension.id.as_slice_less_safe().last().unwrap();
handler(last_octet)
}

/// A certificate revocation list (CRL) distribution point name, describing a source of
Expand Down Expand Up @@ -109,3 +100,28 @@ impl<'a> FromDer<'a> for DistributionPointName<'a> {

const TYPE_ID: DerTypeId = DerTypeId::DistributionPointName;
}

/// Simplified representation of supported extension OIDs.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum ExtensionOid {
/// Extensions whose OID is under `id-ce` arc.
Standard(u8),
}

impl ExtensionOid {
fn lookup(id: untrusted::Input<'_>) -> Option<Self> {
match id.as_slice_less_safe() {
[first, second, x] if [*first, *second] == ID_CE => Some(Self::Standard(*x)),
_ => None,
}
}
}

/// ISO arc for standard certificate and CRL extensions.
///
/// ```text
/// id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29}
/// ```
///
/// <https://www.rfc-editor.org/rfc/rfc5280#appendix-A.2>
const ID_CE: [u8; 2] = oid!(2, 5, 29);