Skip to content

Commit 525dcbb

Browse files
nomickthillux
authored andcommitted
IP address range parsing
1 parent c160383 commit 525dcbb

File tree

3 files changed

+287
-19
lines changed

3 files changed

+287
-19
lines changed

openssl-sys/src/handwritten/x509_sbgp.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,155 @@ pub struct _ASIdentifiers {
3333
pub rdi: *mut ASIdentifierChoice,
3434
}
3535

36+
#[repr(C)]
37+
pub struct IPAddressRange {
38+
pub min: *mut ASN1_BIT_STRING,
39+
pub max: *mut ASN1_BIT_STRING,
40+
}
41+
42+
#[repr(C)]
43+
pub struct _IPAddressOrRange {
44+
pub type_: c_int,
45+
pub u: IPAddressOrRange_st_anon_union,
46+
}
47+
#[repr(C)]
48+
pub union IPAddressOrRange_st_anon_union {
49+
pub addressPrefix: *mut ASN1_BIT_STRING,
50+
pub addressRange: *mut IPAddressRange,
51+
}
52+
53+
stack!(stack_st_IPAddressOrRange);
54+
type IPAddressOrRanges = stack_st_IPAddressOrRange;
55+
56+
#[repr(C)]
57+
pub struct IPAddressChoice {
58+
pub type_: c_int,
59+
pub addressesOrRanges: *mut IPAddressOrRanges,
60+
}
61+
62+
#[repr(C)]
63+
pub struct _IPAddressFamily {
64+
pub addressFamily: *mut ASN1_OCTET_STRING,
65+
pub ipAddressChoice: *mut IPAddressChoice,
66+
}
67+
68+
stack!(stack_st_IPAddressFamily);
69+
type IPAddrBlocks = stack_st_IPAddressFamily;
70+
3671
extern "C" {
3772
pub fn ASIdentifiers_free(asi: *mut _ASIdentifiers);
3873
pub fn ASIdOrRange_free(asi: *mut _ASIdOrRange);
74+
pub fn IPAddressFamily_free(asi: *mut _IPAddressFamily);
75+
pub fn IPAddressOrRange_free(asi: *mut _IPAddressOrRange);
76+
}
77+
78+
pub fn X509v3_addr_get_afi(f: *mut _IPAddressFamily) -> c_int {
79+
unsafe {
80+
if f.is_null() {
81+
0
82+
} else {
83+
let d = (*f).addressFamily as *mut ASN1_STRING;
84+
if d.is_null() || ASN1_STRING_length(d) < 2 || ASN1_STRING_get0_data(d).is_null() {
85+
0
86+
} else {
87+
let raw = ASN1_STRING_get0_data(d);
88+
((*raw.offset(0) as i32) << 8) | *raw.offset(1) as i32
89+
}
90+
}
91+
}
92+
}
93+
94+
fn length_from_afi(afi: c_int) -> isize {
95+
match afi {
96+
IANA_AFI_IPV4 => 4,
97+
IANA_AFI_IPV6 => 16,
98+
_ => 0,
99+
}
100+
}
101+
102+
struct ASN1_STRING_internal {
103+
length: c_int,
104+
type_: c_int,
105+
data: *mut u8,
106+
/*
107+
* The value of the following field depends on the type being held. It
108+
* is mostly being used for BIT_STRING so if the input data has a
109+
* non-zero 'unused bits' value, it will be handled correctly
110+
*/
111+
flags: c_int,
112+
}
113+
/*
114+
* Expand the bitstring form of an address into a raw byte array.
115+
* At the moment this is coded for simplicity, not speed.
116+
*/
117+
fn addr_expand(addr: *mut u8, bs: *const ASN1_BIT_STRING, length: isize, fill: u8) -> bool {
118+
unsafe {
119+
let str = bs as *mut ASN1_STRING;
120+
let str_len = ASN1_STRING_length(str);
121+
if str_len < 0 || str_len as isize > length {
122+
return false;
123+
}
124+
125+
if str_len > 0 {
126+
// copy bytes
127+
let d = ASN1_STRING_get0_data(str);
128+
for i in 0..(str_len as isize) {
129+
*addr.offset(i) = *d.offset(i);
130+
}
131+
132+
let internal_str = bs as *mut ASN1_STRING_internal;
133+
if ((*internal_str).flags & 7) != 0 {
134+
let mask = 0xFF >> (8 - ((*internal_str).flags & 7));
135+
let val = if fill == 0 {
136+
*d.offset(str_len as isize - 1) & !mask
137+
} else {
138+
*d.offset(str_len as isize - 1) | mask
139+
};
140+
*addr.offset(str_len as isize - 1) = val;
141+
}
142+
}
143+
144+
// fill up bytes
145+
for i in (str_len as isize)..(length as isize) {
146+
*addr.offset(i) = fill;
147+
}
148+
}
149+
150+
true
151+
}
152+
153+
/*
154+
* Extract min and max values from an IPAddressOrRange.
155+
*/
156+
fn extract_min_max(aor: *mut _IPAddressOrRange, min: *mut u8, max: *mut u8, length: isize) -> bool {
157+
unsafe {
158+
match (*aor).type_ {
159+
IPAddressOrRange_addressPrefix => {
160+
return addr_expand(min, (*aor).u.addressPrefix, length, 0x00)
161+
&& addr_expand(max, (*aor).u.addressPrefix, length, 0xFF)
162+
}
163+
IPAddressOrRange_addressRange => {
164+
return addr_expand(min, (*(*aor).u.addressRange).min, length, 0x00)
165+
&& addr_expand(max, (*(*aor).u.addressRange).max, length, 0xFF)
166+
}
167+
_ => false,
168+
}
169+
}
170+
}
171+
172+
pub fn X509v3_addr_get_range(
173+
aor: *mut _IPAddressOrRange,
174+
afi: c_int,
175+
min: *mut u8,
176+
max: *mut u8,
177+
length: isize,
178+
) -> isize {
179+
let afi_length = length_from_afi(afi);
180+
if aor.is_null() || min.is_null() || max.is_null() || afi_length == 0 || length < afi_length {
181+
return 0;
182+
}
183+
if !extract_min_max(aor, min, max, afi_length) {
184+
return 0;
185+
}
186+
afi_length
39187
}

openssl-sys/src/x509_sbgp.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,12 @@ pub const ASIdOrRange_range: c_int = 1;
77

88
pub const ASIdentifierChoice_inherit: c_int = 0;
99
pub const ASIdentifierChoice_asIdsOrRanges: c_int = 1;
10+
11+
pub const IPAddressOrRange_addressPrefix: c_int = 0;
12+
pub const IPAddressOrRange_addressRange: c_int = 1;
13+
14+
pub const IPAddressChoice_inherit: c_int = 0;
15+
pub const IPAddressChoice_addressesOrRanges: c_int = 1;
16+
17+
pub const IANA_AFI_IPV4: c_int = 1;
18+
pub const IANA_AFI_IPV6: c_int = 2;

openssl/src/x509/sbgp.rs

Lines changed: 130 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1+
use std::mem::MaybeUninit;
2+
13
use ffi::{
24
ASIdOrRange_id, ASIdOrRange_range, ASIdentifierChoice_asIdsOrRanges,
3-
ASIdentifierChoice_inherit, ASN1_INTEGER,
5+
ASIdentifierChoice_inherit, IPAddressChoice_addressesOrRanges, X509v3_addr_get_afi,
6+
X509v3_addr_get_range, ASN1_INTEGER, IANA_AFI_IPV4, IANA_AFI_IPV6,
47
};
58
use foreign_types::{ForeignType, ForeignTypeRef};
69

710
use crate::{
811
asn1::Asn1IntegerRef,
9-
stack::{StackRef, Stackable},
12+
stack::{Stack, StackRef, Stackable},
1013
util::{ForeignTypeExt, ForeignTypeRefExt},
1114
};
1215

@@ -47,25 +50,27 @@ impl ASIdentifiers {
4750

4851
pub fn ranges(&self) -> Option<Vec<(u32, u32)>> {
4952
let mut r = Vec::new();
53+
let asptr = self.0;
5054
unsafe {
51-
let asptr = self.0;
5255
let asnum = (*asptr).asnum;
53-
if (*asnum).type_ == ASIdentifierChoice_asIdsOrRanges {
54-
if let Some(s) = StackRef::<ASIdOrRange>::from_const_ptr_opt((*asnum).asIdsOrRanges)
55-
{
56-
for a_ptr in s {
57-
let a = a_ptr.as_ptr();
58-
if (*a).type_ == ASIdOrRange_id {
59-
let asn = Self::parse_asn1_integer((*a).u.id)?;
60-
r.push((asn, asn));
61-
} else if (*a).type_ == ASIdOrRange_range {
62-
let range = (*a).u.range;
63-
let asn1 = Self::parse_asn1_integer((*range).min)?;
64-
let asn2 = Self::parse_asn1_integer((*range).max)?;
65-
r.push((asn1, asn2));
66-
}
56+
if (*asnum).type_ != ASIdentifierChoice_asIdsOrRanges {
57+
return None;
58+
}
59+
if let Some(s) = StackRef::<ASIdOrRange>::from_const_ptr_opt((*asnum).asIdsOrRanges) {
60+
for a_ptr in s {
61+
let a = a_ptr.as_ptr();
62+
if (*a).type_ == ASIdOrRange_id {
63+
let asn = Self::parse_asn1_integer((*a).u.id)?;
64+
r.push((asn, asn));
65+
} else if (*a).type_ == ASIdOrRange_range {
66+
let range = (*a).u.range;
67+
let asn1 = Self::parse_asn1_integer((*range).min)?;
68+
let asn2 = Self::parse_asn1_integer((*range).max)?;
69+
r.push((asn1, asn2));
6770
}
6871
}
72+
} else {
73+
return None;
6974
}
7075
}
7176
Some(r)
@@ -80,11 +85,105 @@ impl ASIdentifiers {
8085
}
8186
}
8287

83-
pub trait ExtractASN {
88+
foreign_type_and_impl_send_sync! {
89+
type CType = ffi::_IPAddressOrRange;
90+
fn drop = ffi::IPAddressOrRange_free;
91+
92+
/// The AS number extension of an `X509` certificate.
93+
pub struct IPAddressOrRange;
94+
/// Reference to `IPAddressOrRange`.
95+
pub struct IPAddressOrRangeRef;
96+
}
97+
98+
impl Stackable for IPAddressOrRange {
99+
type StackType = ffi::stack_st_IPAddressOrRange;
100+
}
101+
102+
foreign_type_and_impl_send_sync! {
103+
type CType = ffi::_IPAddressFamily;
104+
fn drop = ffi::IPAddressFamily_free;
105+
106+
/// The AS number extension of an `X509` certificate.
107+
pub struct IPAddressFamily;
108+
/// Reference to `IPAddressFamily`.
109+
pub struct IPAddressFamilyRef;
110+
}
111+
112+
impl Stackable for IPAddressFamily {
113+
type StackType = ffi::stack_st_IPAddressFamily;
114+
}
115+
116+
#[derive(PartialEq, Eq, Debug)]
117+
pub enum IPVersion {
118+
V4,
119+
V6,
120+
}
121+
122+
impl IPAddressFamily {
123+
pub fn fam(&self) -> Option<IPVersion> {
124+
let ptr = self.0;
125+
match X509v3_addr_get_afi(ptr) {
126+
IANA_AFI_IPV4 => Some(IPVersion::V4),
127+
IANA_AFI_IPV6 => Some(IPVersion::V6),
128+
_ => None,
129+
}
130+
}
131+
132+
pub fn range(&self) -> Option<Vec<(std::net::IpAddr, std::net::IpAddr)>> {
133+
let ptr = self.0;
134+
let mut r = Vec::new();
135+
unsafe {
136+
let choice = (*ptr).ipAddressChoice;
137+
if (*choice).type_ != IPAddressChoice_addressesOrRanges {
138+
return None;
139+
}
140+
let stack =
141+
StackRef::<IPAddressOrRange>::from_const_ptr_opt((*choice).addressesOrRanges)?;
142+
for e in stack {
143+
let mut min = MaybeUninit::<[u8; 16]>::uninit();
144+
let mut max = MaybeUninit::<[u8; 16]>::uninit();
145+
let size = X509v3_addr_get_range(
146+
e.as_ptr(),
147+
X509v3_addr_get_afi(ptr),
148+
min.as_mut_ptr() as *mut u8,
149+
max.as_mut_ptr() as *mut u8,
150+
16,
151+
);
152+
r.push((
153+
Self::data_to_ip_addr(min.assume_init(), size)?,
154+
Self::data_to_ip_addr(max.assume_init(), size)?,
155+
))
156+
}
157+
}
158+
Some(r)
159+
}
160+
161+
fn data_to_ip_addr(data: [u8; 16], len: isize) -> Option<std::net::IpAddr> {
162+
match len {
163+
4 => Some(std::net::IpAddr::V4(std::net::Ipv4Addr::new(
164+
data[0], data[1], data[2], data[3],
165+
))),
166+
16 => Some(std::net::IpAddr::V6(std::net::Ipv6Addr::new(
167+
(data[0] as u16) << 8 | data[1] as u16,
168+
(data[2] as u16) << 8 | data[3] as u16,
169+
(data[4] as u16) << 8 | data[5] as u16,
170+
(data[6] as u16) << 8 | data[7] as u16,
171+
(data[8] as u16) << 8 | data[9] as u16,
172+
(data[10] as u16) << 8 | data[11] as u16,
173+
(data[12] as u16) << 8 | data[13] as u16,
174+
(data[14] as u16) << 8 | data[15] as u16,
175+
))),
176+
_ => None,
177+
}
178+
}
179+
}
180+
181+
pub trait ExtractSBGPInfo {
84182
fn asn(&self) -> Option<ASIdentifiers>;
183+
fn ip_addresses(&self) -> Option<Stack<IPAddressFamily>>;
85184
}
86185

87-
impl ExtractASN for X509 {
186+
impl ExtractSBGPInfo for X509 {
88187
fn asn(&self) -> Option<ASIdentifiers> {
89188
unsafe {
90189
let asn = ffi::X509_get_ext_d2i(
@@ -96,4 +195,16 @@ impl ExtractASN for X509 {
96195
ASIdentifiers::from_ptr_opt(asn as *mut _)
97196
}
98197
}
198+
199+
fn ip_addresses(&self) -> Option<Stack<IPAddressFamily>> {
200+
unsafe {
201+
let asn = ffi::X509_get_ext_d2i(
202+
self.as_ptr(),
203+
ffi::NID_sbgp_ipAddrBlock,
204+
std::ptr::null_mut(),
205+
std::ptr::null_mut(),
206+
);
207+
Stack::from_ptr_opt(asn as *mut _)
208+
}
209+
}
99210
}

0 commit comments

Comments
 (0)