/
generalname.rs
127 lines (123 loc) · 4.85 KB
/
generalname.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use super::UnparsedObject;
use crate::error::{X509Error, X509Result};
use crate::prelude::format_serial;
use crate::x509::X509Name;
use asn1_rs::{Any, CheckDerConstraints, Class, Error, FromDer, Oid, Sequence};
use core::convert::TryFrom;
use nom::combinator::all_consuming;
use nom::{Err, IResult};
use std::fmt;
#[derive(Clone, Debug, PartialEq)]
/// Represents a GeneralName as defined in RFC5280. There
/// is no support X.400 addresses and EDIPartyName.
///
/// String formats are not validated.
pub enum GeneralName<'a> {
OtherName(Oid<'a>, &'a [u8]),
/// More or less an e-mail, the format is not checked.
RFC822Name(&'a str),
/// A hostname, format is not checked.
DNSName(&'a str),
/// X400Address,
X400Address(UnparsedObject<'a>),
/// 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
EDIPartyName(UnparsedObject<'a>),
/// An uniform resource identifier. The format is not checked.
URI(&'a str),
/// An ip address, provided as encoded.
IPAddress(&'a [u8]),
RegisteredID(Oid<'a>),
}
impl<'a> FromDer<'a, X509Error> for GeneralName<'a> {
fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
parse_generalname(i).map_err(Err::convert)
}
}
impl<'a> fmt::Display for GeneralName<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GeneralName::OtherName(oid, _) => write!(f, "OtherName({}, [...])", oid),
GeneralName::RFC822Name(s) => write!(f, "RFC822Name({})", s),
GeneralName::DNSName(s) => write!(f, "DNSName({})", s),
GeneralName::X400Address(_) => write!(f, "X400Address(<unparsed>)"),
GeneralName::DirectoryName(dn) => write!(f, "DirectoryName({})", dn),
GeneralName::EDIPartyName(_) => write!(f, "EDIPartyName(<unparsed>)"),
GeneralName::URI(s) => write!(f, "URI({})", s),
GeneralName::IPAddress(b) => write!(f, "IPAddress({})", format_serial(b)),
GeneralName::RegisteredID(oid) => write!(f, "RegisteredID({})", oid),
}
}
}
pub(crate) fn parse_generalname<'a>(i: &'a [u8]) -> IResult<&'a [u8], GeneralName, BerError> {
let (rest, hdr) = verify(der_read_element_header, |hdr| hdr.is_contextspecific())(i)?;
let len = hdr.length().definite()?;
if len > rest.len() {
let needed = Needed::new(len - rest.len());
return Err(nom::Err::Failure(BerError::Incomplete(needed)));
}
fn ia5str<'a>(i: &'a [u8], hdr: Header) -> Result<&'a str, Err<BerError>> {
// Relax constraints from RFC here: we are expecting an IA5String, but many certificates
// are using unicode characters
der_read_element_content_as(i, Tag::Utf8String, hdr.length(), hdr.is_constructed(), 1)?
.1
.as_slice()
.and_then(|s| std::str::from_utf8(s).map_err(|_| BerError::BerValueError))
.map_err(nom::Err::Failure)
}
let name = match hdr.tag().0 {
0 => {
// otherName SEQUENCE { OID, [0] explicit any defined by oid }
let (any, oid) = Oid::from_der(rest)?;
GeneralName::OtherName(oid, any)
}
1 => GeneralName::RFC822Name(ia5str(rest, hdr)?),
2 => GeneralName::DNSName(ia5str(rest, hdr)?),
3 => {
// XXX Not yet implemented
let (_, data) = take(len)(rest)?;
let obj = UnparsedObject { header: hdr, data };
GeneralName::X400Address(obj)
}
4 => {
// directoryName, name
let (_, name) = all_consuming(X509Name::from_der)(&rest[..len])
.or(Err(BerError::Unsupported)) // XXX remove me
?;
GeneralName::DirectoryName(name)
}
5 => {
// XXX Not yet implemented
let (_, data) = take(len)(rest)?;
let obj = UnparsedObject { header: hdr, data };
GeneralName::EDIPartyName(obj)
}
6 => GeneralName::URI(ia5str(rest, hdr)?),
7 => {
// IPAddress, OctetString
let ip = der_read_element_content_as(
rest,
Tag::OctetString,
hdr.length(),
hdr.is_constructed(),
1,
)?
.1
.as_slice()
.map_err(nom::Err::Failure)?;
GeneralName::IPAddress(ip)
}
8 => {
let oid =
der_read_element_content_as(rest, Tag::Oid, hdr.length(), hdr.is_constructed(), 1)?
.1
.as_oid_val()
.map_err(nom::Err::Failure)?;
GeneralName::RegisteredID(oid)
}
_ => return Err(Err::Failure(BerError::unexpected_tag(None, hdr.tag()))),
};
Ok((&rest[len..], name))
}