Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

X509ref: Add name_constraints & policy_mappings access #2319

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions openssl-sys/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## [Unreleased]

### Added

* Added `NAME_CONSTRAINTS`, `GENERAL_SUBTREE`, `stack_st_GENERAL_SUBTREE`
* Added `POLICY_MAPPING`, `stack_st_POLICY_MAPPING`

## [v0.9.104] - 2024-10-15

### Added
Expand Down
36 changes: 36 additions & 0 deletions openssl-sys/src/handwritten/x509v3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,39 @@ extern "C" {
pub fn X509_check_ip(x: *mut X509, chk: *const c_uchar, chklen: usize, flags: c_uint) -> c_int;
pub fn X509_check_ip_asc(x: *mut X509, ipasc: *const c_char, flags: c_uint) -> c_int;
}

#[repr(C)]
pub struct GENERAL_SUBTREE {
pub base: *mut GENERAL_NAME,
pub minimum: *mut ASN1_INTEGER,
pub maximum: *mut ASN1_INTEGER,
}

extern "C" {
pub fn GENERAL_SUBTREE_new() -> *mut GENERAL_SUBTREE;
pub fn GENERAL_SUBTREE_free(name: *mut GENERAL_SUBTREE);
}

stack!(stack_st_GENERAL_SUBTREE);

#[repr(C)]
pub struct NAME_CONSTRAINTS {
pub permittedSubtrees: *mut stack_st_GENERAL_SUBTREE,
pub excludedSubtrees: *mut stack_st_GENERAL_SUBTREE,
}

extern "C" {
pub fn NAME_CONSTRAINTS_free(nc: *mut NAME_CONSTRAINTS);
}

#[repr(C)]
pub struct POLICY_MAPPING {
pub issuerDomainPolicy: *mut ASN1_OBJECT,
pub subjectDomainPolicy: *mut ASN1_OBJECT,
}

extern "C" {
pub fn POLICY_MAPPING_free(nc: *mut POLICY_MAPPING);
}

stack!(stack_st_POLICY_MAPPING);
5 changes: 5 additions & 0 deletions openssl/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## [Unreleased]

### Added

- Added `X509Ref::name_constraints`
- Added `X509Ref::policy_mappings`

## [v0.10.68] - 2024-10-16

### Fixed
Expand Down
104 changes: 104 additions & 0 deletions openssl/src/x509/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,38 @@ impl X509Ref {
}
}

/// Returns this certificate's [`name constraints`] entry, if it exists.
///
/// [`name constraints`]: https://tools.ietf.org/html/rfc5280#section-4.2.1.10
#[corresponds(X509_get_ext_d2i)]
pub fn name_constraints(&self) -> Option<&NameConstraintsRef> {
unsafe {
let ext = ffi::X509_get_ext_d2i(
self.as_ptr(),
ffi::NID_name_constraints,
ptr::null_mut(),
ptr::null_mut(),
);
NameConstraintsRef::from_const_ptr_opt(ext as *mut _)
}
}

/// Returns this certificate's [`policy mappings`] entries, if they exist.
///
/// [`policy mappings`]: https://tools.ietf.org/html/rfc5280#section-4.2.1.5
#[corresponds(X509_get_ext_d2i)]
pub fn policy_mappings(&self) -> Option<Stack<PolicyMapping>> {
unsafe {
let stack = ffi::X509_get_ext_d2i(
self.as_ptr(),
ffi::NID_policy_mappings,
ptr::null_mut(),
ptr::null_mut(),
);
Stack::from_ptr_opt(stack as *mut _)
}
}

/// Retrieves the path length extension from a certificate, if it exists.
#[corresponds(X509_get_pathlen)]
#[cfg(any(ossl110, boringssl))]
Expand Down Expand Up @@ -2261,6 +2293,78 @@ impl Stackable for AccessDescription {
type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
}

foreign_type_and_impl_send_sync! {
type CType = ffi::GENERAL_SUBTREE;
fn drop = ffi::GENERAL_SUBTREE_free;

/// An `X509` subtree.
pub struct GeneralSubtree;
/// Reference to `GeneralSubtree`.
pub struct GeneralSubtreeRef;
}

impl Stackable for GeneralSubtree {
type StackType = ffi::stack_st_GENERAL_SUBTREE;
}

impl GeneralSubtreeRef {
pub fn base(&self) -> &GeneralNameRef {
unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).base) }
}

pub fn minimum(&self) -> Option<&Asn1IntegerRef> {
unsafe { Asn1IntegerRef::from_const_ptr_opt((*self.as_ptr()).minimum) }
}

pub fn maximum(&self) -> Option<&Asn1IntegerRef> {
unsafe { Asn1IntegerRef::from_const_ptr_opt((*self.as_ptr()).maximum) }
}
}

foreign_type_and_impl_send_sync! {
type CType = ffi::NAME_CONSTRAINTS;
fn drop = ffi::NAME_CONSTRAINTS_free;

/// `NameConstraints` of certificate authority information.
pub struct NameConstraints;
/// Reference to `NameConstraints`.
pub struct NameConstraintsRef;
}

impl NameConstraintsRef {
pub fn permitted(&self) -> Option<&StackRef<GeneralSubtree>> {
unsafe { StackRef::from_const_ptr_opt((*self.as_ptr()).permittedSubtrees) }
}

pub fn excluded(&self) -> Option<&StackRef<GeneralSubtree>> {
unsafe { StackRef::from_const_ptr_opt((*self.as_ptr()).excludedSubtrees) }
}
}

foreign_type_and_impl_send_sync! {
type CType = ffi::POLICY_MAPPING;
fn drop = ffi::POLICY_MAPPING_free;

/// `PolicyMapping` of certificate authority information.
pub struct PolicyMapping;
/// Reference to `PolicyMapping`.
pub struct PolicyMappingRef;
}

impl Stackable for PolicyMapping {
type StackType = ffi::stack_st_POLICY_MAPPING;
}

impl PolicyMappingRef {
pub fn issuer_domain_policy(&self) -> &Asn1ObjectRef {
unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).issuerDomainPolicy) }
}

pub fn subject_domain_policy(&self) -> &Asn1ObjectRef {
unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).subjectDomainPolicy) }
}
}

foreign_type_and_impl_send_sync! {
type CType = ffi::X509_ALGOR;
fn drop = ffi::X509_ALGOR_free;
Expand Down
50 changes: 50 additions & 0 deletions openssl/src/x509/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,56 @@ fn test_subject_alt_name_iter() {
assert!(subject_alt_names_iter.next().is_none());
}

#[test]
fn test_name_constraints() {
let cert = include_bytes!("../../test/name_constraints.pem");
let cert = X509::from_pem(cert).unwrap();

// Access through .name_constraints()
let name_constraints = cert
.name_constraints()
.expect("Name constraints extension should be present");

let permitted = name_constraints.permitted().unwrap();
assert_eq!(permitted.len(), 1);

let base = permitted[0].base().dnsname().unwrap();
assert_eq!(base, ".example.com");

let minimum = permitted[0].minimum().is_none();
assert!(minimum);
let maximum = permitted[0].maximum().is_none();
assert!(maximum);

let excluded = name_constraints.excluded().unwrap();
assert_eq!(excluded.len(), 1);

let base = excluded[0].base().dnsname().unwrap();
assert_eq!(base, ".example.net");

let minimum = excluded[0].minimum().is_none();
assert!(minimum);
let maximum = excluded[0].maximum().is_none();
assert!(maximum);
}

#[test]
fn test_policy_mappings() {
let cert = include_bytes!("../../test/policy_mappings.pem");
let cert = X509::from_pem(cert).unwrap();

// Access through .policy_mappings()
let policy_mappings = cert
.policy_mappings()
.expect("Policy mappings should be present");

assert_eq!(policy_mappings.len(), 1);
let policy = policy_mappings[0].issuer_domain_policy().to_string();
assert_eq!(policy, "2.16.840.1.101.3.2.1.48.1");
let policy = policy_mappings[0].subject_domain_policy().to_string();
assert_eq!(policy, "2.16.840.1.101.3.2.1.48.2");
}

#[test]
fn test_aia_ca_issuer() {
// With AIA
Expand Down
31 changes: 31 additions & 0 deletions openssl/test/name_constraints.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgIUOwEq2g8zyCoGLVhxTQ/loZ7M0qwwDQYJKoZIhvcNAQEL
BQAwLDELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0V4YW1wbGUxCzAJBgNVBAsMAkNB
MB4XDTI0MTAxNjA0NTcyOFoXDTI1MTAxNjA0NTcyOFowLDELMAkGA1UEBhMCVVMx
EDAOBgNVBAoMB0V4YW1wbGUxCzAJBgNVBAsMAkNBMIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEAoRQKVqSwPHyHQiHxMVCxabVO2W7dNGSP7jvnAR5Yu424
9vLaY/n347f80w1ad8c1Ecl8m8vrprg7jAXuDoI02ys62J6qE87bqGpfL5oJ5AGD
RDm3x+T63bNvBbU2pSN5F0INXlahaGufE1BqDQlPq3CRDDnXSslTMGruZbcriW/u
IMgvnCGm7WtKejcnWa0vEmOo9KgOnHrpzYqWRJg6FmeT8D4P703HSexL1wNw7e4n
jSmaWrAMQeq8H0srjyMfKItMm1khYN7s4xFHkYARh9ppolXAXwLN56c9ZTunpb+p
Y1yBpYIeOp8NIDvwTfdUyHzr6ZsQ4tHu3XsXi4HMmBqnXxDIIctkwE1zB8nrGF8J
8GEH0hwXInsIG8ib7FIpF3T9zx85FsjK90TPMIG5DoBg3IuYiGU4Jc3tKrQLbrGl
fr25tneqbvndLSsIrRkb5z7JNnLNTv6eCVQGus6MYaOnR/tJAm7htCoImxvuc7+h
4nXIzypjNz1ephlvtad69RZYf1WQMMeVR3uK6T/J6QYVN3VqmU62pRJPuC3J3x/l
nEqJphA51gattgX7WJLb0dKSEEuRZzSmEJcgEnHg3Pyg0ST7Tbbj3hkLYVLD+kOn
VTaI4PDzLNSWnucZ6hcIDJr3rTj4wekkq+MsZ2dOacrzZKlJKWXTQGtdSeTxIesC
AwEAAaN0MHIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
BBYEFGa7OPpxvHJn7JmdrnSvM8Yc1plJMDAGA1UdHgEB/wQmMCSgEDAOggwuZXhh
bXBsZS5jb22hEDAOggwuZXhhbXBsZS5uZXQwDQYJKoZIhvcNAQELBQADggIBAAbd
/7jTjmctPZrCB2//jLQXzPkqtwjK/kIWJ90l2XtlALsykdjawGi7GsbLHWabM0Cm
55iRFsQ+w3DC9+m/2wCL6yG/Pjnj/c3PNb707S4y57o8ALL7YuURso3PGOqYfBY1
G851MXahFCM3SjxVKlJc6XCfs/XgJ7N0loAYLQSNsYjNk4QiuEsU6r7WtPy0qEzv
ly6u8U8DWQ0EEH3dA9UzUpwHW3sipUzxeKpxzqhaTc8U8+TPS+InEJfWHrGMKwF7
Db1q7aQA6s8U7uLG45RIIvLBerpdyPsSpcFIlP7DAhllPgTWhtkAAvcddkeIUUcy
YKsjKMrtIX9Jzzo+ddgsIB8C/SRSE310lx2EJoD8gS1zMg4y9zQ/WXLI2ASzsO42
n4b/O7me1Qd85ku8XgnEPxmLIzpNgfDTPR5z85zeCcejmFEXzXCAwIKhCub9tjjY
9ujbrI1jGGSfCv2YvxwfZgbMMwii5YA8wK9aXqqndV/IZasxDZqJiXhDhzxZMscf
RCOphZL2dzjeiS0iWmlSTr8YQ0jr5kjZc/zl5Z3WEQFWcVzBAjJwcYiiXtIWQBVH
aEdupCi8xLVm5lRZIGL/UupM2Kz8gPPxUJkmKGDS/cceoUmtdXsNrlNUSHiXlWh1
ZITcIQozA0r0o+aEXoQtc6Tmb/rNnf84Rrfns622
-----END CERTIFICATE-----
16 changes: 16 additions & 0 deletions openssl/test/policy_mappings.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICfDCCAiOgAwIBAgIKaALI6NVFszY7ADAKBggqhkjOPQQDAjBcMQswCQYDVQQG
EwJVUzEgMB4GA1UECgwXVGVzdCBNQ0EgT3JnYW5pemF0aW9uIDIxHzAdBgNVBAMM
FlRlc3QgSUVFRSAyMDMwLjUgTUNBIDIxCjAIBgNVBAUMATEwIBcNMTkwNDE2MDU0
MzE4WhgPOTk5OTEyMzEyMzU5NTlaMF4xCzAJBgNVBAYTAlVTMSEwHwYDVQQKDBhU
ZXN0IE1JQ0EgT3JnYW5pemF0aW9uIDIxIDAeBgNVBAMMF1Rlc3QgSUVFRSAyMDMw
LjUgTUlDQSAyMQowCAYDVQQFDAE0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
hfu4ivOW15lzRrkguuUpDi4jR82g+p1z/2m0AJmiC4uJ2nY4c/80EDhG9mzuOaW4
UqJ5xSoyJWqmjDqLi7RdOaOByDCBxTASBgNVHRMBAf8ECDAGAQH/AgEAMBEGA1Ud
DgQKBAhD4TrR7KbbDTATBgNVHSMEDDAKgAhO1GdTUZdzwDAOBgNVHQ8BAf8EBAMC
AQYwUgYDVR0gAQH/BEgwRjAMBgorBQEEAYK+HAEBMAwGCisFAQQBgr4cAQIwDAYK
KwUBBAGCvhwBAzAMBgorBQEEAYK+HAIBMAwGCisFAQQBgr4cAgQwIwYDVR0hBBww
GjAYBgpghkgBZQMCATABBgpghkgBZQMCATACMAoGCCqGSM49BAMCA0cAMEQCIDJn
3s1sy27lQgxYNPImr9nYzsvIlTrEGbZUuBcw7knuAiAGWfpCVFxzE+UujZ8+ylqT
k6IKlu1bUvsNJL0Tv8XV6A==
-----END CERTIFICATE-----
Loading