Skip to content

Commit c2bcdbf

Browse files
iamjpottsest31
authored andcommitted
Parse an IP address into SANType from a x509 GeneralName.
1 parent e8a127b commit c2bcdbf

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/target
22
**/*.rs.bk
33
certs/
4+
.idea

src/lib.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ use std::fmt;
4949
use std::convert::TryFrom;
5050
use std::error::Error;
5151
use std::net::IpAddr;
52+
#[cfg(feature = "x509-parser")]
53+
use std::net::{Ipv4Addr, Ipv6Addr};
5254
use std::str::FromStr;
5355
use std::hash::{Hash, Hasher};
5456

@@ -159,6 +161,19 @@ pub enum SanType {
159161
IpAddress(IpAddr),
160162
}
161163

164+
#[cfg(feature = "x509-parser")]
165+
fn ip_addr_from_octets(octets: &[u8]) -> Result<IpAddr, RcgenError> {
166+
if let Ok(ipv6_octets) = <&[u8; 16]>::try_from(octets) {
167+
Ok(Ipv6Addr::from(*ipv6_octets).into())
168+
}
169+
else if let Ok(ipv4_octets) = <&[u8; 4]>::try_from(octets) {
170+
Ok(Ipv4Addr::from(*ipv4_octets).into())
171+
}
172+
else {
173+
Err(RcgenError::InvalidIpAddressOctetLength(octets.len()))
174+
}
175+
}
176+
162177
impl SanType {
163178
#[cfg(feature = "x509-parser")]
164179
fn try_from_general(name :&x509_parser::extensions::GeneralName<'_>) -> Result<Self, RcgenError> {
@@ -172,6 +187,9 @@ impl SanType {
172187
x509_parser::extensions::GeneralName::URI(name) => {
173188
SanType::URI((*name).into())
174189
}
190+
x509_parser::extensions::GeneralName::IPAddress(octets) => {
191+
SanType::IpAddress(ip_addr_from_octets(octets)?)
192+
}
175193
_ => return Err(RcgenError::InvalidNameType),
176194
})
177195
}
@@ -1585,6 +1603,8 @@ pub enum RcgenError {
15851603
#[cfg(feature = "x509-parser")]
15861604
/// Invalid subject alternative name type
15871605
InvalidNameType,
1606+
/// An IP address was provided as a byte array, but the byte array was an invalid length.
1607+
InvalidIpAddressOctetLength(usize),
15881608
/// There is no support for generating
15891609
/// keys for the given algorithm
15901610
KeyGenerationUnavailable,
@@ -1621,6 +1641,7 @@ impl fmt::Display for RcgenError {
16211641
CouldNotParseKeyPair => write!(f, "Could not parse key pair")?,
16221642
#[cfg(feature = "x509-parser")]
16231643
InvalidNameType => write!(f, "Invalid subject alternative name type")?,
1644+
InvalidIpAddressOctetLength(actual) => write!(f, "Invalid IP address octet length of {actual} bytes")?,
16241645
KeyGenerationUnavailable => write!(f, "There is no support for generating \
16251646
keys for the given algorithm")?,
16261647
UnsupportedSignatureAlgorithm => write!(f, "The requested signature algorithm \
@@ -2249,4 +2270,74 @@ mod tests {
22492270
}
22502271
}
22512272
}
2273+
2274+
#[cfg(feature = "x509-parser")]
2275+
mod test_ip_address_from_octets {
2276+
use std::net::IpAddr;
2277+
use super::super::ip_addr_from_octets;
2278+
use super::super::RcgenError;
2279+
2280+
#[test]
2281+
fn ipv4() {
2282+
let octets = [10, 20, 30, 40];
2283+
2284+
let actual = ip_addr_from_octets(&octets)
2285+
.unwrap();
2286+
2287+
assert_eq!(IpAddr::from(octets), actual)
2288+
}
2289+
2290+
#[test]
2291+
fn ipv6() {
2292+
let octets = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
2293+
2294+
let actual = ip_addr_from_octets(&octets)
2295+
.unwrap();
2296+
2297+
assert_eq!(IpAddr::from(octets), actual)
2298+
}
2299+
2300+
#[test]
2301+
fn mismatch() {
2302+
let incorrect: Vec<u8> = (0..10).into_iter().collect();
2303+
let actual = ip_addr_from_octets(&incorrect)
2304+
.unwrap_err();
2305+
2306+
assert_eq!(RcgenError::InvalidIpAddressOctetLength(10), actual);
2307+
}
2308+
2309+
#[test]
2310+
fn none() {
2311+
let actual = ip_addr_from_octets(&[])
2312+
.unwrap_err();
2313+
2314+
assert_eq!(RcgenError::InvalidIpAddressOctetLength(0), actual);
2315+
}
2316+
2317+
#[test]
2318+
fn too_many() {
2319+
let incorrect: Vec<u8> = (0..20).into_iter().collect();
2320+
let actual = ip_addr_from_octets(&incorrect)
2321+
.unwrap_err();
2322+
2323+
assert_eq!(RcgenError::InvalidIpAddressOctetLength(20), actual);
2324+
}
2325+
}
2326+
2327+
#[cfg(feature = "x509-parser")]
2328+
mod test_san_type_from_general_name {
2329+
use std::net::IpAddr;
2330+
use x509_parser::extensions::GeneralName;
2331+
use crate::SanType;
2332+
2333+
#[test]
2334+
fn with_ipv4() {
2335+
let octets = [1, 2, 3, 4];
2336+
let value = GeneralName::IPAddress(&octets);
2337+
let actual = SanType::try_from_general(&value)
2338+
.unwrap();
2339+
2340+
assert_eq!(SanType::IpAddress(IpAddr::from(octets)), actual);
2341+
}
2342+
}
22522343
}

0 commit comments

Comments
 (0)