/rust/registry/src/index.crates.io-1949cf8c6b5b557f/x509-parser-0.16.0/src/extensions/generalname.rs
Line | Count | Source |
1 | | use crate::error::{X509Error, X509Result}; |
2 | | use crate::prelude::format_serial; |
3 | | use crate::x509::X509Name; |
4 | | use asn1_rs::{Any, CheckDerConstraints, Class, Error, FromDer, Oid, Sequence}; |
5 | | use core::convert::TryFrom; |
6 | | use nom::combinator::all_consuming; |
7 | | use nom::{Err, IResult}; |
8 | | use std::fmt; |
9 | | |
10 | | #[derive(Clone, Debug, PartialEq)] |
11 | | /// Represents a GeneralName as defined in RFC5280. There |
12 | | /// is no support X.400 addresses and EDIPartyName. |
13 | | /// |
14 | | /// String formats are not validated. |
15 | | pub enum GeneralName<'a> { |
16 | | OtherName(Oid<'a>, &'a [u8]), |
17 | | /// More or less an e-mail, the format is not checked. |
18 | | RFC822Name(&'a str), |
19 | | /// A hostname, format is not checked. |
20 | | DNSName(&'a str), |
21 | | /// X400Address, |
22 | | X400Address(Any<'a>), |
23 | | /// RFC5280 defines several string types, we always try to parse as utf-8 |
24 | | /// which is more or less a superset of the string types. |
25 | | DirectoryName(X509Name<'a>), |
26 | | /// EDIPartyName |
27 | | EDIPartyName(Any<'a>), |
28 | | /// An uniform resource identifier. The format is not checked. |
29 | | URI(&'a str), |
30 | | /// An ip address, provided as encoded. |
31 | | IPAddress(&'a [u8]), |
32 | | RegisteredID(Oid<'a>), |
33 | | } |
34 | | |
35 | | impl<'a> TryFrom<Any<'a>> for GeneralName<'a> { |
36 | | type Error = Error; |
37 | | |
38 | 26.5k | fn try_from(any: Any<'a>) -> Result<Self, Self::Error> { |
39 | 26.5k | any.class().assert_eq(Class::ContextSpecific)?; |
40 | 26.5k | fn ia5str(any: Any) -> Result<&str, Err<Error>> { |
41 | | // Relax constraints from RFC here: we are expecting an IA5String, but many certificates |
42 | | // are using unicode characters |
43 | 26.5k | std::str::from_utf8(any.data).map_err(|_| nom::Err::Failure(Error::BerValueError)) |
44 | 26.5k | } |
45 | 26.5k | let name = match any.tag().0 { |
46 | | 0 => { |
47 | | // otherName SEQUENCE { OID, [0] explicit any defined by oid } |
48 | 0 | let (rest, oid) = Oid::from_der(any.data)?; |
49 | 0 | GeneralName::OtherName(oid, rest) |
50 | | } |
51 | 0 | 1 => GeneralName::RFC822Name(ia5str(any)?), |
52 | 19.6k | 2 => GeneralName::DNSName(ia5str(any)?), |
53 | | 3 => { |
54 | | // XXX Not yet implemented |
55 | 0 | GeneralName::X400Address(any) |
56 | | } |
57 | | 4 => { |
58 | | // directoryName, name |
59 | 61 | let (_, name) = all_consuming(X509Name::from_der)(any.data) |
60 | 61 | .or(Err(Error::Unsupported)) // XXX remove me |
61 | 0 | ?; |
62 | 61 | GeneralName::DirectoryName(name) |
63 | | } |
64 | | 5 => { |
65 | | // XXX Not yet implemented |
66 | 0 | GeneralName::EDIPartyName(any) |
67 | | } |
68 | 6.83k | 6 => GeneralName::URI(ia5str(any)?), |
69 | | 7 => { |
70 | | // IPAddress, OctetString |
71 | 0 | GeneralName::IPAddress(any.data) |
72 | | } |
73 | | 8 => { |
74 | 0 | let oid = Oid::new(any.data.into()); |
75 | 0 | GeneralName::RegisteredID(oid) |
76 | | } |
77 | 0 | _ => return Err(Error::unexpected_tag(None, any.tag())), |
78 | | }; |
79 | 26.5k | Ok(name) |
80 | 26.5k | } |
81 | | } |
82 | | |
83 | | impl CheckDerConstraints for GeneralName<'_> { |
84 | 0 | fn check_constraints(any: &Any) -> asn1_rs::Result<()> { |
85 | 0 | Sequence::check_constraints(any) |
86 | 0 | } |
87 | | } |
88 | | |
89 | | impl<'a> FromDer<'a, X509Error> for GeneralName<'a> { |
90 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
91 | 0 | parse_generalname(i).map_err(Err::convert) |
92 | 0 | } |
93 | | } |
94 | | |
95 | | impl<'a> fmt::Display for GeneralName<'a> { |
96 | 54 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
97 | 54 | match self { |
98 | 0 | GeneralName::OtherName(oid, _) => write!(f, "OtherName({}, [...])", oid), |
99 | 0 | GeneralName::RFC822Name(s) => write!(f, "RFC822Name({})", s), |
100 | 0 | GeneralName::DNSName(s) => write!(f, "DNSName({})", s), |
101 | 0 | GeneralName::X400Address(_) => write!(f, "X400Address(<unparsed>)"), |
102 | 54 | GeneralName::DirectoryName(dn) => write!(f, "DirectoryName({})", dn), |
103 | 0 | GeneralName::EDIPartyName(_) => write!(f, "EDIPartyName(<unparsed>)"), |
104 | 0 | GeneralName::URI(s) => write!(f, "URI({})", s), |
105 | 0 | GeneralName::IPAddress(b) => write!(f, "IPAddress({})", format_serial(b)), |
106 | 0 | GeneralName::RegisteredID(oid) => write!(f, "RegisteredID({})", oid), |
107 | | } |
108 | 54 | } |
109 | | } |
110 | | |
111 | 31.5k | pub(crate) fn parse_generalname(i: &[u8]) -> IResult<&[u8], GeneralName, Error> { |
112 | 31.5k | let (rest, any) = Any::from_der(i)?; |
113 | 26.5k | let gn = GeneralName::try_from(any)?; |
114 | 26.5k | Ok((rest, gn)) |
115 | 31.5k | } |