X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Ftls.c;h=5ac8fc1af1ddf5d4539cf414aff32fcd6a121219;hb=92e1ccbd1216421ba5de341120a5cc3f0759762a;hp=f6c210ca71e158e548ca497c22fc04dded2b23d9;hpb=fcf39a039da6beacc2f21d5e876cb304a29a3115;p=freeradius.git diff --git a/src/main/tls.c b/src/main/tls.c index f6c210c..5ac8fc1 100644 --- a/src/main/tls.c +++ b/src/main/tls.c @@ -505,6 +505,7 @@ tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *con talloc_set_destructor(ssn, _tls_session_free); ssn->ctx = conf->ctx; + ssn->mtu = conf->fragment_size; SSL_CTX_set_mode(ssn->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY); @@ -537,6 +538,21 @@ tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *con SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_SSN, (void *)ssn); SSL_set_fd(ssn->ssl, fd); ret = SSL_connect(ssn->ssl); + + if (ret < 0) { + switch (SSL_get_error(ssn->ssl, ret)) { + default: + break; + + + + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + ssn->connected = false; + return ssn; + } + } + if (ret <= 0) { tls_error_io_log(NULL, ssn, ret, "Failed in " STRINGIFY(__FUNCTION__) " (SSL_connect)"); talloc_free(ssn); @@ -544,12 +560,10 @@ tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *con return NULL; } - ssn->mtu = conf->fragment_size; - + ssn->connected = true; return ssn; } - /** Create a new TLS session * * Configures a new TLS session, configuring options, setting callbacks etc... @@ -823,10 +837,10 @@ static void session_init(tls_session_t *ssn) static void session_close(tls_session_t *ssn) { - SSL_set_quiet_shutdown(ssn->ssl, 1); - SSL_shutdown(ssn->ssl); - if (ssn->ssl) { + SSL_set_quiet_shutdown(ssn->ssl, 1); + SSL_shutdown(ssn->ssl); + SSL_free(ssn->ssl); ssn->ssl = NULL; } @@ -1382,7 +1396,7 @@ static int cbtls_new_session(SSL *ssl, SSL_SESSION *sess) /* open output file */ snprintf(filename, sizeof(filename), "%s%c%s.asn1", conf->session_cache_path, FR_DIR_SEP, buffer); - fd = open(filename, O_RDWR|O_CREAT|O_EXCL, 0600); + fd = open(filename, O_RDWR|O_CREAT|O_EXCL, S_IWUSR); if (fd < 0) { if (request) RERROR("Session serialisation failed, failed opening session file %s: %s", filename, fr_syserror(errno)); @@ -1400,8 +1414,6 @@ static int cbtls_new_session(SSL *ssl, SSL_SESSION *sess) fr_pair_value_strcpy(vp, filename); fr_pair_add(&request->state, vp); } - - (void) fchmod(fd, S_IWUSR); } todo = blob_len; @@ -1441,7 +1453,7 @@ static int ocsp_asn1time_to_epoch(time_t *out, char const *asn1) memset(&t, 0, sizeof(t)); - if ((end - p) <= 12) { + if ((end - p) <= 13) { if ((end - p) < 2) { fr_strerror_printf("ASN1 date string too short, expected 2 additional bytes, got %zu bytes", end - p); @@ -1459,7 +1471,7 @@ static int ocsp_asn1time_to_epoch(time_t *out, char const *asn1) t.tm_year -= 1900; } - if ((end - p) < 10) { + if ((end - p) < 4) { fr_strerror_printf("ASN1 string too short, expected 10 additional bytes, got %zu bytes", end - p); return -1; @@ -1469,14 +1481,21 @@ static int ocsp_asn1time_to_epoch(time_t *out, char const *asn1) t.tm_mon += (*(p++) - '0') - 1; // -1 since January is 0 not 1. t.tm_mday = (*(p++) - '0') * 10; t.tm_mday += (*(p++) - '0'); + + if ((end - p) < 2) goto done; t.tm_hour = (*(p++) - '0') * 10; t.tm_hour += (*(p++) - '0'); + + if ((end - p) < 2) goto done; t.tm_min = (*(p++) - '0') * 10; t.tm_min += (*(p++) - '0'); + + if ((end - p) < 2) goto done; t.tm_sec = (*(p++) - '0') * 10; t.tm_sec += (*(p++) - '0'); /* Apparently OpenSSL converts all timestamps to UTC? Maybe? */ +done: *out = timegm(&t); return 0; } @@ -1592,6 +1611,7 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl, const unsigned char *data, int l /* not safe to un-persist a session w/o VPs */ RWDEBUG("Failed loading persisted VPs for session %s", buffer); SSL_SESSION_free(sess); + sess = NULL; goto error; } @@ -1603,14 +1623,16 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl, const unsigned char *data, int l time_t expires; if (ocsp_asn1time_to_epoch(&expires, vp->vp_strvalue) < 0) { - RDEBUG2("Failed getting certificate expiration, removing cache entry for session %s", buffer); + RDEBUG2("Failed getting certificate expiration, removing cache entry for session %s - %s", buffer, fr_strerror()); SSL_SESSION_free(sess); + sess = NULL; goto error; } if (expires <= request->timestamp) { RDEBUG2("Certificate has expired, removing cache entry for session %s", buffer); SSL_SESSION_free(sess); + sess = NULL; goto error; } @@ -2018,7 +2040,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx) char cn_str[1024]; char buf[64]; X509 *client_cert; -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) const STACK_OF(X509_EXTENSION) *ext_list; #else STACK_OF(X509_EXTENSION) *ext_list; @@ -2149,7 +2171,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx) /* * Get the RFC822 Subject Alternative Name */ - loc = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0); + loc = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, -1); if (certs && (lookup <= 1) && (loc >= 0)) { X509_EXTENSION *ext = NULL; GENERAL_NAMES *names = NULL; @@ -2199,7 +2221,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx) } } if (names != NULL) - sk_GENERAL_NAME_free(names); + GENERAL_NAMES_free(names); } /* @@ -2220,7 +2242,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx) } if (lookup == 0) { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) ext_list = X509_get0_extensions(client_cert); #else X509_CINF *client_inf; @@ -2429,7 +2451,8 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx) true, true, EXEC_TIMEOUT) != 0) { AUTH(LOG_PREFIX ": Certificate CN (%s) fails external verification!", common_name); my_ok = 0; - } else { + + } else if (request) { RDEBUG("Client certificate CN %s passed external validation", common_name); } @@ -2525,6 +2548,38 @@ static int set_ecdh_curve(SSL_CTX *ctx, char const *ecdh_curve, bool disable_sin #endif #endif +/* + * DIE OPENSSL DIE DIE DIE + * + * What a palaver, just to free some data attached the + * session. We need to do this because the "remove" callback + * is called when refcount > 0 sometimes, if another thread + * is using the session + */ +static void sess_free_vps(UNUSED void *parent, void *data_ptr, + UNUSED CRYPTO_EX_DATA *ad, UNUSED int idx, + UNUSED long argl, UNUSED void *argp) +{ + VALUE_PAIR *vp = data_ptr; + if (!vp) return; + + DEBUG2(LOG_PREFIX ": Freeing cached session VPs"); + + fr_pair_list_free(&vp); +} + +static void sess_free_certs(UNUSED void *parent, void *data_ptr, + UNUSED CRYPTO_EX_DATA *ad, UNUSED int idx, + UNUSED long argl, UNUSED void *argp) +{ + VALUE_PAIR **certs = data_ptr; + if (!certs) return; + + DEBUG2(LOG_PREFIX ": Freeing cached session Certificates"); + + fr_pair_list_free(certs); +} + /** Add all the default ciphers and message digests reate our context. * * This should be called exactly once from main, before reading the main config @@ -2540,7 +2595,7 @@ void tls_global_init(void) /* * Initialize the index for the certificates. */ - fr_tls_ex_index_certs = SSL_SESSION_get_ex_new_index(0, NULL, NULL, NULL, NULL); + fr_tls_ex_index_certs = SSL_SESSION_get_ex_new_index(0, NULL, NULL, NULL, sess_free_certs); } #ifdef ENABLE_OPENSSL_VERSION_CHECK @@ -2957,7 +3012,7 @@ post_ca: SSL_CTX_set_quiet_shutdown(ctx, 1); if (fr_tls_ex_index_vps < 0) - fr_tls_ex_index_vps = SSL_SESSION_get_ex_new_index(0, NULL, NULL, NULL, NULL); + fr_tls_ex_index_vps = SSL_SESSION_get_ex_new_index(0, NULL, NULL, NULL, sess_free_vps); } /* @@ -2992,6 +3047,7 @@ post_ca: SSL_CTX_set_verify_depth(ctx, conf->verify_depth); } +#ifndef LIBRESSL_VERSION_NUMBER /* Load randomness */ if (conf->random_file) { if (!(RAND_load_file(conf->random_file, 1024*10))) { @@ -2999,6 +3055,7 @@ post_ca: return NULL; } } +#endif /* * Set the cipher list if we were told to @@ -3026,9 +3083,9 @@ post_ca: } /* - * Cache it, and DON'T auto-clear it. + * Cache it, DON'T auto-clear it, and disable the internal OpenSSL session cache. */ - SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR); + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR | SSL_SESS_CACHE_NO_INTERNAL); SSL_CTX_set_session_id_context(ctx, (unsigned char *) conf->session_context_id, @@ -3074,7 +3131,7 @@ static int _tls_server_conf_free(fr_tls_server_conf_t *conf) return 0; } -static fr_tls_server_conf_t *tls_server_conf_alloc(TALLOC_CTX *ctx) +fr_tls_server_conf_t *tls_server_conf_alloc(TALLOC_CTX *ctx) { fr_tls_server_conf_t *conf; @@ -3120,6 +3177,7 @@ fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs) * Only check for certificate things if we don't have a * PSK query. */ +#ifdef PSK_MAX_IDENTITY_LEN if (conf->psk_identity) { if (conf->private_key_file) { WARN(LOG_PREFIX ": Ignoring private key file due to psk_identity being used"); @@ -3129,7 +3187,9 @@ fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs) WARN(LOG_PREFIX ": Ignoring certificate file due to psk_identity being used"); } - } else { + } else +#endif + { if (!conf->private_key_file) { ERROR(LOG_PREFIX ": TLS Server requires a private key file"); goto error;