27 RCSID(
"$Id: 8e13f73c06becd6247ac40679c3359e67570156d $")
31 #define LOG_PREFIX "tls"
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
36 #include <openssl/conf.h>
38 #include <freeradius-devel/server/module.h>
39 #include <freeradius-devel/server/virtual_servers.h>
40 #include <freeradius-devel/util/debug.h>
41 #include <freeradius-devel/util/syserror.h>
42 #include <freeradius-devel/util/rand.h>
53 {
L(
"ASN1"), SSL_FILETYPE_ASN1 },
54 {
L(
"DER"), SSL_FILETYPE_ASN1 },
55 {
L(
"PEM"), SSL_FILETYPE_PEM }
57 static size_t certificate_format_table_len =
NUM_ELEMENTS(certificate_format_table);
60 {
L(
"hard"), FR_TLS_CHAIN_VERIFY_HARD },
61 {
L(
"none"), FR_TLS_CHAIN_VERIFY_NONE },
62 {
L(
"soft"), FR_TLS_CHAIN_VERIFY_SOFT }
64 static size_t chain_verify_mode_table_len =
NUM_ELEMENTS(chain_verify_mode_table);
67 {
L(
"auto"), FR_TLS_CACHE_AUTO },
68 {
L(
"disabled"), FR_TLS_CACHE_DISABLED },
69 {
L(
"stateful"), FR_TLS_CACHE_STATEFUL },
70 {
L(
"stateless"), FR_TLS_CACHE_STATELESS }
72 static size_t cache_mode_table_len =
NUM_ELEMENTS(cache_mode_table);
75 {
L(
"all"), FR_TLS_VERIFY_MODE_ALL },
76 {
L(
"client"), FR_TLS_VERIFY_MODE_LEAF },
77 {
L(
"client-and-issuer"), FR_TLS_VERIFY_MODE_LEAF | FR_TLS_VERIFY_MODE_ISSUER },
78 {
L(
"disabled"), FR_TLS_VERIFY_MODE_DISABLED },
79 {
L(
"untrusted"), FR_TLS_VERIFY_MODE_UNTRUSTED }
81 static size_t verify_mode_table_len =
NUM_ELEMENTS(verify_mode_table);
85 .func = tls_conf_parse_cache_mode,
87 .table = cache_mode_table,
88 .len = &cache_mode_table_len
93 {
FR_CONF_OFFSET(
"lifetime", fr_tls_cache_conf_t, lifetime), .dflt =
"1d" },
95 {
FR_CONF_OFFSET(
"require_extended_master_secret", fr_tls_cache_conf_t, require_extms), .dflt =
"yes" },
96 {
FR_CONF_OFFSET(
"require_perfect_forward_secrecy", fr_tls_cache_conf_t, require_pfs), .dflt =
"no" },
98 {
FR_CONF_OFFSET(
"session_ticket_key", fr_tls_cache_conf_t, session_ticket_key) },
114 .table = certificate_format_table,
115 .len = &certificate_format_table_len
124 {
FR_CONF_OFFSET(
"verify_mode", fr_tls_chain_conf_t, verify_mode),
127 .table = chain_verify_mode_table,
128 .len = &chain_verify_mode_table_len
131 {
FR_CONF_OFFSET(
"include_root_ca", fr_tls_chain_conf_t, include_root_ca), .dflt =
"no" },
139 .table = verify_mode_table,
140 .len = &verify_mode_table_len
143 {
FR_CONF_OFFSET(
"attribute_mode", fr_tls_verify_conf_t, attribute_mode),
146 .table = verify_mode_table,
147 .len = &verify_mode_table_len
149 .dflt =
"client-and-issuer" },
150 {
FR_CONF_OFFSET(
"check_crl", fr_tls_verify_conf_t, check_crl), .dflt =
"no" },
151 {
FR_CONF_OFFSET(
"allow_expired_crl", fr_tls_verify_conf_t, allow_expired_crl) },
152 {
FR_CONF_OFFSET(
"allow_not_yet_valid_crl", fr_tls_verify_conf_t, allow_not_yet_valid_crl) },
160 .subcs_size =
sizeof(fr_tls_chain_conf_t), .subcs_type =
"fr_tls_chain_conf_t", .name2 =
CF_IDENT_ANY },
167 {
FR_CONF_OFFSET(
"verify_depth", fr_tls_conf_t, verify_depth), .dflt =
"0" },
171 #ifdef PSK_MAX_IDENTITY_LEN
179 {
FR_CONF_OFFSET(
"fragment_size", fr_tls_conf_t, fragment_size), .dflt =
"1024" },
180 {
FR_CONF_OFFSET(
"padding", fr_tls_conf_t, padding_block_size), },
182 {
FR_CONF_OFFSET(
"disable_single_dh_use", fr_tls_conf_t, disable_single_dh_use) },
185 {
FR_CONF_OFFSET(
"cipher_server_preference", fr_tls_conf_t, cipher_server_preference), .dflt =
"yes" },
186 #ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS
187 {
FR_CONF_OFFSET(
"allow_renegotiation", fr_tls_conf_t, allow_renegotiation), .dflt =
"no" },
190 #ifndef OPENSSL_NO_ECDH
191 {
FR_CONF_OFFSET(
"ecdh_curve", fr_tls_conf_t, ecdh_curve), .dflt =
"prime256v1" },
193 {
FR_CONF_OFFSET(
"tls_max_version", fr_tls_conf_t, tls_max_version) },
195 {
FR_CONF_OFFSET(
"tls_min_version", fr_tls_conf_t, tls_min_version), .dflt =
"1.2" },
208 .subcs_size =
sizeof(fr_tls_chain_conf_t), .subcs_type =
"fr_tls_chain_conf_t" },
215 #ifdef PSK_MAX_IDENTITY_LEN
222 {
FR_CONF_OFFSET(
"verify_depth", fr_tls_conf_t, verify_depth), .dflt =
"0" },
228 {
FR_CONF_OFFSET(
"fragment_size", fr_tls_conf_t, fragment_size), .dflt =
"1024" },
232 #ifndef OPENSSL_NO_ECDH
233 {
FR_CONF_OFFSET(
"ecdh_curve", fr_tls_conf_t, ecdh_curve), .dflt =
"prime256v1" },
236 {
FR_CONF_OFFSET(
"tls_max_version", fr_tls_conf_t, tls_max_version) },
238 {
FR_CONF_OFFSET(
"tls_min_version", fr_tls_conf_t, tls_min_version), .dflt =
"1.2" },
247 fr_tls_conf_t *
conf = talloc_get_type_abort((
uint8_t *)
parent - offsetof(fr_tls_conf_t, cache), fr_tls_conf_t);
257 switch (cache_mode) {
258 case FR_TLS_CACHE_DISABLED:
259 case FR_TLS_CACHE_STATELESS:
262 case FR_TLS_CACHE_STATEFUL:
263 if (!
conf->virtual_server) {
264 cf_log_err(ci,
"A virtual_server must be set when cache.mode = \"stateful\"");
270 cf_log_err(ci,
"Specified virtual_server must contain a \"load session { ... }\" section "
271 "when cache.mode = \"stateful\"");
276 cf_log_err(ci,
"Specified virtual_server must contain a \"store session { ... }\" section "
277 "when cache.mode = \"stateful\"");
282 cf_log_err(ci,
"Specified virtual_server must contain a \"clear session { ... }\" section "
283 "when cache.mode = \"stateful\"");
287 if (
conf->tls_min_version >= (
float)1.3) {
288 cf_log_err(ci,
"cache.mode = \"stateful\" is not supported with tls_min_version >= 1.3");
293 case FR_TLS_CACHE_AUTO:
294 if (!
conf->virtual_server) {
295 WARN(
"A virtual_server must be provided for stateful caching. "
296 "cache.mode = \"auto\" rewritten to cache.mode = \"stateless\"");
298 cache_mode = FR_TLS_CACHE_STATELESS;
303 cf_log_warn(ci,
"Specified virtual_server missing \"load session { ... }\" section. "
304 "cache.mode = \"auto\" rewritten to cache.mode = \"stateless\"");
305 goto cache_stateless;
309 cf_log_warn(ci,
"Specified virtual_server missing \"store session { ... }\" section. "
310 "cache.mode = \"auto\" rewritten to cache.mode = \"stateless\"");
311 goto cache_stateless;
315 cf_log_warn(ci,
"Specified virtual_server missing \"clear cache { ... }\" section. "
316 "cache.mode = \"auto\" rewritten to cache.mode = \"stateless\"");
317 goto cache_stateless;
320 if (
conf->tls_min_version >= (
float)1.3) {
321 cf_log_err(ci,
"stateful session-resumption is not supported with tls_min_version >= 1.3. "
322 "cache.mode = \"auto\" rewritten to cache.mode = \"stateless\"");
331 if (cache_mode & FR_TLS_CACHE_STATELESS) {
336 if (!
conf->cache.session_ticket_key) {
339 talloc_array_length(
conf->cache.session_ticket_key));
343 *((
int *)
out) = cache_mode;
354 static char const *special_string =
"Apple:UsecertAdmin";
359 static int conf_cert_admin_password(fr_tls_conf_t *
conf)
363 if (!
conf->chains)
return 0;
365 cnt = talloc_array_length(
conf->chains);
366 for (i = 0; i < cnt; i++) {
369 long const max_password_len = 128;
372 if (!
conf->chains[i]->password)
continue;
374 if (strncmp(
conf->chains[i]->password, special_string, strlen(special_string)) != 0)
continue;
376 snprintf(cmd,
sizeof(cmd) - 1,
"/usr/sbin/certadmin --get-private-key-passphrase \"%s\"",
377 conf->chains[i]->private_key_file);
379 DEBUG2(
"Getting private key passphrase using command \"%s\"", cmd);
381 cmd_pipe = popen(cmd,
"r");
383 ERROR(
"%s command failed: Unable to get private_key_password", cmd);
384 ERROR(
"Error reading private_key_file %s",
conf->chains[i]->private_key_file);
388 password = talloc_array(
conf,
char, max_password_len);
390 ERROR(
"Can't allocate space for private_key_password");
391 ERROR(
"Error reading private_key_file %s",
conf->chains[i]->private_key_file);
396 fgets(password, max_password_len, cmd_pipe);
400 password[strlen(password) - 1] =
'\0';
402 DEBUG3(
"Password from command = \"%s\"", password);
404 conf->chains[i]->password = password;
411 #ifdef HAVE_OPENSSL_OCSP_H
419 static X509_STORE *conf_ocsp_revocation_store(fr_tls_conf_t *
conf)
421 X509_STORE *
store = NULL;
423 store = X509_STORE_new();
427 if (!X509_STORE_load_locations(
store,
conf->ca_file,
conf->ca_path)) {
428 fr_tls_log(NULL,
"Error reading Trusted root CA list \"%s\"",
conf->ca_file);
429 X509_STORE_free(
store);
433 #ifdef X509_V_FLAG_CRL_CHECK_ALL
434 if (
conf->verify.check_crl) X509_STORE_set_flags(
store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
453 fr_tls_conf_t *fr_tls_conf_alloc(TALLOC_CTX *ctx)
457 MEM(
conf = talloc_zero(ctx, fr_tls_conf_t));
463 fr_tls_conf_t *fr_tls_conf_parse_server(
CONF_SECTION *cs)
473 DEBUG(
"Using cached TLS configuration from previous invocation");
479 conf = fr_tls_conf_alloc(cs);
493 if (
conf->fragment_size < 100)
conf->fragment_size = 100;
498 if (conf_cert_admin_password(
conf) < 0)
goto error;
509 fr_tls_conf_t *fr_tls_conf_parse_client(
CONF_SECTION *cs)
515 DEBUG2(
"Using cached TLS configuration from previous invocation");
521 conf = fr_tls_conf_alloc(cs);
535 if (
conf->fragment_size < 100)
conf->fragment_size = 100;
541 if (conf_cert_admin_password(
conf) < 0)
goto error;
#define store(_store, _var)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define USES_APPLE_DEPRECATED_API
#define L(_str)
Helper for initialising arrays of string literals.
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
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_section_parse_pass2(void *base, CONF_SECTION *cs)
Fixup xlat expansions and attributes.
#define CONF_PARSER_TERMINATOR
#define FR_CONF_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR is found
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
#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 cf_section_rules_push(_cs, _rule)
#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_SECRET
Only print value if debug level >= 3.
@ CONF_FLAG_FILE_INPUT
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.
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
#define cf_log_err(_cf, _fmt,...)
#define cf_data_add(_cf, _data, _name, _free)
#define cf_data_find(_cf, _type, _name)
#define cf_log_warn(_cf, _fmt,...)
static int _conf_server_free(fr_tls_conf_t *conf)
void fr_rand_buffer(void *start, size_t length)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
An element in a lexicographically sorted array of name to num mappings.
static int talloc_const_free(void const *ptr)
Free const'd memory.
static size_t char ** out
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.