#ifdef HAVE_UTIME_H
#include <utime.h>
#endif
+#include <ctype.h>
#ifdef WITH_TLS
#ifdef HAVE_OPENSSL_RAND_H
unsigned int size);
#ifdef PSK_MAX_IDENTITY_LEN
-static unsigned int psk_server_callback(SSL *ssl, char const *identity,
+static bool identity_is_safe(const char *identity)
+{
+ char c;
+
+ if (!identity) return true;
+
+ while ((c = *(identity++)) != '\0') {
+ if (isalpha((int) c) || isdigit((int) c) || isspace((int) c) ||
+ (c == '@') || (c == '-') || (c == '_') || (c == '.')) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+
+/*
+ * When a client uses TLS-PSK to talk to a server, this callback
+ * is used by the server to determine the PSK to use.
+ */
+static unsigned int psk_server_callback(SSL *ssl, const char *identity,
unsigned char *psk,
unsigned int max_psk_len)
{
- unsigned int psk_len;
+ unsigned int psk_len = 0;
fr_tls_server_conf_t *conf;
+ REQUEST *request;
conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl,
FR_TLS_EX_INDEX_CONF);
if (!conf) return 0;
+ request = (REQUEST *)SSL_get_ex_data(ssl,
+ FR_TLS_EX_INDEX_REQUEST);
+ if (request && conf->psk_query) {
+ size_t hex_len;
+ VALUE_PAIR *vp;
+ char buffer[2 * PSK_MAX_PSK_LEN + 4]; /* allow for too-long keys */
+
+ /*
+ * The passed identity is weird. Deny it.
+ */
+ if (!identity_is_safe(identity)) {
+ RWDEBUG("Invalid characters in PSK identity %s", identity);
+ return 0;
+ }
+
+ vp = pairmake_packet("TLS-PSK-Identity", identity, T_OP_SET);
+ if (!vp) return 0;
+
+ hex_len = radius_xlat(buffer, sizeof(buffer), request, conf->psk_query,
+ NULL, NULL);
+ if (!hex_len) {
+ RWDEBUG("PSK expansion returned an empty string.");
+ return 0;
+ }
+
+ /*
+ * The returned key is truncated at MORE than
+ * OpenSSL can handle. That way we can detect
+ * the truncation, and complain about it.
+ */
+ if (hex_len > (2 * max_psk_len)) {
+ RWDEBUG("Returned PSK is too long (%u > %u)",
+ (unsigned int) hex_len, 2 * max_psk_len);
+ return 0;
+ }
+
+ /*
+ * Leave the TLS-PSK-Identity in the request, and
+ * convert the expansion from printable string
+ * back to hex.
+ */
+ return fr_hex2bin(psk, max_psk_len, buffer, hex_len);
+ }
+
/*
- * FIXME: Look up the PSK password based on the identity!
+ * No REQUEST, or no dynamic query. Just look for a
+ * static identity.
*/
if (strcmp(identity, conf->psk_identity) != 0) {
+ ERROR("Supplied PSK identity %s does not match configuration. Rejecting.",
+ identity);
return 0;
}
psk_len = strlen(conf->psk_password);
if (psk_len > (2 * max_psk_len)) return 0;
- return fr_hex2bin(psk, conf->psk_password, psk_len);
+ return fr_hex2bin(psk, max_psk_len, conf->psk_password, psk_len);
}
static unsigned int psk_client_callback(SSL *ssl, UNUSED char const *hint,
strlcpy(identity, conf->psk_identity, max_identity_len);
- return fr_hex2bin(psk, conf->psk_password, psk_len);
+ return fr_hex2bin(psk, max_psk_len, conf->psk_password, psk_len);
}
#endif
{
int verify_mode;
tls_session_t *ssn = NULL;
+ REQUEST *request;
ssn = talloc_zero(conf, tls_session_t);
if (!ssn) return NULL;
SSL_CTX_set_mode(ssn->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY);
ssn->ssl = SSL_new(ssn->ctx);
- rad_assert(ssn->ssl != NULL);
+ if (!ssn->ssl) {
+ talloc_free(ssn);
+ return NULL;
+ }
+
+ request = request_alloc(ssn);
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_REQUEST, (void *)request);
/*
* Add the message callback to identify what type of
if (SSL_connect(ssn->ssl) <= 0) {
int err;
while ((err = ERR_get_error())) {
- DEBUG("OpenSSL Err says %s",
- ERR_error_string(err, NULL));
+ ERROR("tls: %s", ERR_error_string(err, NULL));
}
SSL_free(ssn->ssl);
talloc_free(ssn);
+
return NULL;
}
return ssn;
}
-tls_session_t *tls_new_session(fr_tls_server_conf_t *conf, REQUEST *request,
- int client_cert)
+static int _tls_session_free(tls_session_t *ssn)
+{
+ /*
+ * Free any opaque TTLS or PEAP data.
+ */
+ if ((ssn->opaque) && (ssn->free_opaque)) {
+ ssn->free_opaque(ssn->opaque);
+ ssn->opaque = NULL;
+ }
+
+ session_close(ssn);
+
+ return 0;
+}
+
+tls_session_t *tls_new_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, REQUEST *request, bool client_cert)
{
tls_session_t *state = NULL;
SSL *new_tls = NULL;
* FIXME: Also do it every N sessions?
*/
if (conf->session_cache_enable &&
- ((conf->session_last_flushed + (conf->session_timeout * 1800)) <= request->timestamp)){
+ ((conf->session_last_flushed + ((int)conf->session_timeout * 1800)) <= request->timestamp)){
RDEBUG2("Flushing SSL sessions (of #%ld)",
SSL_CTX_sess_number(conf->ctx));
/* We use the SSL's "app_data" to indicate a call-back */
SSL_set_app_data(new_tls, NULL);
- state = talloc_zero(conf, tls_session_t);
+ state = talloc_zero(ctx, tls_session_t);
session_init(state);
+ talloc_set_destructor(state, _tls_session_free);
state->ctx = conf->ctx;
state->ssl = new_tls;
session_init(ssn);
}
-void session_free(void *ssn)
-{
- tls_session_t *sess = (tls_session_t *)ssn;
-
- if (!ssn) return;
-
- /*
- * Free any opaque TTLS or PEAP data.
- */
- if ((sess->opaque) && (sess->free_opaque)) {
- sess->free_opaque(sess->opaque);
- sess->opaque = NULL;
- }
-
- session_close(sess);
-
- talloc_free(sess);
-}
-
static void record_init(record_t *rec)
{
rec->used = 0;
str_details1, str_details2);
request = SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST);
-
- RDEBUG2("%s\n", tls_session->info.info_description);
+ if (request) {
+ RDEBUG2("%s", tls_session->info.info_description);
+ } else {
+ DEBUG2("%s", tls_session->info.info_description);
+ }
}
static CONF_PARSER cache_config[] = {
- { "enable", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, session_cache_enable), NULL, "no" },
- { "lifetime", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, session_timeout), NULL, "24" },
- { "max_entries", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, session_cache_size), NULL, "255" },
- { "name", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, session_id_name), NULL, NULL},
- { "persist_dir", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, session_cache_path), NULL, NULL},
+ { "enable", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, session_cache_enable), "no" },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, session_timeout), "24" },
+ { "max_entries", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, session_cache_size), "255" },
+ { "name", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, session_id_name), NULL },
+ { "persist_dir", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, session_cache_path), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
static CONF_PARSER verify_config[] = {
- { "tmpdir", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, verify_tmp_dir), NULL, NULL},
- { "client", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, verify_client_cert_cmd), NULL, NULL},
+ { "tmpdir", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, verify_tmp_dir), NULL },
+ { "client", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, verify_client_cert_cmd), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
#ifdef HAVE_OPENSSL_OCSP_H
static CONF_PARSER ocsp_config[] = {
- { "enable", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, ocsp_enable), NULL, "no"},
- { "override_cert_url", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, ocsp_override_url), NULL, "no"},
- { "url", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, ocsp_url), NULL, NULL },
- { "use_nonce", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, ocsp_use_nonce), NULL, "yes"},
- { "timeout", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, ocsp_timeout), NULL, "yes"},
- { "softfail", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, ocsp_softfail), NULL, "yes"},
+ { "enable", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_enable), "no" },
+ { "override_cert_url", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_override_url), "no" },
+ { "url", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, ocsp_url), NULL },
+ { "use_nonce", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_use_nonce), "yes" },
+ { "timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, ocsp_timeout), "yes" },
+ { "softfail", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_softfail), "yes" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
#endif
static CONF_PARSER tls_server_config[] = {
- { "rsa_key_exchange", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, rsa_key), NULL, "no" },
- { "dh_key_exchange", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, dh_key), NULL, "yes" },
- { "rsa_key_length", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, rsa_key_length), NULL, "512" },
- { "dh_key_length", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, dh_key_length), NULL, "512" },
- { "verify_depth", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, verify_depth), NULL, "0" },
- { "CA_path", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED,
- offsetof(fr_tls_server_conf_t, ca_path), NULL, NULL },
- { "ca_path", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, ca_path), NULL, NULL },
- { "pem_file_type", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, file_type), NULL, "yes" },
- { "private_key_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, private_key_file), NULL, NULL },
- { "certificate_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, certificate_file), NULL, NULL },
- { "CA_file", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED,
- offsetof(fr_tls_server_conf_t, ca_file), NULL, NULL },
- { "ca_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, ca_file), NULL, NULL },
- { "private_key_password", PW_TYPE_STRING_PTR | PW_TYPE_SECRET,
- offsetof(fr_tls_server_conf_t, private_key_password), NULL, NULL },
+ { "rsa_key_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, rsa_key), "no" },
+ { "dh_key_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, dh_key), "yes" },
+ { "rsa_key_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, rsa_key_length), "512" },
+ { "dh_key_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, dh_key_length), "512" },
+ { "verify_depth", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, verify_depth), "0" },
+ { "CA_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, fr_tls_server_conf_t, ca_path), NULL },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_path), NULL },
+ { "pem_file_type", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, file_type), "yes" },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, private_key_file), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, certificate_file), NULL },
+ { "CA_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, fr_tls_server_conf_t, ca_file), NULL },
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_file), NULL },
+ { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, fr_tls_server_conf_t, private_key_password), NULL },
#ifdef PSK_MAX_IDENTITY_LEN
- { "psk_identity", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, psk_identity), NULL, NULL },
- { "psk_hexphrase", PW_TYPE_STRING_PTR | PW_TYPE_SECRET,
- offsetof(fr_tls_server_conf_t, psk_password), NULL, NULL },
+ { "psk_identity", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, psk_identity), NULL },
+ { "psk_hexphrase", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, fr_tls_server_conf_t, psk_password), NULL },
+ { "psk_query", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, psk_query), NULL },
#endif
- { "dh_file", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, dh_file), NULL, NULL },
- { "random_file", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, random_file), NULL, NULL },
- { "fragment_size", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, fragment_size), NULL, "1024" },
- { "include_length", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, include_length), NULL, "yes" },
- { "check_crl", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, check_crl), NULL, "no"},
- { "allow_expired_crl", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, allow_expired_crl), NULL, NULL},
- { "check_cert_cn", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, check_cert_cn), NULL, NULL},
- { "cipher_list", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, cipher_list), NULL, NULL},
- { "check_cert_issuer", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, check_cert_issuer), NULL, NULL},
- { "require_client_cert", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, require_client_cert), NULL, NULL },
+ { "dh_file", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, dh_file), NULL },
+ { "random_file", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, random_file), NULL },
+ { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, fragment_size), "1024" },
+ { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, include_length), "yes" },
+ { "check_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, check_crl), "no" },
+ { "allow_expired_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, allow_expired_crl), NULL },
+ { "check_cert_cn", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_cn), NULL },
+ { "cipher_list", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, cipher_list), NULL },
+ { "check_cert_issuer", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_issuer), NULL },
+ { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, require_client_cert), NULL },
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
- { "ecdh_curve", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, ecdh_curve), NULL, "prime256v1"},
+ { "ecdh_curve", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, ecdh_curve), "prime256v1" },
#endif
#endif
- { "cache", PW_TYPE_SUBSECTION, 0, NULL, (void const *) cache_config },
+ { "cache", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) cache_config },
- { "verify", PW_TYPE_SUBSECTION, 0, NULL, (void const *) verify_config },
+ { "verify", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) verify_config },
#ifdef HAVE_OPENSSL_OCSP_H
- { "ocsp", PW_TYPE_SUBSECTION, 0, NULL, (void const *) ocsp_config },
+ { "ocsp", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) ocsp_config },
#endif
{ NULL, -1, 0, NULL, NULL } /* end the list */
static CONF_PARSER tls_client_config[] = {
- { "rsa_key_exchange", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, rsa_key), NULL, "no" },
- { "dh_key_exchange", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, dh_key), NULL, "yes" },
- { "rsa_key_length", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, rsa_key_length), NULL, "512" },
- { "dh_key_length", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, dh_key_length), NULL, "512" },
- { "verify_depth", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, verify_depth), NULL, "0" },
- { "ca_path", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, ca_path), NULL, NULL },
- { "pem_file_type", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, file_type), NULL, "yes" },
- { "private_key_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, private_key_file), NULL, NULL },
- { "certificate_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, certificate_file), NULL, NULL },
- { "ca_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, ca_file), NULL, NULL },
- { "private_key_password", PW_TYPE_STRING_PTR | PW_TYPE_SECRET,
- offsetof(fr_tls_server_conf_t, private_key_password), NULL, NULL },
- { "dh_file", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, dh_file), NULL, NULL },
- { "random_file", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, random_file), NULL, NULL },
- { "fragment_size", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, fragment_size), NULL, "1024" },
- { "include_length", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, include_length), NULL, "yes" },
- { "check_crl", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, check_crl), NULL, "no"},
- { "check_cert_cn", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, check_cert_cn), NULL, NULL},
- { "cipher_list", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, cipher_list), NULL, NULL},
- { "check_cert_issuer", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, check_cert_issuer), NULL, NULL},
+ { "rsa_key_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, rsa_key), "no" },
+ { "dh_key_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, dh_key), "yes" },
+ { "rsa_key_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, rsa_key_length), "512" },
+ { "dh_key_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, dh_key_length), "512" },
+ { "verify_depth", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, verify_depth), "0" },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_path), NULL },
+ { "pem_file_type", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, file_type), "yes" },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, private_key_file), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, certificate_file), NULL },
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_file), NULL },
+ { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, fr_tls_server_conf_t, private_key_password), NULL },
+ { "dh_file", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, dh_file), NULL },
+ { "random_file", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, random_file), NULL },
+ { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, fragment_size), "1024" },
+ { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, include_length), "yes" },
+ { "check_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, check_crl), "no" },
+ { "check_cert_cn", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_cn), NULL },
+ { "cipher_list", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, cipher_list), NULL },
+ { "check_cert_issuer", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_issuer), NULL },
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
- { "ecdh_curve", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, ecdh_curve), NULL, "prime256v1"},
+ { "ecdh_curve", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, ecdh_curve), "prime256v1" },
#endif
#endif
return 0;
}
+
+ /* Do not convert to TALLOC - Thread safety */
/* alloc and convert to ASN.1 */
- sess_blob = talloc_array(conf, unsigned char, blob_len);
+ sess_blob = malloc(blob_len);
if (!sess_blob) {
DEBUG2(" SSL: could not allocate buffer len=%d to persist session", blob_len);
return 0;
}
error:
- if (sess_blob) talloc_free(sess_blob);
+ free(sess_blob);
return 0;
}
*/
/* Get OCSP responder URL */
- if(conf->ocsp_override_url) {
- OCSP_parse_url(conf->ocsp_url, &host, &port, &path, &use_ssl);
+ if (conf->ocsp_override_url) {
+ char *url;
+
+ memcpy(&url, &conf->ocsp_url, sizeof(url));
+ /* Reading the libssl src, they do a strdup on the URL, so it could of been const *sigh* */
+ OCSP_parse_url(url, &host, &port, &path, &use_ssl);
}
else {
ocsp_parse_cert_url(client_cert, &host, &port, &path, &use_ssl);
if (!conf) return 1;
request = (REQUEST *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
-
- if (!request) return 1; /* FIXME: outbound TLS */
-
rad_assert(request != NULL);
certs = (VALUE_PAIR **)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CERTS);
- rad_assert(certs != NULL);
+
identity = (char **)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_IDENTITY);
#ifdef HAVE_OPENSSL_OCSP_H
ocsp_store = (X509_STORE *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_STORE);
* have a user identity. i.e. we don't create the
* attributes for RadSec connections.
*/
- if (identity &&
+ if (certs && identity &&
(lookup <= 1) && sn && ((size_t) sn->length < (sizeof(buf) / 2))) {
char *p = buf;
int i;
*/
buf[0] = '\0';
asn_time = X509_get_notAfter(client_cert);
- if (identity && (lookup <= 1) && asn_time &&
+ if (certs && identity && (lookup <= 1) && asn_time &&
(asn_time->length < (int) sizeof(buf))) {
memcpy(buf, (char*) asn_time->data, asn_time->length);
buf[asn_time->length] = '\0';
X509_NAME_oneline(X509_get_subject_name(client_cert), subject,
sizeof(subject));
subject[sizeof(subject) - 1] = '\0';
- if (identity && (lookup <= 1) && subject[0]) {
+ if (certs && identity && (lookup <= 1) && subject[0]) {
pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_SUBJECT][lookup], subject, T_OP_SET);
}
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), issuer,
sizeof(issuer));
issuer[sizeof(issuer) - 1] = '\0';
- if (identity && (lookup <= 1) && issuer[0]) {
+ if (certs && identity && (lookup <= 1) && issuer[0]) {
pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_ISSUER][lookup], issuer, T_OP_SET);
}
X509_NAME_get_text_by_NID(X509_get_subject_name(client_cert),
NID_commonName, common_name, sizeof(common_name));
common_name[sizeof(common_name) - 1] = '\0';
- if (identity && (lookup <= 1) && common_name[0] && subject[0]) {
+ if (certs && identity && (lookup <= 1) && common_name[0] && subject[0]) {
pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_CN][lookup], common_name, T_OP_SET);
}
* Get the RFC822 Subject Alternative Name
*/
loc = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0);
- if (lookup <= 1 && loc >= 0) {
+ if (certs && (lookup <= 1) && (loc >= 0)) {
X509_EXTENSION *ext = NULL;
GENERAL_NAMES *names = NULL;
int i;
pairfree(certs);
}
-/*
- * Add all the default ciphers and message digests
- * Create our context.
+/** Add all the default ciphers and message digests reate our context.
*
- * This should be called exactly once from main.
+ * This should be called exactly once from main, before reading the main config
+ * or initialising any modules.
*/
-int tls_global_init(char const *acknowledged)
+void tls_global_init(void)
{
- uint64_t v;
-
SSL_load_error_strings(); /* readable error messages (examples show call before library_init) */
SSL_library_init(); /* initialize library */
OpenSSL_add_all_algorithms(); /* required for SHA2 in OpenSSL < 0.9.8o and 1.0.0.a */
OPENSSL_config(NULL);
+}
+
+/** Check for vulnerable versions of libssl
+ *
+ * @param acknowledged The highest CVE number a user has confirmed is not present in the system's libssl.
+ * @return 0 if the CVE specified by the user matches the most recent CVE we have, else -1.
+ */
+int tls_global_version_check(char const *acknowledged)
+{
+ uint64_t v;
if ((strcmp(acknowledged, libssl_defects[0].id) != 0) && (strcmp(acknowledged, "yes") != 0)) {
bool bad = false;
return 0;
}
-void tls_global_remove(void)
+/** Free any memory alloced by libssl
+ *
+ */
+void tls_global_cleanup(void)
{
ERR_remove_state(0);
ENGINE_cleanup();
* - Load the Private key & the certificate
* - Set the Context options & Verify options
*/
-static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf, int client)
+static SSL_CTX *tls_init_ctx(fr_tls_server_conf_t *conf, int client)
{
SSL_CTX *ctx;
X509_STORE *certstore;
* programmatically.
*/
char const* special_string = "Apple:UseCertAdmin";
- if (strncmp(conf->private_key_password,
- special_string,
- strlen(special_string)) == 0)
- {
+ if (strncmp(conf->private_key_password, special_string, strlen(special_string)) == 0) {
char cmd[256];
+ char *password;
long const max_password_len = 128;
- snprintf(cmd, sizeof(cmd) - 1,
- "/usr/sbin/certadmin --get-private-key-passphrase \"%s\"",
- conf->private_key_file);
+ snprintf(cmd, sizeof(cmd) - 1, "/usr/sbin/certadmin --get-private-key-passphrase \"%s\"",
+ conf->private_key_file);
DEBUG2("tls: Getting private key passphrase using command \"%s\"", cmd);
return NULL;
}
- talloc_free(conf->private_key_password);
- conf->private_key_password = talloc_array(conf, char, max_password_len);
- if (!conf->private_key_password) {
+ rad_const_free(conf->private_key_password);
+ password = talloc_array(conf, char, max_password_len);
+ if (!password) {
ERROR("TLS: Can't allocate space for private_key_password");
ERROR("TLS: Error reading private_key_file %s", conf->private_key_file);
pclose(cmd_pipe);
return NULL;
}
- fgets(conf->private_key_password, max_password_len, cmd_pipe);
+ fgets(password, max_password_len, cmd_pipe);
pclose(cmd_pipe);
/* Get rid of newline at end of password. */
- conf->private_key_password[strlen(conf->private_key_password) - 1] = '\0';
+ password[strlen(password) - 1] = '\0';
- DEBUG3("tls: Password from command = \"%s\"", conf->private_key_password);
+ DEBUG3("tls: Password from command = \"%s\"", password);
+ conf->private_key_password = password;
}
#endif
- SSL_CTX_set_default_passwd_cb_userdata(ctx, conf->private_key_password);
- SSL_CTX_set_default_passwd_cb(ctx, cbtls_password);
+
+ {
+ char *password;
+
+ memcpy(&password, &conf->private_key_password, sizeof(password));
+ SSL_CTX_set_default_passwd_cb_userdata(ctx, password);
+ SSL_CTX_set_default_passwd_cb(ctx, cbtls_password);
+ }
}
#ifdef PSK_MAX_IDENTITY_LEN
+ if (!client) {
+ /*
+ * No dynamic query exists. There MUST be a
+ * statically configured identity and password.
+ */
+ if (conf->psk_query && !*conf->psk_query) {
+ ERROR("Invalid PSK Configuration: psk_query cannot be empty");
+ return NULL;
+ }
+
+ SSL_CTX_set_psk_server_callback(ctx, psk_server_callback);
+
+ } else if (conf->psk_query) {
+ ERROR("Invalid PSK Configuration: psk_query cannot be used for outgoing connections");
+ return NULL;
+ }
+
+ /*
+ * Now check that if PSK is being used, the config is valid.
+ */
if ((conf->psk_identity && !conf->psk_password) ||
(!conf->psk_identity && conf->psk_password) ||
(conf->psk_identity && !*conf->psk_identity) ||
if (conf->psk_identity) {
size_t psk_len, hex_len;
- char buffer[PSK_MAX_PSK_LEN];
+ uint8_t buffer[PSK_MAX_PSK_LEN];
if (conf->certificate_file ||
conf->private_key_password || conf->private_key_file ||
if (client) {
SSL_CTX_set_psk_client_callback(ctx,
psk_client_callback);
- } else {
- SSL_CTX_set_psk_server_callback(ctx,
- psk_server_callback);
}
psk_len = strlen(conf->psk_password);
return NULL;
}
- hex_len = fr_hex2bin((uint8_t *) buffer, conf->psk_password, psk_len);
+ /*
+ * Check the password now, so that we don't have
+ * errors at run-time.
+ */
+ hex_len = fr_hex2bin(buffer, sizeof(buffer), conf->psk_password, psk_len);
if (psk_len != (2 * hex_len)) {
ERROR("psk_hexphrase is not all hex");
return NULL;
*/
#ifdef X509_V_FLAG_CRL_CHECK
if (conf->check_crl) {
- certstore = SSL_CTX_get_cert_store(ctx);
- if (certstore == NULL) {
- ERROR("tls: SSL error %s", ERR_error_string(ERR_get_error(), NULL));
- ERROR("tls: Error reading Certificate Store");
- return NULL;
- }
- X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
+ certstore = SSL_CTX_get_cert_store(ctx);
+ if (certstore == NULL) {
+ ERROR("tls: SSL error %s", ERR_error_string(ERR_get_error(), NULL));
+ ERROR("tls: Error reading Certificate Store");
+ return NULL;
+ }
+ X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
}
#endif
* added to automatically free the data when the CONF_SECTION
* is freed.
*/
-static int tls_server_conf_free(fr_tls_server_conf_t *conf)
+static int _tls_server_conf_free(fr_tls_server_conf_t *conf)
{
if (conf->ctx) SSL_CTX_free(conf->ctx);
return 0;
}
+static fr_tls_server_conf_t *tls_server_conf_alloc(TALLOC_CTX *ctx)
+{
+ fr_tls_server_conf_t *conf;
+
+ conf = talloc_zero(ctx, fr_tls_server_conf_t);
+ if (!conf) {
+ ERROR("Out of memory");
+ return NULL;
+ }
+
+ talloc_set_destructor(conf, _tls_server_conf_free);
+
+ return conf;
+}
+
fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs)
{
return conf;
}
- conf = talloc_zero(cs, fr_tls_server_conf_t);
- if (!conf) {
- ERROR("Out of memory");
- return NULL;
- }
-
- talloc_set_destructor(conf, tls_server_conf_free);
+ conf = tls_server_conf_alloc(cs);
if (cf_section_parse(cs, conf, tls_server_config) < 0) {
error:
/*
* Initialize TLS
*/
- conf->ctx = init_tls_ctx(conf, 0);
+ conf->ctx = tls_init_ctx(conf, 0);
if (conf->ctx == NULL) {
goto error;
}
if (conf->ocsp_store == NULL) goto error;
}
#endif /*HAVE_OPENSSL_OCSP_H*/
+ {
+ char *dh_file;
- if (load_dh_params(conf->ctx, conf->dh_file) < 0) {
- goto error;
+ memcpy(&dh_file, &conf->dh_file, sizeof(dh_file));
+ if (load_dh_params(conf->ctx, dh_file) < 0) {
+ goto error;
+ }
}
if (generate_eph_rsa_key(conf->ctx) < 0) {
return conf;
}
- conf = talloc_zero(cs, fr_tls_server_conf_t);
- if (!conf) {
- ERROR("Out of memory");
- return NULL;
- }
-
- talloc_set_destructor(conf, tls_server_conf_free);
+ conf = tls_server_conf_alloc(cs);
if (cf_section_parse(cs, conf, tls_client_config) < 0) {
error:
/*
* Initialize TLS
*/
- conf->ctx = init_tls_ctx(conf, 1);
+ conf->ctx = tls_init_ctx(conf, 1);
if (conf->ctx == NULL) {
goto error;
}
- if (load_dh_params(conf->ctx, conf->dh_file) < 0) {
- goto error;
+ {
+ char *dh_file;
+
+ memcpy(&dh_file, &conf->dh_file, sizeof(dh_file));
+ if (load_dh_params(conf->ctx, dh_file) < 0) {
+ goto error;
+ }
}
if (generate_eph_rsa_key(conf->ctx) < 0) {
paircopyvp(request->packet, vp));
} else {
pairadd(&request->reply->vps,
- paircopyvp(request->packet, vp));
+ paircopyvp(request->reply, vp));
}
}