tls: store list of subject alternative names

So far, the SANs were available as a part of IssuerDN via x509_parser
crate but SANs were not available to the SSLState* to be directly used
to setup and match against a sticky buffer.
Expose it to SSLStateConnp.

Feature 5234
pull/11112/head
Shivani Bhardwaj 2 years ago committed by Victor Julien
parent 8560564657
commit 3a1c12414a

@ -23,7 +23,9 @@ use crate::common::rust_string_to_c;
use nom7::Err; use nom7::Err;
use std; use std;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::fmt;
use x509_parser::prelude::*; use x509_parser::prelude::*;
use crate::x509::GeneralName;
mod time; mod time;
mod log; mod log;
@ -46,6 +48,19 @@ pub enum X509DecodeError {
pub struct X509(X509Certificate<'static>); pub struct X509(X509Certificate<'static>);
pub struct SCGeneralName<'a>(&'a GeneralName<'a>);
impl<'a> fmt::Display for SCGeneralName<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
GeneralName::DNSName(s) => write!(f, "{}", s),
GeneralName::URI(s) => write!(f, "{}", s),
GeneralName::IPAddress(s) => write!(f, "{:?}", s),
_ => write!(f, "{}", self.0)
}
}
}
/// Attempt to parse a X.509 from input, and return a pointer to the parsed object if successful. /// Attempt to parse a X.509 from input, and return a pointer to the parsed object if successful.
/// ///
/// # Safety /// # Safety
@ -79,6 +94,37 @@ pub unsafe extern "C" fn rs_x509_get_subject(ptr: *const X509) -> *mut c_char {
rust_string_to_c(subject) rust_string_to_c(subject)
} }
#[no_mangle]
pub unsafe extern "C" fn rs_x509_get_subjectaltname_len(ptr: *const X509) -> u16 {
if ptr.is_null() {
return 0;
}
let x509 = cast_pointer! {ptr, X509};
let san_list = x509.0.tbs_certificate.subject_alternative_name();
if let Ok(Some(sans)) = san_list {
// SAN length in a certificate is kept u16 following discussions at
// https://community.letsencrypt.org/t/why-sans-are-limited-to-100-domains-only
debug_validate_bug_on!(sans.value.general_names.len() == u16::MAX.into());
return sans.value.general_names.len() as u16;
}
return 0;
}
#[no_mangle]
pub unsafe extern "C" fn rs_x509_get_subjectaltname_at(ptr: *const X509, idx: u16) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
let x509 = cast_pointer! {ptr, X509};
let san_list = x509.0.tbs_certificate.subject_alternative_name();
if let Ok(Some(sans)) = san_list {
let general_name = &sans.value.general_names[idx as usize];
let dns_name = SCGeneralName(general_name);
return rust_string_to_c(dns_name.to_string());
}
return std::ptr::null_mut();
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn rs_x509_get_issuer(ptr: *const X509) -> *mut c_char { pub unsafe extern "C" fn rs_x509_get_issuer(ptr: *const X509) -> *mut c_char {
if ptr.is_null() { if ptr.is_null() {

@ -292,6 +292,8 @@ static inline int SafeMemcpy(void *dst, size_t dst_offset, size_t dst_size,
} \ } \
} while (0) } while (0)
static void SSLStateCertSANFree(SSLStateConnp *connp);
static void *SSLGetTx(void *state, uint64_t tx_id) static void *SSLGetTx(void *state, uint64_t tx_id)
{ {
SSLState *ssl_state = (SSLState *)state; SSLState *ssl_state = (SSLState *)state;
@ -546,6 +548,15 @@ static int TlsDecodeHSCertificate(SSLState *ssl_state, SSLStateConnp *connp,
} }
connp->cert0_issuerdn = str; connp->cert0_issuerdn = str;
connp->cert0_sans_len = rs_x509_get_subjectaltname_len(x509);
char **sans = SCCalloc(connp->cert0_sans_len, sizeof(char *));
if (sans == NULL) {
goto error;
}
for (uint16_t i = 0; i < connp->cert0_sans_len; i++) {
sans[i] = rs_x509_get_subjectaltname_at(x509, i);
}
connp->cert0_sans = sans;
str = rs_x509_get_serial(x509); str = rs_x509_get_serial(x509);
if (str == NULL) { if (str == NULL) {
err_code = ERR_INVALID_SERIAL; err_code = ERR_INVALID_SERIAL;
@ -584,6 +595,8 @@ error:
TlsDecodeHSCertificateErrSetEvent(ssl_state, err_code); TlsDecodeHSCertificateErrSetEvent(ssl_state, err_code);
if (x509 != NULL) if (x509 != NULL)
rs_x509_free(x509); rs_x509_free(x509);
SSLStateCertSANFree(connp);
return -1; return -1;
invalid_cert: invalid_cert:
@ -2832,6 +2845,16 @@ static void *SSLStateAlloc(void *orig_state, AppProto proto_orig)
return (void *)ssl_state; return (void *)ssl_state;
} }
static void SSLStateCertSANFree(SSLStateConnp *connp)
{
if (connp->cert0_sans) {
for (uint16_t i = 0; i < connp->cert0_sans_len; i++) {
rs_cstring_free(connp->cert0_sans[i]);
}
SCFree(connp->cert0_sans);
}
}
/** /**
* \internal * \internal
* \brief Function to free the SSL state memory. * \brief Function to free the SSL state memory.
@ -2882,6 +2905,9 @@ static void SSLStateFree(void *p)
if (ssl_state->server_connp.hs_buffer) if (ssl_state->server_connp.hs_buffer)
SCFree(ssl_state->server_connp.hs_buffer); SCFree(ssl_state->server_connp.hs_buffer);
SSLStateCertSANFree(&ssl_state->server_connp);
SSLStateCertSANFree(&ssl_state->client_connp);
AppLayerDecoderEventsFreeEvents(&ssl_state->tx_data.events); AppLayerDecoderEventsFreeEvents(&ssl_state->tx_data.events);
if (ssl_state->tx_data.de_state != NULL) { if (ssl_state->tx_data.de_state != NULL) {

@ -254,6 +254,8 @@ typedef struct SSLStateConnp_ {
int64_t cert0_not_after; int64_t cert0_not_after;
char *cert0_fingerprint; char *cert0_fingerprint;
char **cert0_sans;
uint16_t cert0_sans_len;
/* ssl server name indication extension */ /* ssl server name indication extension */
char *sni; char *sni;

Loading…
Cancel
Save