x509_parser/extensions/
generalname.rs1use crate::error::{X509Error, X509Result};
2use crate::prelude::format_serial;
3use crate::x509::X509Name;
4use asn1_rs::{Any, CheckDerConstraints, Class, Error, FromDer, Oid, Sequence, Tag};
5use core::convert::TryFrom;
6use nom::combinator::all_consuming;
7use nom::{Err, IResult};
8use std::fmt;
9
10#[derive(Clone, Debug, PartialEq)]
11pub enum GeneralName<'a> {
16 OtherName(Oid<'a>, &'a [u8]),
17 RFC822Name(&'a str),
19 DNSName(&'a str),
21 X400Address(Any<'a>),
23 DirectoryName(X509Name<'a>),
26 EDIPartyName(Any<'a>),
28 URI(&'a str),
30 IPAddress(&'a [u8]),
32 RegisteredID(Oid<'a>),
33 Invalid(Tag, &'a [u8]),
35}
36
37impl<'a> TryFrom<Any<'a>> for GeneralName<'a> {
38 type Error = Error;
39
40 fn try_from(any: Any<'a>) -> Result<Self, Self::Error> {
41 any.class().assert_eq(Class::ContextSpecific)?;
42
43 let name = match parse_generalname_entry(any.clone()) {
44 Ok(name) => name,
45 Err(_) => GeneralName::Invalid(any.tag(), any.data),
46 };
47 Ok(name)
48 }
49}
50
51fn parse_generalname_entry(
52 any: Any<'_>,
53) -> Result<GeneralName<'_>, <GeneralName<'_> as TryFrom<Any<'_>>>::Error> {
54 Ok(match any.tag().0 {
55 0 => {
56 let (rest, oid) = Oid::from_der(any.data)?;
58 GeneralName::OtherName(oid, rest)
59 }
60 1 => GeneralName::RFC822Name(ia5str(any)?),
61 2 => GeneralName::DNSName(ia5str(any)?),
62 3 => {
63 GeneralName::X400Address(any)
65 }
66 4 => {
67 let (_, name) = all_consuming(X509Name::from_der)(any.data)
69 .or(Err(Error::Unsupported)) ?;
71 GeneralName::DirectoryName(name)
72 }
73 5 => {
74 GeneralName::EDIPartyName(any)
76 }
77 6 => GeneralName::URI(ia5str(any)?),
78 7 => {
79 GeneralName::IPAddress(any.data)
81 }
82 8 => {
83 let oid = Oid::new(any.data.into());
84 GeneralName::RegisteredID(oid)
85 }
86 _ => return Err(Error::unexpected_tag(None, any.tag())),
87 })
88}
89
90impl CheckDerConstraints for GeneralName<'_> {
91 fn check_constraints(any: &Any) -> asn1_rs::Result<()> {
92 Sequence::check_constraints(any)
93 }
94}
95
96impl<'a> FromDer<'a, X509Error> for GeneralName<'a> {
97 fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
98 parse_generalname(i).map_err(Err::convert)
99 }
100}
101
102impl fmt::Display for GeneralName<'_> {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 match self {
105 GeneralName::OtherName(oid, _) => write!(f, "OtherName({oid}, [...])"),
106 GeneralName::RFC822Name(s) => write!(f, "RFC822Name({s})"),
107 GeneralName::DNSName(s) => write!(f, "DNSName({s})"),
108 GeneralName::X400Address(_) => write!(f, "X400Address(<unparsed>)"),
109 GeneralName::DirectoryName(dn) => write!(f, "DirectoryName({dn})"),
110 GeneralName::EDIPartyName(_) => write!(f, "EDIPartyName(<unparsed>)"),
111 GeneralName::URI(s) => write!(f, "URI({s})"),
112 GeneralName::IPAddress(b) => write!(f, "IPAddress({})", format_serial(b)),
113 GeneralName::RegisteredID(oid) => write!(f, "RegisteredID({oid})"),
114 GeneralName::Invalid(tag, b) => {
115 write!(f, "Invalid(tag={}, data={})", tag, format_serial(b))
116 }
117 }
118 }
119}
120
121fn ia5str(any: Any<'_>) -> Result<&str, Err<Error>> {
122 std::str::from_utf8(any.data).map_err(|_| Err::Failure(Error::BerValueError))
125}
126
127pub(crate) fn parse_generalname(i: &[u8]) -> IResult<&[u8], GeneralName<'_>, Error> {
128 let (rest, any) = Any::from_der(i)?;
129 let gn = GeneralName::try_from(any)?;
130 Ok((rest, gn))
131}