summaryrefslogtreecommitdiffstats
path: root/vendor/openssl/src/x509
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/openssl/src/x509')
-rw-r--r--vendor/openssl/src/x509/extension.rs35
-rw-r--r--vendor/openssl/src/x509/mod.rs275
-rw-r--r--vendor/openssl/src/x509/tests.rs152
-rw-r--r--vendor/openssl/src/x509/verify.rs4
4 files changed, 442 insertions, 24 deletions
diff --git a/vendor/openssl/src/x509/extension.rs b/vendor/openssl/src/x509/extension.rs
index f04d22796..11e015153 100644
--- a/vendor/openssl/src/x509/extension.rs
+++ b/vendor/openssl/src/x509/extension.rs
@@ -67,6 +67,9 @@ impl BasicConstraints {
}
/// Return the `BasicConstraints` extension as an `X509Extension`.
+ // Temporarily silence the deprecation warning - this should be ported to
+ // `X509Extension::new_internal`.
+ #[allow(deprecated)]
pub fn build(&self) -> Result<X509Extension, ErrorStack> {
let mut value = String::new();
if self.critical {
@@ -183,6 +186,9 @@ impl KeyUsage {
}
/// Return the `KeyUsage` extension as an `X509Extension`.
+ // Temporarily silence the deprecation warning - this should be ported to
+ // `X509Extension::new_internal`.
+ #[allow(deprecated)]
pub fn build(&self) -> Result<X509Extension, ErrorStack> {
let mut value = String::new();
let mut first = true;
@@ -346,6 +352,9 @@ impl SubjectKeyIdentifier {
}
/// Return a `SubjectKeyIdentifier` extension as an `X509Extension`.
+ // Temporarily silence the deprecation warning - this should be ported to
+ // `X509Extension::new_internal`.
+ #[allow(deprecated)]
pub fn build(&self, ctx: &X509v3Context<'_>) -> Result<X509Extension, ErrorStack> {
let mut value = String::new();
let mut first = true;
@@ -398,6 +407,9 @@ impl AuthorityKeyIdentifier {
}
/// Return a `AuthorityKeyIdentifier` extension as an `X509Extension`.
+ // Temporarily silence the deprecation warning - this should be ported to
+ // `X509Extension::new_internal`.
+ #[allow(deprecated)]
pub fn build(&self, ctx: &X509v3Context<'_>) -> Result<X509Extension, ErrorStack> {
let mut value = String::new();
let mut first = true;
@@ -422,6 +434,7 @@ enum RustGeneralName {
Uri(String),
Ip(String),
Rid(String),
+ OtherName(Asn1Object, Vec<u8>),
}
/// An extension that allows additional identities to be bound to the subject
@@ -494,12 +507,21 @@ impl SubjectAlternativeName {
/// Sets the `otherName` flag.
///
- /// Not currently actually supported, always panics.
- #[deprecated = "other_name is deprecated and always panics. Please file a bug if you have a use case for this."]
+ /// Not currently actually supported, always panics. Please use other_name2
+ #[deprecated = "other_name is deprecated and always panics. Please use other_name2."]
pub fn other_name(&mut self, _other_name: &str) -> &mut SubjectAlternativeName {
- unimplemented!(
- "This has not yet been adapted for the new internals. File a bug if you need this."
- );
+ unimplemented!("This has not yet been adapted for the new internals. Use other_name2.");
+ }
+
+ /// Sets the `otherName` flag.
+ ///
+ /// `content` must be a valid der encoded ASN1_TYPE
+ ///
+ /// If you want to add just a ia5string use `other_name_ia5string`
+ pub fn other_name2(&mut self, oid: Asn1Object, content: &[u8]) -> &mut SubjectAlternativeName {
+ self.items
+ .push(RustGeneralName::OtherName(oid, content.into()));
+ self
}
/// Return a `SubjectAlternativeName` extension as an `X509Extension`.
@@ -514,6 +536,9 @@ impl SubjectAlternativeName {
GeneralName::new_ip(s.parse().map_err(|_| ErrorStack::get())?)?
}
RustGeneralName::Rid(s) => GeneralName::new_rid(Asn1Object::from_str(s)?)?,
+ RustGeneralName::OtherName(oid, content) => {
+ GeneralName::new_other_name(oid.clone(), content)?
+ }
};
stack.push(gn)?;
}
diff --git a/vendor/openssl/src/x509/mod.rs b/vendor/openssl/src/x509/mod.rs
index eab1ea675..4325b132e 100644
--- a/vendor/openssl/src/x509/mod.rs
+++ b/vendor/openssl/src/x509/mod.rs
@@ -24,8 +24,8 @@ use std::slice;
use std::str;
use crate::asn1::{
- Asn1BitStringRef, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef,
- Asn1Type,
+ Asn1BitStringRef, Asn1Enumerated, Asn1IntegerRef, Asn1Object, Asn1ObjectRef,
+ Asn1OctetStringRef, Asn1StringRef, Asn1TimeRef, Asn1Type,
};
use crate::bio::MemBioSlice;
use crate::conf::ConfRef;
@@ -50,6 +50,16 @@ pub mod store;
#[cfg(test)]
mod tests;
+/// A type of X509 extension.
+///
+/// # Safety
+/// The value of NID and Output must match those in OpenSSL so that
+/// `Output::from_ptr_opt(*_get_ext_d2i(*, NID, ...))` is valid.
+pub unsafe trait ExtensionType {
+ const NID: Nid;
+ type Output: ForeignType;
+}
+
foreign_type_and_impl_send_sync! {
type CType = ffi::X509_STORE_CTX;
fn drop = ffi::X509_STORE_CTX_free;
@@ -391,7 +401,10 @@ impl X509Ref {
/// Returns the hash of the certificates subject
#[corresponds(X509_subject_name_hash)]
pub fn subject_name_hash(&self) -> u32 {
- unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 }
+ #[allow(clippy::unnecessary_cast)]
+ unsafe {
+ ffi::X509_subject_name_hash(self.as_ptr()) as u32
+ }
}
/// Returns this certificate's issuer name.
@@ -406,7 +419,10 @@ impl X509Ref {
/// Returns the hash of the certificates issuer
#[corresponds(X509_issuer_name_hash)]
pub fn issuer_name_hash(&self) -> u32 {
- unsafe { ffi::X509_issuer_name_hash(self.as_ptr()) as u32 }
+ #[allow(clippy::unnecessary_cast)]
+ unsafe {
+ ffi::X509_issuer_name_hash(self.as_ptr()) as u32
+ }
}
/// Returns this certificate's subject alternative name entries, if they exist.
@@ -467,6 +483,54 @@ impl X509Ref {
}
}
+ /// Retrieves the path length extension from a certificate, if it exists.
+ #[corresponds(X509_get_pathlen)]
+ #[cfg(ossl110)]
+ pub fn pathlen(&self) -> Option<u32> {
+ let v = unsafe { ffi::X509_get_pathlen(self.as_ptr()) };
+ u32::try_from(v).ok()
+ }
+
+ /// Returns this certificate's subject key id, if it exists.
+ #[corresponds(X509_get0_subject_key_id)]
+ #[cfg(ossl110)]
+ pub fn subject_key_id(&self) -> Option<&Asn1OctetStringRef> {
+ unsafe {
+ let data = ffi::X509_get0_subject_key_id(self.as_ptr());
+ Asn1OctetStringRef::from_const_ptr_opt(data)
+ }
+ }
+
+ /// Returns this certificate's authority key id, if it exists.
+ #[corresponds(X509_get0_authority_key_id)]
+ #[cfg(ossl110)]
+ pub fn authority_key_id(&self) -> Option<&Asn1OctetStringRef> {
+ unsafe {
+ let data = ffi::X509_get0_authority_key_id(self.as_ptr());
+ Asn1OctetStringRef::from_const_ptr_opt(data)
+ }
+ }
+
+ /// Returns this certificate's authority issuer name entries, if they exist.
+ #[corresponds(X509_get0_authority_issuer)]
+ #[cfg(ossl111d)]
+ pub fn authority_issuer(&self) -> Option<&StackRef<GeneralName>> {
+ unsafe {
+ let stack = ffi::X509_get0_authority_issuer(self.as_ptr());
+ StackRef::from_const_ptr_opt(stack)
+ }
+ }
+
+ /// Returns this certificate's authority serial number, if it exists.
+ #[corresponds(X509_get0_authority_serial)]
+ #[cfg(ossl111d)]
+ pub fn authority_serial(&self) -> Option<&Asn1IntegerRef> {
+ unsafe {
+ let r = ffi::X509_get0_authority_serial(self.as_ptr());
+ Asn1IntegerRef::from_const_ptr_opt(r)
+ }
+ }
+
#[corresponds(X509_get_pubkey)]
pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
unsafe {
@@ -562,6 +626,7 @@ impl X509Ref {
/// Note that `0` return value stands for version 1, `1` for version 2 and so on.
#[corresponds(X509_get_version)]
#[cfg(ossl110)]
+ #[allow(clippy::unnecessary_cast)]
pub fn version(&self) -> i32 {
unsafe { ffi::X509_get_version(self.as_ptr()) as i32 }
}
@@ -825,6 +890,13 @@ impl X509Extension {
/// mini-language that can read arbitrary files.
///
/// See the extension module for builder types which will construct certain common extensions.
+ ///
+ /// This function is deprecated, `X509Extension::new_from_der` or the
+ /// types in `x509::extension` should be used in its place.
+ #[deprecated(
+ note = "Use x509::extension types or new_from_der instead",
+ since = "0.10.51"
+ )]
pub fn new(
conf: Option<&ConfRef>,
context: Option<&X509v3Context<'_>>,
@@ -870,6 +942,13 @@ impl X509Extension {
/// mini-language that can read arbitrary files.
///
/// See the extension module for builder types which will construct certain common extensions.
+ ///
+ /// This function is deprecated, `X509Extension::new_from_der` or the
+ /// types in `x509::extension` should be used in its place.
+ #[deprecated(
+ note = "Use x509::extension types or new_from_der instead",
+ since = "0.10.51"
+ )]
pub fn new_nid(
conf: Option<&ConfRef>,
context: Option<&X509v3Context<'_>>,
@@ -904,6 +983,31 @@ impl X509Extension {
}
}
+ /// Constructs a new X509 extension value from its OID, whether it's
+ /// critical, and its DER contents.
+ ///
+ /// The extent structure of the DER value will vary based on the
+ /// extension type, and can generally be found in the RFC defining the
+ /// extension.
+ ///
+ /// For common extension types, there are Rust APIs provided in
+ /// `openssl::x509::extensions` which are more ergonomic.
+ pub fn new_from_der(
+ oid: &Asn1ObjectRef,
+ critical: bool,
+ der_contents: &Asn1OctetStringRef,
+ ) -> Result<X509Extension, ErrorStack> {
+ unsafe {
+ cvt_p(ffi::X509_EXTENSION_create_by_OBJ(
+ ptr::null_mut(),
+ oid.as_ptr(),
+ critical as _,
+ der_contents.as_ptr(),
+ ))
+ .map(X509Extension)
+ }
+ }
+
pub(crate) unsafe fn new_internal(
nid: Nid,
critical: bool,
@@ -919,6 +1023,10 @@ impl X509Extension {
///
/// This method modifies global state without locking and therefore is not thread safe
#[corresponds(X509V3_EXT_add_alias)]
+ #[deprecated(
+ note = "Use x509::extension types or new_from_der and then this is not necessary",
+ since = "0.10.51"
+ )]
pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> {
ffi::init();
cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ())
@@ -969,13 +1077,13 @@ impl X509NameBuilder {
pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
unsafe {
let field = CString::new(field).unwrap();
- assert!(value.len() <= c_int::max_value() as usize);
+ assert!(value.len() <= crate::SLenType::max_value() as usize);
cvt(ffi::X509_NAME_add_entry_by_txt(
self.0.as_ptr(),
field.as_ptr() as *mut _,
ffi::MBSTRING_UTF8,
value.as_ptr(),
- value.len() as c_int,
+ value.len() as crate::SLenType,
-1,
0,
))
@@ -996,13 +1104,13 @@ impl X509NameBuilder {
) -> Result<(), ErrorStack> {
unsafe {
let field = CString::new(field).unwrap();
- assert!(value.len() <= c_int::max_value() as usize);
+ assert!(value.len() <= crate::SLenType::max_value() as usize);
cvt(ffi::X509_NAME_add_entry_by_txt(
self.0.as_ptr(),
field.as_ptr() as *mut _,
ty.as_raw(),
value.as_ptr(),
- value.len() as c_int,
+ value.len() as crate::SLenType,
-1,
0,
))
@@ -1017,13 +1125,13 @@ impl X509NameBuilder {
/// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html
pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
unsafe {
- assert!(value.len() <= c_int::max_value() as usize);
+ assert!(value.len() <= crate::SLenType::max_value() as usize);
cvt(ffi::X509_NAME_add_entry_by_NID(
self.0.as_ptr(),
field.as_raw(),
ffi::MBSTRING_UTF8,
value.as_ptr() as *mut _,
- value.len() as c_int,
+ value.len() as crate::SLenType,
-1,
0,
))
@@ -1043,13 +1151,13 @@ impl X509NameBuilder {
ty: Asn1Type,
) -> Result<(), ErrorStack> {
unsafe {
- assert!(value.len() <= c_int::max_value() as usize);
+ assert!(value.len() <= crate::SLenType::max_value() as usize);
cvt(ffi::X509_NAME_add_entry_by_NID(
self.0.as_ptr(),
field.as_raw(),
ty.as_raw(),
value.as_ptr() as *mut _,
- value.len() as c_int,
+ value.len() as crate::SLenType,
-1,
0,
))
@@ -1442,6 +1550,7 @@ impl X509ReqRef {
/// This corresponds to [`X509_REQ_get_version`]
///
/// [`X509_REQ_get_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_version.html
+ #[allow(clippy::unnecessary_cast)]
pub fn version(&self) -> i32 {
unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
}
@@ -1495,13 +1604,41 @@ impl X509ReqRef {
}
}
+/// The reason that a certificate was revoked.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct CrlReason(c_int);
+
+#[allow(missing_docs)] // no need to document the constants
+impl CrlReason {
+ pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED);
+ pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE);
+ pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE);
+ pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED);
+ pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED);
+ pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION);
+ pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD);
+ pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL);
+ pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN);
+ pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE);
+
+ /// Constructs an `CrlReason` from a raw OpenSSL value.
+ pub const fn from_raw(value: c_int) -> Self {
+ CrlReason(value)
+ }
+
+ /// Returns the raw OpenSSL value represented by this type.
+ pub const fn as_raw(&self) -> c_int {
+ self.0
+ }
+}
+
foreign_type_and_impl_send_sync! {
type CType = ffi::X509_REVOKED;
fn drop = ffi::X509_REVOKED_free;
- /// An `X509` certificate request.
+ /// An `X509` certificate revocation status.
pub struct X509Revoked;
- /// Reference to `X509Crl`.
+ /// Reference to `X509Revoked`.
pub struct X509RevokedRef;
}
@@ -1527,6 +1664,13 @@ impl X509RevokedRef {
ffi::i2d_X509_REVOKED
}
+ /// Copies the entry to a new `X509Revoked`.
+ #[corresponds(X509_NAME_dup)]
+ #[cfg(any(boringssl, ossl110, libressl270))]
+ pub fn to_owned(&self) -> Result<X509Revoked, ErrorStack> {
+ unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) }
+ }
+
/// Get the date that the certificate was revoked
#[corresponds(X509_REVOKED_get0_revocationDate)]
pub fn revocation_date(&self) -> &Asn1TimeRef {
@@ -1546,13 +1690,67 @@ impl X509RevokedRef {
Asn1IntegerRef::from_ptr(r as *mut _)
}
}
+
+ /// Get the criticality and value of an extension.
+ ///
+ /// This returns None if the extension is not present or occurs multiple times.
+ #[corresponds(X509_REVOKED_get_ext_d2i)]
+ pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
+ let mut critical = -1;
+ let out = unsafe {
+ // SAFETY: self.as_ptr() is a valid pointer to an X509_REVOKED.
+ let ext = ffi::X509_REVOKED_get_ext_d2i(
+ self.as_ptr(),
+ T::NID.as_raw(),
+ &mut critical as *mut _,
+ ptr::null_mut(),
+ );
+ // SAFETY: Extensions's contract promises that the type returned by
+ // OpenSSL here is T::Output.
+ T::Output::from_ptr_opt(ext as *mut _)
+ };
+ match (critical, out) {
+ (0, Some(out)) => Ok(Some((false, out))),
+ (1, Some(out)) => Ok(Some((true, out))),
+ // -1 means the extension wasn't found, -2 means multiple were found.
+ (-1 | -2, _) => Ok(None),
+ // A critical value of 0 or 1 suggests success, but a null pointer
+ // was returned so something went wrong.
+ (0 | 1, None) => Err(ErrorStack::get()),
+ (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
+ }
+ }
+}
+
+/// The CRL entry extension identifying the reason for revocation see [`CrlReason`],
+/// this is as defined in RFC 5280 Section 5.3.1.
+pub enum ReasonCode {}
+
+// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
+// and in OpenSSL.
+unsafe impl ExtensionType for ReasonCode {
+ const NID: Nid = Nid::from_raw(ffi::NID_crl_reason);
+
+ type Output = Asn1Enumerated;
+}
+
+/// The CRL entry extension identifying the issuer of a certificate used in
+/// indirect CRLs, as defined in RFC 5280 Section 5.3.3.
+pub enum CertificateIssuer {}
+
+// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
+// and in OpenSSL.
+unsafe impl ExtensionType for CertificateIssuer {
+ const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer);
+
+ type Output = Stack<GeneralName>;
}
foreign_type_and_impl_send_sync! {
type CType = ffi::X509_CRL;
fn drop = ffi::X509_CRL_free;
- /// An `X509` certificate request.
+ /// An `X509` certificate revocation list.
pub struct X509Crl;
/// Reference to `X509Crl`.
pub struct X509CrlRef;
@@ -1856,6 +2054,37 @@ impl GeneralName {
Ok(GeneralName::from_ptr(gn))
}
}
+
+ pub(crate) fn new_other_name(
+ oid: Asn1Object,
+ value: &Vec<u8>,
+ ) -> Result<GeneralName, ErrorStack> {
+ unsafe {
+ ffi::init();
+
+ let typ = cvt_p(ffi::d2i_ASN1_TYPE(
+ ptr::null_mut(),
+ &mut value.as_ptr().cast(),
+ value.len().try_into().unwrap(),
+ ))?;
+
+ let gn = cvt_p(ffi::GENERAL_NAME_new())?;
+ (*gn).type_ = ffi::GEN_OTHERNAME;
+
+ if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername(
+ gn,
+ oid.as_ptr().cast(),
+ typ,
+ )) {
+ ffi::GENERAL_NAME_free(gn);
+ return Err(e);
+ }
+
+ mem::forget(oid);
+
+ Ok(GeneralName::from_ptr(gn))
+ }
+ }
}
impl GeneralNameRef {
@@ -1886,6 +2115,22 @@ impl GeneralNameRef {
self.ia5_string(ffi::GEN_EMAIL)
}
+ /// Returns the contents of this `GeneralName` if it is a `directoryName`.
+ pub fn directory_name(&self) -> Option<&X509NameRef> {
+ unsafe {
+ if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME {
+ return None;
+ }
+
+ #[cfg(boringssl)]
+ let d = (*self.as_ptr()).d.ptr;
+ #[cfg(not(boringssl))]
+ let d = (*self.as_ptr()).d;
+
+ Some(X509NameRef::from_const_ptr(d as *const _))
+ }
+ }
+
/// Returns the contents of this `GeneralName` if it is a `dNSName`.
pub fn dnsname(&self) -> Option<&str> {
self.ia5_string(ffi::GEN_DNS)
diff --git a/vendor/openssl/src/x509/tests.rs b/vendor/openssl/src/x509/tests.rs
index 365960441..da3ce2fed 100644
--- a/vendor/openssl/src/x509/tests.rs
+++ b/vendor/openssl/src/x509/tests.rs
@@ -1,6 +1,6 @@
use std::cmp::Ordering;
-use crate::asn1::Asn1Time;
+use crate::asn1::{Asn1Object, Asn1OctetString, Asn1Time};
use crate::bn::{BigNum, MsbOption};
use crate::hash::MessageDigest;
use crate::nid::Nid;
@@ -18,19 +18,24 @@ use crate::x509::store::X509Lookup;
use crate::x509::store::X509StoreBuilder;
#[cfg(any(ossl102, libressl261))]
use crate::x509::verify::{X509VerifyFlags, X509VerifyParam};
-#[cfg(ossl110)]
-use crate::x509::X509Builder;
#[cfg(ossl102)]
use crate::x509::X509PurposeId;
#[cfg(any(ossl102, libressl261))]
use crate::x509::X509PurposeRef;
+#[cfg(ossl110)]
+use crate::x509::{CrlReason, X509Builder};
use crate::x509::{
CrlStatus, X509Crl, X509Extension, X509Name, X509Req, X509StoreContext, X509VerifyResult, X509,
};
+
+#[cfg(ossl110)]
+use foreign_types::ForeignType;
use hex::{self, FromHex};
#[cfg(any(ossl102, libressl261))]
use libc::time_t;
+use super::{CertificateIssuer, ReasonCode};
+
fn pkey() -> PKey<Private> {
let rsa = Rsa::generate(2048).unwrap();
PKey::from_rsa(rsa).unwrap()
@@ -167,6 +172,70 @@ fn test_subject_alt_name() {
}
#[test]
+#[cfg(ossl110)]
+fn test_retrieve_pathlen() {
+ let cert = include_bytes!("../../test/root-ca.pem");
+ let cert = X509::from_pem(cert).unwrap();
+ assert_eq!(cert.pathlen(), None);
+
+ let cert = include_bytes!("../../test/intermediate-ca.pem");
+ let cert = X509::from_pem(cert).unwrap();
+ assert_eq!(cert.pathlen(), Some(0));
+
+ let cert = include_bytes!("../../test/alt_name_cert.pem");
+ let cert = X509::from_pem(cert).unwrap();
+ assert_eq!(cert.pathlen(), None);
+}
+
+#[test]
+#[cfg(ossl110)]
+fn test_subject_key_id() {
+ let cert = include_bytes!("../../test/certv3.pem");
+ let cert = X509::from_pem(cert).unwrap();
+
+ let subject_key_id = cert.subject_key_id().unwrap();
+ assert_eq!(
+ subject_key_id.as_slice(),
+ &b"\xB6\x73\x2F\x61\xA5\x4B\xA1\xEF\x48\x2C\x15\xB1\x9F\xF3\xDC\x34\x2F\xBC\xAC\x30"[..]
+ );
+}
+
+#[test]
+#[cfg(ossl110)]
+fn test_authority_key_id() {
+ let cert = include_bytes!("../../test/certv3.pem");
+ let cert = X509::from_pem(cert).unwrap();
+
+ let authority_key_id = cert.authority_key_id().unwrap();
+ assert_eq!(
+ authority_key_id.as_slice(),
+ &b"\x6C\xD3\xA5\x03\xAB\x0D\x5F\x2C\xC9\x8D\x8A\x9C\x88\xA7\x88\x77\xB8\x37\xFD\x9A"[..]
+ );
+}
+
+#[test]
+#[cfg(ossl111d)]
+fn test_authority_issuer_and_serial() {
+ let cert = include_bytes!("../../test/authority_key_identifier.pem");
+ let cert = X509::from_pem(cert).unwrap();
+
+ let authority_issuer = cert.authority_issuer().unwrap();
+ assert_eq!(1, authority_issuer.len());
+ let dn = authority_issuer[0].directory_name().unwrap();
+ let mut o = dn.entries_by_nid(Nid::ORGANIZATIONNAME);
+ let o = o.next().unwrap().data().as_utf8().unwrap();
+ assert_eq!(o.as_bytes(), b"PyCA");
+ let mut cn = dn.entries_by_nid(Nid::COMMONNAME);
+ let cn = cn.next().unwrap().data().as_utf8().unwrap();
+ assert_eq!(cn.as_bytes(), b"cryptography.io");
+
+ let authority_serial = cert.authority_serial().unwrap();
+ let serial = authority_serial.to_bn().unwrap();
+ let expected = BigNum::from_u32(3).unwrap();
+ assert_eq!(serial, expected);
+}
+
+#[test]
fn test_subject_alt_name_iter() {
let cert = include_bytes!("../../test/alt_name_cert.pem");
let cert = X509::from_pem(cert).unwrap();
@@ -288,6 +357,8 @@ fn x509_builder() {
}
#[test]
+// This tests `X509Extension::new`, even though its deprecated.
+#[allow(deprecated)]
fn x509_extension_new() {
assert!(X509Extension::new(None, None, "crlDistributionPoints", "section").is_err());
assert!(X509Extension::new(None, None, "proxyCertInfo", "").is_err());
@@ -296,6 +367,20 @@ fn x509_extension_new() {
}
#[test]
+fn x509_extension_new_from_der() {
+ let ext = X509Extension::new_from_der(
+ &Asn1Object::from_str("2.5.29.19").unwrap(),
+ true,
+ &Asn1OctetString::new_from_bytes(b"\x30\x03\x01\x01\xff").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ ext.to_der().unwrap(),
+ b"0\x0f\x06\x03U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff"
+ );
+}
+
+#[test]
fn x509_extension_to_der() {
let builder = X509::builder().unwrap();
@@ -612,6 +697,42 @@ fn test_load_crl() {
}
#[test]
+fn test_crl_entry_extensions() {
+ let crl = include_bytes!("../../test/entry_extensions.crl");
+ let crl = X509Crl::from_pem(crl).unwrap();
+
+ let revoked_certs = crl.get_revoked().unwrap();
+ let entry = &revoked_certs[0];
+
+ let (critical, issuer) = entry
+ .extension::<CertificateIssuer>()
+ .unwrap()
+ .expect("Certificate issuer extension should be present");
+ assert!(critical, "Certificate issuer extension is critical");
+ assert_eq!(issuer.len(), 1, "Certificate issuer should have one entry");
+ let issuer = issuer[0]
+ .directory_name()
+ .expect("Issuer should be a directory name");
+ assert_eq!(
+ format!("{:?}", issuer),
+ r#"[countryName = "GB", commonName = "Test CA"]"#
+ );
+
+ // reason_code can't be inspected without ossl110
+ #[allow(unused_variables)]
+ let (critical, reason_code) = entry
+ .extension::<ReasonCode>()
+ .unwrap()
+ .expect("Reason code extension should be present");
+ assert!(!critical, "Reason code extension is not critical");
+ #[cfg(ossl110)]
+ assert_eq!(
+ CrlReason::KEY_COMPROMISE,
+ CrlReason::from_raw(reason_code.get_i64().unwrap() as ffi::c_int)
+ );
+}
+
+#[test]
fn test_save_subject_der() {
let cert = include_bytes!("../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
@@ -987,6 +1108,31 @@ fn ipv6_as_subject_alternative_name_is_formatted_in_debug() {
]);
}
+#[cfg(ossl110)]
+#[test]
+fn other_name_as_subject_alternative_name() {
+ let oid = Asn1Object::from_str("1.3.6.1.5.5.7.8.11").unwrap();
+ // this is the hex representation of "test" encoded as a ia5string
+ let content = [0x16, 0x04, 0x74, 0x65, 0x73, 0x74];
+
+ let mut builder = X509Builder::new().unwrap();
+ let san = SubjectAlternativeName::new()
+ .other_name2(oid, &content)
+ .build(&builder.x509v3_context(None, None))
+ .unwrap();
+ builder.append_extension(san).unwrap();
+ let cert = builder.build();
+ let general_name = cert
+ .subject_alt_names()
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap();
+ unsafe {
+ assert_eq!((*general_name.as_ptr()).type_, 0);
+ }
+}
+
#[test]
fn test_dist_point() {
let cert = include_bytes!("../../test/certv3.pem");
diff --git a/vendor/openssl/src/x509/verify.rs b/vendor/openssl/src/x509/verify.rs
index b0e22ef46..e8481c551 100644
--- a/vendor/openssl/src/x509/verify.rs
+++ b/vendor/openssl/src/x509/verify.rs
@@ -120,9 +120,11 @@ impl X509VerifyParamRef {
#[corresponds(X509_VERIFY_PARAM_set1_host)]
pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> {
unsafe {
+ // len == 0 means "run strlen" :(
+ let raw_host = if host.is_empty() { "\0" } else { host };
cvt(ffi::X509_VERIFY_PARAM_set1_host(
self.as_ptr(),
- host.as_ptr() as *const _,
+ raw_host.as_ptr() as *const _,
host.len(),
))
.map(|_| ())