25RCSID(
"$Id: d81ad6701acbe09eab4c6bdef74484d768300fcf $")
29#define LOG_PREFIX "tls"
34#include <openssl/conf.h>
35#include <openssl/pem.h>
37#include <freeradius-devel/server/module.h>
38#include <freeradius-devel/server/virtual_servers.h>
39#include <freeradius-devel/util/debug.h>
40#include <freeradius-devel/util/syserror.h>
41#include <freeradius-devel/util/rand.h>
59 {
L(
"ASN1"), SSL_FILETYPE_ASN1 },
60 {
L(
"DER"), SSL_FILETYPE_ASN1 },
61 {
L(
"PEM"), SSL_FILETYPE_PEM }
63static size_t certificate_format_table_len =
NUM_ELEMENTS(certificate_format_table);
66 {
L(
"hard"), FR_TLS_CHAIN_VERIFY_HARD },
67 {
L(
"none"), FR_TLS_CHAIN_VERIFY_NONE },
68 {
L(
"soft"), FR_TLS_CHAIN_VERIFY_SOFT }
70static size_t chain_verify_mode_table_len =
NUM_ELEMENTS(chain_verify_mode_table);
73 {
L(
"auto"), FR_TLS_TICKET_AUTO },
74 {
L(
"disabled"), FR_TLS_TICKET_DISABLED },
75 {
L(
"stateful"), FR_TLS_TICKET_STATEFUL },
76 {
L(
"stateless"), FR_TLS_TICKET_STATELESS }
78static size_t cache_mode_table_len =
NUM_ELEMENTS(cache_mode_table);
81 {
L(
"all"), FR_TLS_VERIFY_MODE_ALL },
82 {
L(
"client"), FR_TLS_VERIFY_MODE_LEAF },
83 {
L(
"client-and-issuer"), FR_TLS_VERIFY_MODE_LEAF | FR_TLS_VERIFY_MODE_ISSUER },
84 {
L(
"disabled"), FR_TLS_VERIFY_MODE_DISABLED },
85 {
L(
"untrusted"), FR_TLS_VERIFY_MODE_UNTRUSTED }
87static size_t verify_mode_table_len =
NUM_ELEMENTS(verify_mode_table);
91 .
func = tls_conf_parse_cache_mode,
93 .table = cache_mode_table,
94 .len = &cache_mode_table_len
99 {
FR_CONF_OFFSET(
"lifetime", fr_tls_ticket_conf_t, lifetime), .func = tls_ticket_lifetime_parse, .dflt =
"1d" },
103 {
FR_CONF_OFFSET(
"require_extended_master_secret", fr_tls_ticket_conf_t, require_extms), .dflt =
"yes" },
104 {
FR_CONF_OFFSET(
"require_perfect_forward_secrecy", fr_tls_ticket_conf_t, require_pfs), .dflt =
"no" },
106 {
FR_CONF_OFFSET(
"session_ticket_key", fr_tls_ticket_conf_t, session_ticket_key) },
122 .table = certificate_format_table,
123 .len = &certificate_format_table_len
134 .func = tls_chain_private_key_file_parse },
136 {
FR_CONF_OFFSET(
"verify_mode", fr_tls_chain_conf_t, verify_mode),
139 .table = chain_verify_mode_table,
140 .len = &chain_verify_mode_table_len
143 {
FR_CONF_OFFSET(
"include_root_ca", fr_tls_chain_conf_t, include_root_ca), .dflt =
"no" },
151 .table = verify_mode_table,
152 .len = &verify_mode_table_len
155 {
FR_CONF_OFFSET(
"attribute_mode", fr_tls_verify_conf_t, attribute_mode),
158 .table = verify_mode_table,
159 .len = &verify_mode_table_len
161 .dflt =
"client-and-issuer" },
162 {
FR_CONF_OFFSET(
"der_decode", fr_tls_verify_conf_t, der_decode) },
166#ifdef PSK_MAX_IDENTITY_LEN
178 .subcs_type =
"fr_tls_chain_conf_t", .name2 =
CF_IDENT_ANY },
185 {
FR_CONF_OFFSET(
"verify_depth", fr_tls_conf_t, verify_depth), .dflt =
"0" },
189#ifdef PSK_MAX_IDENTITY_LEN
198 {
FR_CONF_OFFSET(
"fragment_size", fr_tls_conf_t, fragment_size), .func = tls_fragment_size_parse, .dflt =
"1024" },
199 {
FR_CONF_OFFSET(
"padding", fr_tls_conf_t, padding_block_size), .func = tls_padding_parse },
201 {
FR_CONF_OFFSET(
"disable_single_dh_use", fr_tls_conf_t, disable_single_dh_use) },
204 {
FR_CONF_OFFSET(
"cipher_suites", fr_tls_conf_t, cipher_suites) },
205 {
FR_CONF_OFFSET(
"cipher_server_preference", fr_tls_conf_t, cipher_server_preference), .dflt =
"yes" },
206#ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS
207 {
FR_CONF_OFFSET(
"allow_renegotiation", fr_tls_conf_t, allow_renegotiation), .dflt =
"no" },
210#ifndef OPENSSL_NO_ECDH
211 {
FR_CONF_OFFSET(
"ecdh_curve", fr_tls_conf_t, ecdh_curve), .dflt =
"prime256v1" },
213 {
FR_CONF_OFFSET(
"tls_max_version", fr_tls_conf_t, tls_max_version) },
215 {
FR_CONF_OFFSET(
"tls_min_version", fr_tls_conf_t, tls_min_version), .dflt =
"1.2" },
217 {
FR_CONF_OFFSET(
"client_hello_parse", fr_tls_conf_t, client_hello_parse )},
237 .
func = tls_virtual_server_cf_parse },
240 .subcs_type =
"fr_tls_chain_conf_t" },
251#ifdef PSK_MAX_IDENTITY_LEN
259 {
FR_CONF_OFFSET(
"verify_depth", fr_tls_conf_t, verify_depth), .dflt =
"0" },
265 {
FR_CONF_OFFSET(
"fragment_size", fr_tls_conf_t, fragment_size), .func = tls_fragment_size_parse, .dflt =
"1024" },
268 {
FR_CONF_OFFSET(
"cipher_suites", fr_tls_conf_t, cipher_suites) },
270#ifndef OPENSSL_NO_ECDH
271 {
FR_CONF_OFFSET(
"ecdh_curve", fr_tls_conf_t, ecdh_curve), .dflt =
"prime256v1" },
274 {
FR_CONF_OFFSET(
"tls_max_version", fr_tls_conf_t, tls_max_version) },
276 {
FR_CONF_OFFSET(
"tls_min_version", fr_tls_conf_t, tls_min_version), .dflt =
"1.2" },
286 fr_tls_conf_t *
conf = talloc_get_type_abort(
parent, fr_tls_conf_t);
303#ifdef PSK_MAX_IDENTITY_LEN
307 cf_log_err(ci,
"Specified virtual_server has a \"load psk { ... }\" section, "
308 "but OpenSSL was built without PSK support");
317 fr_tls_conf_t *
conf = talloc_get_type_abort((
uint8_t *)
parent - offsetof(fr_tls_conf_t, cache), fr_tls_conf_t);
327 switch (cache_mode) {
328 case FR_TLS_TICKET_DISABLED:
329 case FR_TLS_TICKET_STATELESS:
332 case FR_TLS_TICKET_STATEFUL:
333 if (!
conf->virtual_server) {
334 cf_log_err(ci,
"A virtual_server must be set when session.mode = \"stateful\"");
340 cf_log_err(ci,
"Specified virtual_server must contain a \"load session { ... }\" section "
341 "when session.mode = \"stateful\"");
346 cf_log_err(ci,
"Specified virtual_server must contain a \"store session { ... }\" section "
347 "when session.mode = \"stateful\"");
352 cf_log_err(ci,
"Specified virtual_server must contain a \"clear session { ... }\" section "
353 "when session.mode = \"stateful\"");
357 if (
conf->tls_min_version >= (
float)1.3) {
358 cf_log_err(ci,
"session.mode = \"stateful\" is not supported with tls_min_version >= 1.3");
363 case FR_TLS_TICKET_AUTO:
364 if (!
conf->virtual_server) {
365 WARN(
"A virtual_server must be provided for stateful caching. "
366 "session.mode = \"auto\" rewritten to session.mode = \"stateless\"");
368 cache_mode = FR_TLS_TICKET_STATELESS;
373 cf_log_warn(ci,
"Specified virtual_server missing \"load session { ... }\" section. "
374 "session.mode = \"auto\" rewritten to session.mode = \"stateless\"");
375 goto cache_stateless;
379 cf_log_warn(ci,
"Specified virtual_server missing \"store session { ... }\" section. "
380 "session.mode = \"auto\" rewritten to session.mode = \"stateless\"");
381 goto cache_stateless;
385 cf_log_warn(ci,
"Specified virtual_server missing \"clear cache { ... }\" section. "
386 "session.mode = \"auto\" rewritten to session.mode = \"stateless\"");
387 goto cache_stateless;
390 if (
conf->tls_min_version >= (
float)1.3) {
391 cf_log_err(ci,
"stateful session-resumption is not supported with tls_min_version >= 1.3. "
392 "session.mode = \"auto\" rewritten to session.mode = \"stateless\"");
393 goto cache_stateless;
401 if (cache_mode & FR_TLS_TICKET_STATELESS) {
406 if (!
conf->cache.session_ticket_key) {
409 talloc_array_length(
conf->cache.session_ticket_key));
413 *((
int *)
out) = cache_mode;
430 if (*fragment_size < 100) {
431 cf_log_warn(ci,
"Ignoring \"fragment_size = %u\", forcing to \"fragment_size = 100\"", *fragment_size);
432 *fragment_size = 100;
434 if (*fragment_size > SSL3_RT_MAX_PLAIN_LENGTH) {
435 cf_log_warn(ci,
"Ignoring \"fragment_size = %u\", forcing to \"fragment_size = %u\"",
436 *fragment_size, (
unsigned int)SSL3_RT_MAX_PLAIN_LENGTH);
437 *fragment_size = SSL3_RT_MAX_PLAIN_LENGTH;
452 if (*padding > SSL3_RT_MAX_PLAIN_LENGTH) {
453 cf_log_warn(ci,
"Ignoring \"padding = %u\", forcing to \"padding = %u\"",
454 *padding, (
unsigned int)SSL3_RT_MAX_PLAIN_LENGTH);
455 *padding = SSL3_RT_MAX_PLAIN_LENGTH;
472 cf_log_warn(ci,
"Ignoring \"lifetime = %pV\", forcing to \"lifetime = %pV\"",
485static char const *special_string =
"Apple:UsecertAdmin";
495static int tls_chain_password_certadmin(fr_tls_chain_conf_t *chain,
CONF_ITEM *ci)
498 char *password, *buf;
499 long const max_password_len = 128;
502 if (!chain->password)
return 0;
503 if (strncmp(chain->password, special_string, strlen(special_string)) != 0)
return 0;
505 snprintf(cmd,
sizeof(cmd) - 1,
"/usr/sbin/certadmin --get-private-key-passphrase \"%s\"",
506 chain->private_key_file);
508 DEBUG2(
"Getting private key passphrase using command \"%s\"", cmd);
510 cmd_pipe = popen(cmd,
"r");
512 cf_log_err(ci,
"%s command failed: Unable to get private_key_password", cmd);
513 cf_log_err(ci,
"Error reading private_key_file %s", chain->private_key_file);
517 MEM(password = talloc_array(chain,
char, max_password_len));
519 buf = fgets(password, max_password_len, cmd_pipe);
520 if (!buf || ferror(cmd_pipe)) {
523 cf_log_err(ci,
"%s command failed: Unable to get private_key_password", cmd);
524 cf_log_err(ci,
"Error reading private_key_file %s", chain->private_key_file);
530 for (buf = password; buf < (password + max_password_len); buf++) {
531 if ((
unsigned char)*buf <
' ') {
538 cf_log_err(ci,
"%s command failed: Unable to get private_key_password", cmd);
539 cf_log_err(ci,
"Error reading private_key_file %s - password is too long", chain->private_key_file);
543 DEBUG3(
"Password from command = \"%s\"", password);
545 chain->password = password;
553static int _tls_chain_conf_free(fr_tls_chain_conf_t *chain)
555 if (chain->leaf) X509_free(chain->leaf);
556 if (chain->extra) sk_X509_pop_free(chain->extra, X509_free);
557 if (chain->private_key) EVP_PKEY_free(chain->private_key);
573static X509 *tls_chain_cert_read(
CONF_ITEM *ci, FILE *fp,
int format,
bool aux)
578 case SSL_FILETYPE_PEM:
579 cert = aux ? PEM_read_X509_AUX(fp, NULL, NULL, NULL) : PEM_read_X509(fp, NULL, NULL, NULL);
581 unsigned long err = ERR_peek_last_error();
587 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
593 case SSL_FILETYPE_ASN1:
594 return d2i_X509_fp(fp, NULL);
597 cf_log_err(ci,
"Unknown certificate format %d", format);
615 fr_tls_chain_conf_t *chain = talloc_get_type_abort(
parent, fr_tls_chain_conf_t);
624 if (tls_chain_password_certadmin(chain, ci) < 0)
return -1;
627 talloc_set_destructor(chain, _tls_chain_conf_free);
632 fp = fopen(chain->certificate_file,
"r");
634 cf_log_err(ci,
"Failed opening certificate_file \"%s\": %s", chain->certificate_file,
fr_syserror(errno));
638 chain->leaf = tls_chain_cert_read(ci, fp, chain->file_format,
true);
640 fr_tls_strerror_printf(
"No certificate found");
641 cf_log_perr(ci,
"Failed reading certificate_file \"%s\"", chain->certificate_file);
646 MEM(chain->extra = sk_X509_new_null());
647 while ((cert = tls_chain_cert_read(ci, fp, chain->file_format,
false))) {
648 if (chain->file_format != SSL_FILETYPE_PEM) {
652 MEM(sk_X509_push(chain->extra, cert) > 0);
655 if (ERR_peek_error()) {
656 fr_tls_strerror_printf(NULL);
657 cf_log_perr(ci,
"Failed reading certificate_file \"%s\"", chain->certificate_file);
664 ca_cnt = chain->ca_files ? talloc_array_length(chain->ca_files) : 0;
665 for (i = 0; i < ca_cnt; i++) {
666 fp = fopen(chain->ca_files[i],
"r");
671 cert = tls_chain_cert_read(ci, fp, chain->file_format,
false);
674 fr_tls_strerror_printf(
"No certificate found");
675 cf_log_perr(ci,
"Failed reading ca_file \"%s\"", chain->ca_files[i]);
678 MEM(sk_X509_push(chain->extra, cert) > 0);
685 fp = fopen(chain->private_key_file,
"r");
687 cf_log_err(ci,
"Failed opening private_key_file \"%s\": %s", chain->private_key_file,
fr_syserror(errno));
690 switch (chain->file_format) {
691 case SSL_FILETYPE_PEM:
692 chain->private_key = PEM_read_PrivateKey(fp, NULL, fr_tls_session_password_cb,
693 UNCONST(
char *, chain->password));
696 case SSL_FILETYPE_ASN1:
697 chain->private_key = d2i_PrivateKey_fp(fp, NULL);
705 if (!chain->private_key) {
706 fr_tls_strerror_printf(NULL);
707 cf_log_perr(ci,
"Failed reading private_key_file \"%s\"", chain->private_key_file);
711 if (X509_check_private_key(chain->leaf, chain->private_key) != 1) {
712 fr_tls_strerror_printf(NULL);
713 cf_log_perr(ci,
"Private key does not match the certificate public key");
723 for (
n = -1;
n < sk_X509_num(chain->extra);
n++) {
726 cert = (
n < 0) ? chain->leaf : sk_X509_value(chain->extra,
n);
728 cf_log_perr(ci,
"Failed parsing notAfter time of certificate %d in the chain",
n + 2);
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define USES_APPLE_DEPRECATED_API
#define DIAG_UNKNOWN_PRAGMAS
#define L(_str)
Helper for initialising arrays of string literals.
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
int cf_pair_parse_value(TALLOC_CTX *ctx, void *out, UNUSED void *base, CONF_ITEM *ci, conf_parser_t const *rule)
Parses a CONF_PAIR into a C data type.
#define CONF_PARSER_TERMINATOR
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
#define FR_CONF_V3_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a deprecated v3 item is found
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_CONF_SUBSECTION_ALLOC_MULTI(_name, _flags, _struct, _field, _subcs)
conf_parser_t which allocates one struct for each instance of a subsection
#define FR_CONF_OFFSET_IS_SET(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct,...
#define FR_CONF_OFFSET_HINT_TYPE(_name, _type, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
@ CONF_FLAG_MULTI
CONF_PAIR can have multiple copies.
@ CONF_FLAG_V3_DEPRECATED
If a matching CONF_PAIR is found, error out with a deprecated message.
@ CONF_FLAG_SECRET
Only print value if debug level >= 3.
@ CONF_FLAG_FILE_READABLE
File matching value must exist, and must be readable.
@ CONF_FLAG_OK_MISSING
OK if it's missing.
@ CONF_FLAG_FILE_EXISTS
File matching value must exist.
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Defines a CONF_PAIR to C data type mapping.
Common header for all CONF_* types.
A section grouping multiple CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_perr(_cf, _fmt,...)
#define cf_log_warn(_cf, _fmt,...)
#define cf_log_debug(_cf, _fmt,...)
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_STRING
String of printable characters.
void fr_rand_buffer(void *start, size_t length)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
An element in a lexicographically sorted array of name to num mappings.
static int talloc_const_free(void const *ptr)
Free const'd memory.
#define fr_unix_time_ispos(_a)
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
#define fr_unix_time_gt(_a, _b)
#define fr_unix_time_wrap(_time)
static fr_unix_time_t fr_unix_time_from_time(time_t time)
Convert a time_t into out internal fr_unix_time_t.
#define fr_time_delta_gt(_a, _b)
A time delta, a difference in time measured in nanoseconds.
int fr_tls_utils_asn1time_to_epoch(time_t *out, ASN1_TIME const *asn1)
Convert OpenSSL's ASN1_TIME to an epoch time.
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
static fr_sbuff_err_t char ** out
#define fr_box_time_delta(_val)
#define fr_box_date(_val)
int virtual_server_cf_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Wrapper for the config parser to allow pass1 resolution of virtual servers.
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.