Skip to content

Commit

Permalink
Convert all structs to Cow (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
chifflier committed May 5, 2021
1 parent d387316 commit d0663a4
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 64 deletions.
2 changes: 1 addition & 1 deletion examples/print-cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn format_oid(oid: &Oid) -> String {
fn print_x509_extension(oid: &Oid, ext: &X509Extension) {
print!(" {}: ", format_oid(oid));
print!(" Critical={}", ext.critical);
print!(" len={}", ext.value.len());
print!(" len={}", ext.value().len());
println!();
match ext.parsed_extension() {
ParsedExtension::BasicConstraints(bc) => {
Expand Down
4 changes: 2 additions & 2 deletions examples/print-crl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn print_authority_key_identifier(aki: &AuthorityKeyIdentifier, level: usize) {
if aki.authority_cert_issuer.is_some() {
unimplemented!();
}
if let Some(serial) = aki.authority_cert_serial {
if let Some(serial) = &aki.authority_cert_serial {
let mut s = serial
.iter()
.fold(String::with_capacity(3 * serial.len()), |a, b| {
Expand Down Expand Up @@ -76,7 +76,7 @@ fn print_x509_extension(oid: &Oid, ext: &X509Extension, level: usize) {
x => {
print!("{:indent$}{}:", "", format_oid(oid), indent = level);
print!(" Critical={}", ext.critical);
print!(" len={}", ext.value.len());
print!(" len={}", ext.value().len());
println!();
println!(" {:indent$}{:?}", "", x, indent = level);
}
Expand Down
13 changes: 7 additions & 6 deletions src/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use der_parser::oid::Oid;
use der_parser::*;
use nom::Offset;
use oid_registry::*;
use std::borrow::Cow;
use std::collections::HashMap;

/// An X.509 v3 Certificate.
Expand Down Expand Up @@ -179,7 +180,7 @@ impl<'a> X509Certificate<'a> {
signature::UnparsedPublicKey::new(verification_alg, &spki.subject_public_key.data);
// verify signature
let sig = &self.signature_value.data;
key.verify(self.tbs_certificate.raw, &sig)
key.verify(&self.tbs_certificate.raw, &sig)
.or(Err(X509Error::SignatureVerificationError))
}
}
Expand Down Expand Up @@ -218,8 +219,8 @@ pub struct TbsCertificate<'a> {
pub issuer_uid: Option<UniqueIdentifier<'a>>,
pub subject_uid: Option<UniqueIdentifier<'a>>,
pub extensions: HashMap<Oid<'a>, X509Extension<'a>>,
pub(crate) raw: &'a [u8],
pub(crate) raw_serial: &'a [u8],
pub(crate) raw: Cow<'a, [u8]>,
pub(crate) raw_serial: Cow<'a, [u8]>,
}

impl<'a> TbsCertificate<'a> {
Expand Down Expand Up @@ -267,8 +268,8 @@ impl<'a> TbsCertificate<'a> {
subject_uid,
extensions,

raw: &start_i[..len],
raw_serial: serial.0,
raw: Cow::Borrowed(&start_i[..len]),
raw_serial: Cow::Borrowed(serial.0),
};
Ok((i, tbs))
})(i)
Expand Down Expand Up @@ -352,7 +353,7 @@ impl<'a> TbsCertificate<'a> {

/// Get the raw bytes of the certificate serial number
pub fn raw_serial(&self) -> &[u8] {
self.raw_serial
&self.raw_serial
}

/// Get a formatted string of the certificate serial number, separated by ':'
Expand Down
7 changes: 4 additions & 3 deletions src/certification_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use der_parser::*;
use nom::Offset;
#[cfg(feature = "verify")]
use oid_registry::*;
use std::borrow::Cow;
use std::collections::HashMap;

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -100,7 +101,7 @@ impl<'a> X509CertificationRequest<'a> {
signature::UnparsedPublicKey::new(verification_alg, &spki.subject_public_key.data);
// verify signature
let sig = &self.signature_value.data;
key.verify(self.certification_request_info.raw, &sig)
key.verify(&self.certification_request_info.raw, &sig)
.or(Err(X509Error::SignatureVerificationError))
}
}
Expand All @@ -111,7 +112,7 @@ pub struct X509CertificationRequestInfo<'a> {
pub subject: X509Name<'a>,
pub subject_pki: SubjectPublicKeyInfo<'a>,
pub attributes: HashMap<Oid<'a>, X509CriAttribute<'a>>,
pub raw: &'a [u8],
pub raw: Cow<'a, [u8]>,
}

impl<'a> X509CertificationRequestInfo<'a> {
Expand Down Expand Up @@ -145,7 +146,7 @@ impl<'a> X509CertificationRequestInfo<'a> {
subject,
subject_pki,
attributes,
raw: &start_i[..len],
raw: Cow::Borrowed(&start_i[..len]),
};
Ok((i, tbs))
})(i)
Expand Down
9 changes: 7 additions & 2 deletions src/cri_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ use der_parser::oid::Oid;
use nom::combinator::map_res;
use nom::Err;
use oid_registry::*;
use std::borrow::Cow;
use std::collections::HashMap;

/// Attributes for Certification Request
#[derive(Debug, PartialEq)]
pub struct X509CriAttribute<'a> {
pub oid: Oid<'a>,
pub value: &'a [u8],
pub(crate) value: Cow<'a, [u8]>,
pub(crate) parsed_attribute: ParsedCriAttribute<'a>,
}

Expand All @@ -34,13 +35,17 @@ impl<'a> X509CriAttribute<'a> {
let (i, parsed_attribute) = crate::cri_attributes::parser::parse_attribute(i, &oid)?;
let ext = X509CriAttribute {
oid,
value: &value_start[..value_start.len() - i.len()],
value: Cow::Borrowed(&value_start[..value_start.len() - i.len()]),
parsed_attribute,
};
Ok((i, ext))
})(i)
.map_err(|_| X509Error::InvalidAttributes.into())
}

pub fn value(&'a self) -> &'a [u8] {
&self.value
}
}

/// Section 3.1 of rfc 5272
Expand Down
69 changes: 43 additions & 26 deletions src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use nom::combinator::{all_consuming, complete, map_opt, map_res, opt};
use nom::multi::{many0, many1};
use nom::{exact, Err};
use oid_registry::*;
use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;

Expand All @@ -24,7 +25,7 @@ pub struct X509Extension<'a> {
/// An extension includes the boolean critical, with a default value of FALSE.
pub critical: bool,
/// Raw content of the extension
pub value: &'a [u8],
pub(crate) value: Cow<'a, [u8]>,
pub(crate) parsed_extension: ParsedExtension<'a>,
}

Expand Down Expand Up @@ -92,7 +93,7 @@ impl<'a> X509Extension<'a> {
let ext = X509Extension {
oid,
critical,
value,
value: Cow::Borrowed(value),
parsed_extension,
};
Ok((i, ext))
Expand All @@ -109,11 +110,16 @@ impl<'a> X509Extension<'a> {
X509Extension {
oid,
critical,
value,
value: Cow::Borrowed(value),
parsed_extension,
}
}

/// Return the value bytes
pub fn value(&'a self) -> &'a [u8] {
&self.value
}

/// Return the extension type or `UnsupportedExtension` if the extension is not implemented.
pub fn parsed_extension(&self) -> &ParsedExtension<'a> {
&self.parsed_extension
Expand Down Expand Up @@ -163,12 +169,12 @@ pub enum ParsedExtension<'a> {
pub struct AuthorityKeyIdentifier<'a> {
pub key_identifier: Option<KeyIdentifier<'a>>,
pub authority_cert_issuer: Option<Vec<GeneralName<'a>>>,
pub authority_cert_serial: Option<&'a [u8]>,
pub authority_cert_serial: Option<Cow<'a, [u8]>>,
}

#[derive(Debug, PartialEq)]
pub struct CertificatePolicies<'a> {
pub policies: HashMap<Oid<'a>, &'a [u8]>,
pub policies: HashMap<Oid<'a>, Cow<'a, [u8]>>,
}

/// Identifies whether the subject of the certificate is a CA, and the max validation depth.
Expand All @@ -179,7 +185,7 @@ pub struct BasicConstraints {
}

#[derive(Debug, PartialEq)]
pub struct KeyIdentifier<'a>(pub &'a [u8]);
pub struct KeyIdentifier<'a>(pub Cow<'a, [u8]>);

#[derive(Debug, PartialEq)]
pub struct KeyUsage {
Expand Down Expand Up @@ -355,20 +361,20 @@ pub struct SubjectAlternativeName<'a> {
///
/// String formats are not validated.
pub enum GeneralName<'a> {
OtherName(Oid<'a>, &'a [u8]),
OtherName(Oid<'a>, Cow<'a, [u8]>),
/// More or less an e-mail, the format is not checked.
RFC822Name(&'a str),
RFC822Name(Cow<'a, str>),
/// A hostname, format is not checked.
DNSName(&'a str),
DNSName(Cow<'a, str>),
// X400Address,
/// RFC5280 defines several string types, we always try to parse as utf-8
/// which is more or less a superset of the string types.
DirectoryName(X509Name<'a>),
// EDIPartyName { name_assigner: Option<&'a str>, party_name: &'a str },
/// An uniform resource identifier. The format is not checked.
URI(&'a str),
URI(Cow<'a, str>),
/// An ip address, provided as encoded.
IPAddress(&'a [u8]),
IPAddress(Cow<'a, [u8]>),
RegisteredID(Oid<'a>),
}

Expand Down Expand Up @@ -552,19 +558,20 @@ pub(crate) mod parser {
if len > rest.len() {
return Err(nom::Err::Failure(BerError::ObjectTooShort));
}
fn ia5str<'a>(i: &'a [u8], hdr: DerObjectHeader) -> Result<&'a str, Err<BerError>> {
fn ia5str<'a>(i: &'a [u8], hdr: DerObjectHeader) -> Result<Cow<'a, str>, Err<BerError>> {
der_read_element_content_as(i, DerTag::Ia5String, hdr.len, hdr.is_constructed(), 0)?
.1
.into_bytes()
.and_then(|s| std::str::from_utf8(s).map_err(|_| BerError::BerValueError))
.map(Cow::Borrowed)
.map_err(nom::Err::Failure)
}
let name = match hdr.tag.0 {
0 => {
// otherName SEQUENCE { OID, [0] explicit any defined by oid }
let (any, oid) = parse_der_oid(rest)?;
let oid = oid.as_oid_val().map_err(nom::Err::Failure)?;
GeneralName::OtherName(oid, any)
GeneralName::OtherName(oid, Cow::Borrowed(any))
}
1 => GeneralName::RFC822Name(ia5str(rest, hdr)?),
2 => GeneralName::DNSName(ia5str(rest, hdr)?),
Expand All @@ -590,7 +597,7 @@ pub(crate) mod parser {
.1
.into_bytes()
.map_err(nom::Err::Failure)?;
GeneralName::IPAddress(ip)
GeneralName::IPAddress(Cow::Borrowed(ip))
}
8 => {
let oid = der_read_element_content_as(
Expand Down Expand Up @@ -756,7 +763,7 @@ pub(crate) mod parser {
_hdr: DerObjectHeader<'_>,
) -> IResult<&'a [u8], AuthorityKeyIdentifier<'a>, BerError> {
let (i, key_identifier) = opt(complete(parse_der_tagged_implicit_g(0, |d, _, _| {
Ok((&[], KeyIdentifier(d)))
Ok((&[], KeyIdentifier(Cow::Borrowed(d))))
})))(i)?;
let (i, authority_cert_issuer) =
opt(complete(parse_der_tagged_implicit_g(1, |d, _, _| {
Expand All @@ -766,7 +773,8 @@ pub(crate) mod parser {
2,
parse_der_content(DerTag::Integer),
)))(i)?;
let authority_cert_serial = authority_cert_serial.and_then(|o| o.into_bytes().ok());
let authority_cert_serial =
authority_cert_serial.and_then(|o| o.into_bytes().map(Cow::Borrowed).ok());
let aki = AuthorityKeyIdentifier {
key_identifier,
authority_cert_issuer,
Expand Down Expand Up @@ -804,7 +812,7 @@ pub(crate) mod parser {
.content
.into_bytes()
.or(Err(Err::Error(BerError::BerTypeError)))?;
let ki = KeyIdentifier(id);
let ki = KeyIdentifier(Cow::Borrowed(id));
let ret = ParsedExtension::SubjectKeyIdentifier(ki);
Ok((rest, ret))
}
Expand Down Expand Up @@ -855,11 +863,12 @@ pub(crate) mod parser {
//
// PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
fn parse_certificatepolicies(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> {
fn parse_policy_information(i: &[u8]) -> IResult<&[u8], (Oid, &[u8]), BerError> {
type LocalPolicyInfo<'a> = (Oid<'a>, Cow<'a, [u8]>);
fn parse_policy_information(i: &[u8]) -> IResult<&[u8], LocalPolicyInfo, BerError> {
parse_der_sequence_defined_g(|content, _| {
let (qualifier_set, oid) =
map_res(parse_der_oid, |x: DerObject| x.as_oid_val())(content)?;
Ok((&[], (oid, qualifier_set)))
Ok((&[], (oid, Cow::Borrowed(qualifier_set))))
})(i)
}
let (ret, mut policy_list) = parse_der_sequence_of_v(parse_policy_information)(i)?;
Expand Down Expand Up @@ -1024,11 +1033,14 @@ mod tests {
);
{
let alt_names = &tbs.subject_alternative_name().unwrap().1.general_names;
assert_eq!(alt_names[0], GeneralName::RFC822Name("foo@example.com"));
assert_eq!(alt_names[1], GeneralName::URI("http://my.url.here/"));
assert_eq!(
alt_names[0],
GeneralName::RFC822Name("foo@example.com".into())
);
assert_eq!(alt_names[1], GeneralName::URI("http://my.url.here/".into()));
assert_eq!(
alt_names[2],
GeneralName::IPAddress([192, 168, 7, 1].as_ref())
GeneralName::IPAddress(Cow::Borrowed(&[192, 168, 7, 1]))
);
assert_eq!(
format!(
Expand All @@ -1040,11 +1052,14 @@ mod tests {
),
"C=UK, O=My Organization, OU=My Unit, CN=My Name"
);
assert_eq!(alt_names[4], GeneralName::DNSName("localhost"));
assert_eq!(alt_names[4], GeneralName::DNSName("localhost".into()));
assert_eq!(alt_names[5], GeneralName::RegisteredID(oid!(1.2.90 .0)));
assert_eq!(
alt_names[6],
GeneralName::OtherName(oid!(1.2.3 .4), b"\xA0\x17\x0C\x15some other identifier")
GeneralName::OtherName(
oid!(1.2.3 .4),
Cow::Borrowed(b"\xA0\x17\x0C\x15some other identifier")
)
);
}

Expand All @@ -1055,10 +1070,12 @@ mod tests {
name_constraints.excluded_subtrees,
Some(vec![
GeneralSubtree {
base: GeneralName::IPAddress([192, 168, 0, 0, 255, 255, 0, 0].as_ref())
base: GeneralName::IPAddress(Cow::Borrowed(&[
192, 168, 0, 0, 255, 255, 0, 0
]))
},
GeneralSubtree {
base: GeneralName::RFC822Name("foo.com")
base: GeneralName::RFC822Name("foo.com".into())
},
])
);
Expand Down

0 comments on commit d0663a4

Please sign in to comment.