25RCSID(
"$Id: 2ea970c1d43ec8944e213f31d653d3fc676a1306 $")
29#define LOG_PREFIX "tls"
31#include <freeradius-devel/tls/openssl_user_macros.h>
32#include <freeradius-devel/util/pair.h>
33#include <freeradius-devel/server/request.h>
34#include <freeradius-devel/server/pair.h>
35#include <freeradius-devel/der/der.h>
43#include <openssl/x509v3.h>
44#include <openssl/ssl.h>
45#include <openssl/ocsp.h>
52 FR_OPENSSL_X509_CONST X509_EXTENSION *ext)
54 GENERAL_NAMES *
names = NULL;
58 if (!(
names = X509V3_EXT_d2i(ext)))
return false;
60 for (i = 0; i < sk_GENERAL_NAME_num(
names); i++) {
61 GENERAL_NAME *
name = sk_GENERAL_NAME_value(
names, i);
69 (
char const *)ASN1_STRING_get0_data(
name->d.rfc822Name),
70 fr_tls_asn1_string_length(
name->d.rfc822Name),
true) == 0);
78 (
char const *)ASN1_STRING_get0_data(
name->d.dNSName),
79 fr_tls_asn1_string_length(
name->d.dNSName),
true) == 0);
85 if (NID_ms_upn != OBJ_obj2nid(
name->d.otherName->type_id))
break;
88 if (
name->d.otherName->value->type == V_ASN1_UTF8STRING) {
92 (
char const *)ASN1_STRING_get0_data(
name->d.otherName->value->value.utf8string),
93 fr_tls_asn1_string_length(
name->d.otherName->value->value.utf8string),
97 RWARN(
"Invalid UPN in Subject Alt Name (should be UTF-8)");
114 FR_OPENSSL_X509_CONST X509_EXTENSION *ext)
116 ASN1_STRING
const *s = X509_EXTENSION_get_data(ext);
117 char unsigned const *
data = ASN1_STRING_get0_data(s);
118 STACK_OF(DIST_POINT) *dps;
120 STACK_OF(GENERAL_NAME) *
names;
125 if (!(dps = d2i_CRL_DIST_POINTS(NULL, &
data, fr_tls_asn1_string_length(s))))
return false;
127 for (i = 0; i < sk_DIST_POINT_num(dps); i++) {
128 dp = sk_DIST_POINT_value(dps, i);
133 if (!dp->distpoint) {
134 CRL_DIST_POINTS_free(dps);
138 names = dp->distpoint->name.fullname;
144 if (dp->reasons)
continue;
146 for (j = 0; j < sk_GENERAL_NAME_num(
names); j++) {
149 if (
name->type != GEN_URI)
continue;
153 (
char const *)ASN1_STRING_get0_data(
name->d.uniformResourceIdentifier),
154 fr_tls_asn1_string_length(
name->d.uniformResourceIdentifier),
159 CRL_DIST_POINTS_free(dps);
168 FR_OPENSSL_X509_CONST X509_EXTENSION *ext)
170 ASN1_STRING
const *s = X509_EXTENSION_get_data(ext);
171 char unsigned const *
data = ASN1_STRING_get0_data(s);
173 AUTHORITY_INFO_ACCESS *aia;
174 ACCESS_DESCRIPTION *ad;
175 char *host = NULL, *path = NULL;
176 int i, port, is_https;
178 if (!(aia = d2i_AUTHORITY_INFO_ACCESS(NULL, &
data, fr_tls_asn1_string_length(s))))
return false;
180 for (i = 0; i < sk_ACCESS_DESCRIPTION_num(aia); i++) {
184 ad = sk_ACCESS_DESCRIPTION_value(aia, i);
185 if (OBJ_obj2nid(ad->method) != NID_ad_OCSP)
continue;
186 if (ad->location->type != GEN_URI)
continue;
188 len = fr_tls_asn1_string_length(ad->location->d.uniformResourceIdentifier);
190 (
char const *)ASN1_STRING_get0_data(ad->location->d.uniformResourceIdentifier),
197 if (OSSL_HTTP_parse_url(uri, &is_https, NULL, &host, NULL, &port, &path, NULL, NULL)) {
206 AUTHORITY_INFO_ACCESS_free(aia);
226#
if OPENSSL_VERSION_NUMBER >= 0x30400000L
236 ASN1_TIME
const *asn_time;
239 STACK_OF(X509_EXTENSION)
const *ext_list = NULL;
242 bool san_found =
false, crl_found =
false, aia_found =
false;
248#if OPENSSL_VERSION_NUMBER >= 0x30400000L
257 der_len = i2d_X509(cert, NULL);
259 fr_tls_log_perror(
request,
"Failed retrieving certificate");
273 fr_tls_log_perror(
request,
"Failed decoding certificate");
289 if (
unlikely(X509_NAME_print_ex(fr_tls_bio_dbuff_thread_local(
vp, 256, 0),
290 X509_get_subject_name(cert), 0, XN_FLAG_ONELINE) < 0)) {
291 fr_tls_bio_dbuff_thread_local_clear();
292 fr_tls_log_perror(
request,
"Failed retrieving certificate subject");
304 loc = X509_NAME_get_index_by_NID(X509_get_subject_name(cert), NID_commonName, -1);
306 ASN1_STRING
const *cn;
308 cn = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(X509_get_subject_name(cert), loc));
309 if (cn && (fr_tls_asn1_string_length(cn) > 0)) {
312 fr_tls_asn1_string_length(cn),
true) == 0);
320 ASN1_BIT_STRING
const *sig;
321 X509_ALGOR
const *alg;
323 X509_get0_signature(&sig, &alg, cert);
327 (
uint8_t const *)ASN1_STRING_get0_data(sig),
328 fr_tls_asn1_string_length(sig),
true) == 0);
330 OBJ_obj2txt(
buff,
sizeof(
buff), alg->algorithm, 0);
339 if (
unlikely(X509_NAME_print_ex(fr_tls_bio_dbuff_thread_local(
vp, 256, 0),
340 X509_get_issuer_name(cert), 0, XN_FLAG_ONELINE) < 0)) {
341 fr_tls_bio_dbuff_thread_local_clear();
342 fr_tls_log_perror(
request,
"Failed retrieving certificate issuer");
351 ASN1_INTEGER
const *serial = NULL;
355 serial = X509_get0_serialNumber(cert);
357 fr_tls_log_perror(
request,
"Failed retrieving certificate serial");
361 len = i2d_ASN1_INTEGER(serial, NULL);
364 i2d_ASN1_INTEGER(serial, &der);
370 asn_time = X509_get0_notBefore(cert);
373 RPWDEBUG(
"(TLS) Failed parsing certificate not-before");
383 asn_time = X509_get0_notAfter(cert);
386 RPWDEBUG(
"(TLS) Failed parsing certificate not-after");
396 loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, 0);
398 FR_OPENSSL_X509_CONST X509_EXTENSION *ext = X509_get_ext(cert, loc);
399 if (ext) san_found = tls_session_pairs_from_san(
pair_list, ctx,
request, ext);
402 loc = X509_get_ext_by_NID(cert, NID_crl_distribution_points, 0);
404 FR_OPENSSL_X509_CONST X509_EXTENSION *ext = X509_get_ext(cert, loc);
405 if (ext) crl_found = tls_session_pairs_from_crl(
pair_list, ctx,
request, ext);
413 certid = OCSP_cert_to_id(NULL, cert, issuer);
415 len = i2d_OCSP_CERTID(certid, &ocsp_certid);
416 if (
len < 0)
goto error;
417 if (ocsp_certid != NULL) {
420 OPENSSL_free(ocsp_certid);
422 OCSP_CERTID_free(certid);
428 ext_list = X509_get0_extensions(cert);
430 RWDEBUG(
"(TLS) Failed retrieving extensions");
438 if (sk_X509_EXTENSION_num(ext_list) > 0) {
441 fr_tls_bio_dbuff_t *bd;
444 bio = fr_tls_bio_dbuff_alloc(&bd, NULL, NULL, 257, 4097,
true);
445 in = fr_tls_bio_dbuff_in(bd);
446 out = fr_tls_bio_dbuff_out(bd);
448 for (i = 0; i < sk_X509_EXTENSION_num(ext_list); i++) {
449 ASN1_OBJECT
const *obj;
454 ext = sk_X509_EXTENSION_value(ext_list, i);
456 obj = X509_EXTENSION_get_object(ext);
466 if (OBJ_obj2nid(obj) == NID_subject_alt_name) {
467 if (!san_found) san_found = tls_session_pairs_from_san(
pair_list, ctx,
request, ext);
471 if (OBJ_obj2nid(obj) == NID_crl_distribution_points) {
472 if (!crl_found) crl_found = tls_session_pairs_from_crl(
pair_list, ctx,
request, ext);
476 if (OBJ_obj2nid(obj) == NID_info_access) {
477 if (!aia_found) aia_found = tls_session_pairs_from_aia(
pair_list, ctx,
request, ext);
481 if (i2a_ASN1_OBJECT(bio, obj) <= 0) {
482 RPWDEBUG(
"(TLS) Skipping X509 Extension (%i) conversion to attribute. "
483 "Conversion from ASN1 failed...", i);
485 fr_tls_bio_dbuff_reset(bd);
503 RWDEBUG(
"(TLS) Attribute name too long");
512 RWDEBUG3(
"(TLS) Skipping attribute \"%pV\": "
513 "Add a dictionary definition if you want to access it",
520 fr_tls_bio_dbuff_reset(bd);
522 if (X509V3_EXT_print(bio, ext, X509V3_EXT_PARSE_UNKNOWN, 0) != 1) {
523 REDEBUG(
"(TLS) Failed extracting data for \"%s\"", da->name);
536 fr_tls_bio_dbuff_reset(bd);
561 size_t hlen,
size_t dlen,
size_t total_len,
fr_dict_attr_t const *da)
563 size_t i,extension_len;
569 if (total_len < hlen) {
570 REDEBUG(
"(TLS) Missing length in %s extension", da->name);
575 extension_len = extension[0];
577 extension_len = (extension[0] << 8) + extension[1];
581 if (extension_len + hlen > total_len) {
582 REDEBUG(
"(TLS) Invalid length %zu in %s extension", extension_len, da->name);
586 data = extension + hlen;
588 for (i = 0; i < extension_len; i += dlen) {
615 uint8_t const *ciphers, *extension;
616 int i, *extensions = NULL;
618 STACK_OF(SSL_CIPHER) *sk;
619 SSL_CIPHER
const *cipher;
620 STACK_OF(SSL_CIPHER) *scsvs;
626 if (container)
return SSL_CLIENT_HELLO_SUCCESS;
630 data_size = SSL_client_hello_get0_ciphers(ssl, &ciphers);
631 if (SSL_bytes_to_cipher_list(ssl, ciphers, data_size,
632#
if OPENSSL_VERSION_NUMBER >= 0x40000000L
635 SSL_client_hello_isv2(ssl),
638 RPEDEBUG(
"(TLS) Failed to decode cipher list");
640 if (extensions) OPENSSL_free(extensions);
642 return SSL_CLIENT_HELLO_ERROR;
645 for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
647 cipher = sk_SSL_CIPHER_value(sk, i);
651 sk_SSL_CIPHER_free(sk);
652 sk_SSL_CIPHER_free(scsvs);
659 if (SSL_client_hello_get1_extensions_present(ssl, &extensions, &data_size) == 0) {
660 RPEDEBUG(
"(TLS) Failed to fetch client hello extensions");
664 for (j = 0; j < data_size; j++) {
667 if (SSL_client_hello_get0_ext(ssl, extensions[j], &extension, &total_len) == 0) {
668 RPDEBUG(
"Failed getting client hello extension %d", extensions[j]);
672 switch (extensions[j]) {
673 case TLSEXT_TYPE_supported_groups:
674 if (fr_tls_extension_decode(
request, container, extension, 2, 2, total_len,
678 case TLSEXT_TYPE_ec_point_formats:
679 if (fr_tls_extension_decode(
request, container, extension, 1, 1, total_len,
683 case TLSEXT_TYPE_signature_algorithms:
684 if (fr_tls_extension_decode(
request, container, extension, 2, 2, total_len,
688 case TLSEXT_TYPE_supported_versions:
689 if (fr_tls_extension_decode(
request, container, extension, 1, 2, total_len,
693 case TLSEXT_TYPE_psk_kex_modes:
694 if (fr_tls_extension_decode(
request, container, extension, 1, 1, total_len,
700 if (extensions) OPENSSL_free(extensions);
707 vp->vp_uint16 = SSL_client_hello_get0_legacy_version(ssl);
711 return SSL_CLIENT_HELLO_SUCCESS;
static uint8_t request[4]
#define USES_APPLE_DEPRECATED_API
#define DIAG_OFF_OPTIONAL(_x)
#define DIAG_ON_OPTIONAL(_x)
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
#define fr_dbuff_end(_dbuff_or_marker)
Return the current 'end' position of a dbuff or marker.
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
#define fr_dbuff_in_bytes(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
TALLOC_CTX * tmp_ctx
ctx under which temporary data will be allocated
bool const fr_dict_attr_allowed_chars[SBUFF_CHAR_CLASS]
Characters allowed in a single dictionary attribute name.
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
HIDDEN fr_dict_attr_t const * attr_tls_certificate
Attribute definitions for lib curl.
#define RPEDEBUG(fmt,...)
#define RPWDEBUG3(fmt,...)
#define RPWDEBUG(fmt,...)
#define RWDEBUG3(fmt,...)
HIDDEN fr_dict_attr_t const * attr_tls_certificate_subject
HIDDEN fr_dict_attr_t const * attr_tls_client_hello
HIDDEN fr_dict_attr_t const * attr_tls_client_hello_psk_key_mode
HIDDEN fr_dict_attr_t const * attr_tls_certificate_serial
HIDDEN fr_dict_attr_t const * attr_tls_certificate_subject_alt_name_dns
HIDDEN fr_dict_attr_t const * attr_tls_client_hello_supported_group
HIDDEN fr_dict_attr_t const * attr_tls_certificate_not_after
HIDDEN fr_dict_attr_t const * attr_tls_certificate_not_before
HIDDEN fr_dict_attr_t const * attr_tls_certificate_signature_algorithm
HIDDEN fr_dict_attr_t const * attr_tls_certificate_subject_alt_name_upn
HIDDEN fr_dict_attr_t const * attr_tls_client_hello_sig_algo
HIDDEN fr_dict_attr_t const * attr_tls_certificate_ocsp_uri
HIDDEN fr_dict_attr_t const * attr_tls_certificate_common_name
HIDDEN fr_dict_attr_t const * attr_tls_certificate_ocsp_cert_id
HIDDEN fr_dict_attr_t const * attr_tls_certificate_issuer
HIDDEN fr_dict_attr_t const * attr_tls_certificate_x509v3_crl_distribution_points
HIDDEN fr_dict_attr_t const * attr_tls_client_hello_ec_point_format
HIDDEN fr_dict_attr_t const * attr_der_certificate
HIDDEN fr_dict_attr_t const * attr_tls_certificate_signature
HIDDEN fr_dict_attr_t const * attr_tls_client_hello_tls_version
HIDDEN fr_dict_attr_t const * attr_tls_client_hello_cipher
HIDDEN fr_dict_attr_t const * attr_tls_certificate_subject_alt_name_email
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and append)
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
int fr_pair_value_bstrdup_buffer_shallow(fr_pair_t *vp, char const *src, bool tainted)
Assign a string to a "string" type value pair.
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, UNUSED bool tainted)
Convert string value to native attribute value.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
int fr_pair_value_mem_alloc(fr_pair_t *vp, uint8_t **out, size_t size, bool tainted)
Pre-allocate a memory buffer for a "octets" type value pair.
ssize_t fr_der_decode_pair_dbuff(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx)
static char buff[sizeof("18446744073709551615")+3]
Stores an attribute, a value and various bits of other data.
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
static const char * names[8]
static fr_unix_time_t fr_unix_time_from_time(time_t time)
Convert a time_t into out internal fr_unix_time_t.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
void fr_pair_list_prepend(fr_pair_list_t *dst, fr_pair_list_t *src)
Move a list of fr_pair_t from a temporary list to the head of a destination list.
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
int fr_tls_utils_asn1time_to_epoch(time_t *out, ASN1_TIME const *asn1)
Convert OpenSSL's ASN1_TIME to an epoch time.
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Copy a buffer to a fr_value_box_t.
static fr_sbuff_err_t char size_t fr_sbuff_t * in
#define fr_box_strvalue_buffer(_val)
#define fr_box_strvalue_len(_val, _len)
static fr_sbuff_err_t char ** out
static fr_sbuff_err_t char size_t * len