Skip to content

Commit fa19ebf

Browse files
committed
Add functions to extract X509 extensions
1 parent e146219 commit fa19ebf

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

Diff for: openssl/src/x509/mod.rs

+60
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,29 @@ impl X509Ref {
667667
}
668668
}
669669

670+
/// Return this certificate's list of extensions.
671+
pub fn extensions(&self) -> Result<Vec<&X509ExtensionRef>, ErrorStack> {
672+
let mut exts = Vec::new();
673+
// SAFETY: the rust openssl binding guarantees that x509 is a valid object.
674+
let ext_count = unsafe { ffi::X509_get_ext_count(self.as_ptr()) };
675+
676+
for index in 0..ext_count {
677+
// SAFETY: the rust openssl binding guarantees that x509 is a valid object
678+
// and `index` is a valid index.
679+
// From the documentation of X509_get_ext:
680+
// The returned extension is an internal pointer which must not be freed
681+
// up by the application. Therefore this pointer is valid as long as the X509
682+
// object lives.
683+
let ext = unsafe {
684+
X509ExtensionRef::from_ptr(cvt_p(ffi::X509_get_ext(self.as_ptr(), index))?)
685+
};
686+
687+
exts.push(ext)
688+
}
689+
690+
Ok(exts)
691+
}
692+
670693
to_pem! {
671694
/// Serializes the certificate into a PEM-encoded X509 structure.
672695
///
@@ -1050,6 +1073,43 @@ impl X509Extension {
10501073
}
10511074

10521075
impl X509ExtensionRef {
1076+
/// Returns the criticality of this extension.
1077+
pub fn critical(&self) -> bool {
1078+
// SAFETY: `self` is a valid object.
1079+
let critical = unsafe { ffi::X509_EXTENSION_get_critical(self.as_ptr()) };
1080+
// In the ASN1, the critical marker is a boolean so it's actually impossible for
1081+
// openssl to return anything but 0 and 1, so throw in error in case we see anything else.
1082+
match critical {
1083+
0 => false,
1084+
1 => true,
1085+
_ => panic!("openssl returned non-boolean critical marker for extension"),
1086+
}
1087+
}
1088+
1089+
/// Returns this extension's type.
1090+
pub fn object(&self) -> Result<&Asn1ObjectRef, ErrorStack> {
1091+
// SAFETY: `self` is a valid object and the returned pointer is marked with the lifetime
1092+
// of the X509 object that owns the memory.
1093+
unsafe {
1094+
// From the documentation of X509_EXTENSION_get_object:
1095+
// The returned pointer is an internal value which must not be freed up.
1096+
let data = cvt_p(ffi::X509_EXTENSION_get_object(self.as_ptr()))?;
1097+
Ok(Asn1ObjectRef::from_ptr(data))
1098+
}
1099+
}
1100+
1101+
/// Returns this extension's data.
1102+
pub fn data(&self) -> Result<&Asn1OctetStringRef, ErrorStack> {
1103+
// SAFETY: `self` is a valid object and the returned pointer is marked with the lifetime
1104+
// of the X509 object that owns the memory.
1105+
unsafe {
1106+
// From the documentation of X509_EXTENSION_get_data:
1107+
// The returned pointer is an internal value which must not be freed up.
1108+
let data = cvt_p(ffi::X509_EXTENSION_get_data(self.as_ptr()))?;
1109+
Ok(Asn1OctetStringRef::from_ptr(data))
1110+
}
1111+
}
1112+
10531113
to_der! {
10541114
/// Serializes the Extension to its standard DER encoding.
10551115
#[corresponds(i2d_X509_EXTENSION)]

Diff for: openssl/src/x509/tests.rs

+18
Original file line numberDiff line numberDiff line change
@@ -1192,3 +1192,21 @@ fn test_store_all_certificates() {
11921192

11931193
assert_eq!(store.all_certificates().len(), 1);
11941194
}
1195+
1196+
#[test]
1197+
fn test_get_extensions() {
1198+
// With AIA
1199+
let cert = include_bytes!("../../test/alt_name_cert.pem");
1200+
let cert = X509::from_pem(cert).unwrap();
1201+
let exts = cert.extensions().unwrap();
1202+
const EXPECTED_EXTS: &[(Nid, usize)] = &[
1203+
(Nid::BASIC_CONSTRAINTS, 2),
1204+
(Nid::KEY_USAGE, 4),
1205+
(Nid::SUBJECT_ALT_NAME, 81),
1206+
];
1207+
assert_eq!(exts.len(), EXPECTED_EXTS.len());
1208+
for (i, (nid, len)) in EXPECTED_EXTS.iter().enumerate() {
1209+
assert_eq!(exts[i].object().unwrap().nid(), *nid);
1210+
assert_eq!(exts[i].data().unwrap().len(), *len);
1211+
}
1212+
}

0 commit comments

Comments
 (0)