Skip to content
Merged
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
17 changes: 17 additions & 0 deletions boring/src/asn1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,14 @@ impl Asn1TimeRef {
}
}

impl AsRef<Asn1StringRef> for Asn1TimeRef {
fn as_ref(&self) -> &Asn1StringRef {
// SAFETY: `ASN1_TIME` is a typedef of `ASN1_STRING`, and the returned
// reference is bounded by the lifetime of `self`.
unsafe { Asn1StringRef::from_ptr(self.as_ptr().cast()) }
}
}

impl PartialEq for Asn1TimeRef {
fn eq(&self, other: &Asn1TimeRef) -> bool {
self.diff(other)
Expand Down Expand Up @@ -830,6 +838,15 @@ mod tests {
assert_eq!("Jan 1 00:00:00 1970 GMT", t.to_string());
}

#[test]
fn time_as_asn1_string() {
let time = Asn1Time::from_str("99991231235959Z").unwrap();
let time_ref: &Asn1TimeRef = time.as_ref();
let string_ref: &Asn1StringRef = time_ref.as_ref();

assert_eq!(string_ref.as_slice(), b"99991231235959Z");
}

#[test]
fn time_eq() {
let a = Asn1Time::from_str("99991231235959Z").unwrap();
Expand Down
42 changes: 42 additions & 0 deletions boring/src/ssl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1475,6 +1475,27 @@ impl SslContextBuilder {
unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())) }
}

/// Sets the leaf certificate from its DER encoding without fully parsing it.
///
/// BoringSSL copies `der` and performs only the checks needed to extract a
/// supported public key. Other malformed certificate fields may be accepted.
///
/// # Warning
///
/// Callers should normally parse the DER with [`X509::from_der`] and use
/// [`Self::set_certificate`]. This method is intended for cases that must
/// preserve certificate DER which cannot be represented by an [`X509Ref`].
#[corresponds(SSL_CTX_use_certificate_ASN1)]
pub fn set_certificate_der_unchecked(&mut self, der: &[u8]) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::SSL_CTX_use_certificate_ASN1(
self.as_ptr(),
der.len(),
der.as_ptr(),
))
}
}

/// Appends a certificate to the certificate chain.
///
/// This chain should contain all certificates necessary to go from the certificate specified by
Expand Down Expand Up @@ -3876,6 +3897,27 @@ impl SslRef {
Ok(())
}

/// Sets the leaf certificate from its DER encoding without fully parsing it.
///
/// BoringSSL copies `der` and performs only the checks needed to extract a
/// supported public key. Other malformed certificate fields may be accepted.
///
/// # Warning
///
/// Callers should normally parse the DER with [`X509::from_der`] and use
/// [`Self::set_certificate`]. This method is intended for cases that must
/// preserve certificate DER which cannot be represented by an [`X509Ref`].
#[corresponds(SSL_use_certificate_ASN1)]
pub fn set_certificate_der_unchecked(&mut self, der: &[u8]) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::SSL_use_certificate_ASN1(
self.as_ptr(),
der.as_ptr(),
der.len(),
))
}
}

/// Sets the list of CA names sent to the client.
///
/// The CA certificates must still be added to the trust root - they are not automatically set
Expand Down
36 changes: 36 additions & 0 deletions boring/src/ssl/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;

use crate::asn1::Asn1StringRef;
use crate::error::ErrorStack;
use crate::hash::MessageDigest;
use crate::pkey::PKey;
Expand Down Expand Up @@ -40,6 +41,41 @@ static CERT: &[u8] = include_bytes!("../../../test/cert.pem");
static KEY: &[u8] = include_bytes!("../../../test/key.pem");
const TEST_CERT_DIGEST: &str = "585e3a58acfd3b4e5e2825659407244ddd93539c";

fn malformed_certificate_der() -> Vec<u8> {
const MALFORMED_TIME: &[u8] = b"250231000000Z";

let cert = X509::from_pem(CERT).unwrap();
let time: &Asn1StringRef = cert.not_before().as_ref();
let original = time.as_slice();
assert_eq!(original.len(), MALFORMED_TIME.len());

let mut der = cert.to_der().unwrap();
let offset = der
.windows(original.len())
.position(|window| window == original)
.unwrap();
der[offset..offset + MALFORMED_TIME.len()].copy_from_slice(MALFORMED_TIME);
assert!(X509::from_der(&der).is_err());

der
}

#[test]
fn set_context_certificate_der_unchecked() {
let mut context = SslContext::builder(SslMethod::tls()).unwrap();
context
.set_certificate_der_unchecked(&malformed_certificate_der())
.unwrap();
}

#[test]
fn set_certificate_der_unchecked() {
let context = SslContext::builder(SslMethod::tls()).unwrap().build();
let mut ssl = Ssl::new(&context).unwrap();
ssl.set_certificate_der_unchecked(&malformed_certificate_der())
.unwrap();
}

#[test]
fn get_ctx_options() {
let ctx = SslContext::builder(SslMethod::tls()).unwrap();
Expand Down
Loading