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
//! GeneralNames as defined in [RFC 5280 Section 4.2.1.6].
use super::{EdiPartyName, OtherName};
use crate::name::Name;
use der::asn1::{Ia5String, ObjectIdentifier, OctetString};
use der::{Choice, ValueOrd};
/// GeneralNames as defined in [RFC 5280 Section 4.2.1.6].
///
/// ```text
/// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
/// ```
///
/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6
pub type GeneralNames = alloc::vec::Vec<GeneralName>;
/// GeneralName as defined in [RFC 5280 Section 4.2.1.6].
///
/// ```text
/// GeneralName ::= CHOICE {
/// otherName [0] OtherName,
/// rfc822Name [1] IA5String,
/// dNSName [2] IA5String,
/// x400Address [3] ORAddress,
/// directoryName [4] Name,
/// ediPartyName [5] EDIPartyName,
/// uniformResourceIdentifier [6] IA5String,
/// iPAddress [7] OCTET STRING,
/// registeredID [8] OBJECT IDENTIFIER
/// }
/// ```
///
/// This implementation does not currently support the `x400Address` choice.
///
/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6
#[derive(Clone, Debug, Eq, PartialEq, Choice, ValueOrd)]
#[allow(missing_docs)]
pub enum GeneralName {
#[asn1(context_specific = "0", tag_mode = "IMPLICIT", constructed = "true")]
OtherName(OtherName),
#[asn1(context_specific = "1", tag_mode = "IMPLICIT")]
Rfc822Name(Ia5String),
#[asn1(context_specific = "2", tag_mode = "IMPLICIT")]
DnsName(Ia5String),
#[asn1(context_specific = "4", tag_mode = "EXPLICIT", constructed = "true")]
DirectoryName(Name),
#[asn1(context_specific = "5", tag_mode = "IMPLICIT", constructed = "true")]
EdiPartyName(EdiPartyName),
#[asn1(context_specific = "6", tag_mode = "IMPLICIT")]
UniformResourceIdentifier(Ia5String),
#[asn1(context_specific = "7", tag_mode = "IMPLICIT")]
IpAddress(OctetString),
#[asn1(context_specific = "8", tag_mode = "IMPLICIT")]
RegisteredId(ObjectIdentifier),
}
#[cfg(feature = "std")]
impl From<std::net::IpAddr> for GeneralName {
fn from(ip: std::net::IpAddr) -> Self {
// Safety: this is unfailable here, OctetString will issue an error if you go
// over 256MiB, here the buffer is at most 16 bytes (ipv6). The two `expect`s
// below are safe.
let buf = match ip {
std::net::IpAddr::V4(v) => {
let value = v.octets();
OctetString::new(&value[..])
.expect("OctetString is not expected to fail with a 4 bytes long buffer")
}
std::net::IpAddr::V6(v) => {
let value = v.octets();
OctetString::new(&value[..])
.expect("OctetString is not expected to fail with a 16 bytes long buffer")
}
};
GeneralName::IpAddress(buf)
}
}
#[cfg(all(feature = "std", test))]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use der::Encode;
#[test]
fn test_convert() {
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
assert_eq!(
GeneralName::from(localhost_v4).to_der().unwrap(),
&[135, 4, 127, 0, 0, 1][..]
);
assert_eq!(
GeneralName::from(localhost_v6).to_der().unwrap(),
&[135, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1][..]
);
}
}