Allow for dynamically expanded PSK.
[freeradius.git] / src / main / tls.c
index 67fefa3..50b1edc 100644 (file)
@@ -22,8 +22,8 @@
  * Copyright 2006  The FreeRADIUS server project
  */
 
-#include <freeradius-devel/ident.h>
 RCSID("$Id$")
+USES_APPLE_DEPRECATED_API      /* OpenSSL API has been deprecated by Apple */
 
 #include <freeradius-devel/radiusd.h>
 #include <freeradius-devel/process.h>
@@ -40,6 +40,7 @@ RCSID("$Id$")
 #ifdef HAVE_UTIME_H
 #include <utime.h>
 #endif
+#include <ctype.h>
 
 #ifdef WITH_TLS
 #ifdef HAVE_OPENSSL_RAND_H
@@ -50,42 +51,132 @@ RCSID("$Id$")
 #include <openssl/ocsp.h>
 #endif
 
-static void tls_server_conf_free(fr_tls_server_conf_t *conf);
+typedef struct libssl_defect {
+       uint64_t        high;
+       uint64_t        low;
+
+       char const      *id;
+       char const      *name;
+       char const      *comment;
+} libssl_defect_t;
+
+/* Record critical defects in libssl here (newest first)*/
+static libssl_defect_t libssl_defects[] =
+{
+       {
+               .low            = 0x010001000,          /* 1.0.1  */
+               .high           = 0x01000106f,          /* 1.0.1f */
+               .id             = "CVE-2014-0160",
+               .name           = "Heartbleed",
+               .comment        = "For more information see http://heartbleed.com"
+       }
+};
 
 /* record */
 static void            record_init(record_t *buf);
 static void            record_close(record_t *buf);
-static unsigned int    record_plus(record_t *buf, const void *ptr,
+static unsigned int    record_plus(record_t *buf, void const *ptr,
                                    unsigned int size);
 static unsigned int    record_minus(record_t *buf, void *ptr,
                                     unsigned int size);
 
 #ifdef PSK_MAX_IDENTITY_LEN
+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(conf->psk_password, psk, psk_len);
+       return fr_hex2bin(psk, max_psk_len, conf->psk_password, psk_len);
 }
 
-static unsigned int psk_client_callback(SSL *ssl, UNUSED const char *hint,
+static unsigned int psk_client_callback(SSL *ssl, UNUSED char const *hint,
                                        char *identity, unsigned int max_identity_len,
                                        unsigned char *psk, unsigned int max_psk_len)
 {
@@ -101,7 +192,7 @@ static unsigned int psk_client_callback(SSL *ssl, UNUSED const char *hint,
 
        strlcpy(identity, conf->psk_identity, max_identity_len);
 
-       return fr_hex2bin(conf->psk_password, psk, psk_len);
+       return fr_hex2bin(psk, max_psk_len, conf->psk_password, psk_len);
 }
 
 #endif
@@ -110,13 +201,23 @@ tls_session_t *tls_new_client_session(fr_tls_server_conf_t *conf, int fd)
 {
        int verify_mode;
        tls_session_t *ssn = NULL;
-       
+       REQUEST *request;
+
        ssn = talloc_zero(conf, tls_session_t);
        if (!ssn) return NULL;
 
        ssn->ctx = conf->ctx;
+
+       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
@@ -140,10 +241,11 @@ tls_session_t *tls_new_client_session(fr_tls_server_conf_t *conf, int fd)
        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;
        }
 
@@ -152,14 +254,30 @@ tls_session_t *tls_new_client_session(fr_tls_server_conf_t *conf, int fd)
        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;
        int             verify_mode = 0;
        VALUE_PAIR      *vp;
 
+       rad_assert(request != NULL);
+
        /*
         *      Manually flush the sessions every so often.  If HALF
         *      of the session lifetime has passed since we last
@@ -168,7 +286,7 @@ tls_session_t *tls_new_session(fr_tls_server_conf_t *conf, REQUEST *request,
         *      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));
 
@@ -177,7 +295,7 @@ tls_session_t *tls_new_session(fr_tls_server_conf_t *conf, REQUEST *request,
        }
 
        if ((new_tls = SSL_new(conf->ctx)) == NULL) {
-               radlog(L_ERR, "SSL: Error creating new SSL: %s",
+               ERROR("SSL: Error creating new SSL: %s",
                       ERR_error_string(ERR_get_error(), NULL));
                return NULL;
        }
@@ -185,8 +303,9 @@ tls_session_t *tls_new_session(fr_tls_server_conf_t *conf, REQUEST *request,
        /* 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;
@@ -262,7 +381,7 @@ tls_session_t *tls_new_session(fr_tls_server_conf_t *conf, REQUEST *request,
        if (conf->session_cache_enable) {
                state->allow_session_resumption = 1; /* otherwise it's zero */
        }
-       
+
        RDEBUG2("Initiate");
 
        return state;
@@ -271,15 +390,15 @@ tls_session_t *tls_new_session(fr_tls_server_conf_t *conf, REQUEST *request,
 /*
  *     Print out some text describing the error.
  */
-static int int_ssl_check(REQUEST *request, SSL *s, int ret, const char *text)
+static int int_ssl_check(REQUEST *request, SSL *s, int ret, char const *text)
 {
        int e;
        unsigned long l;
 
        if ((l = ERR_get_error()) != 0) {
-               const char *p = ERR_error_string(l, NULL);
+               char const *p = ERR_error_string(l, NULL);
 
-               if (request && p) RDEBUGE("SSL says: %s", p);
+               if (request && p) REDEBUG("SSL says: %s", p);
        }
        e = SSL_get_error(s, ret);
 
@@ -309,12 +428,12 @@ static int int_ssl_check(REQUEST *request, SSL *s, int ret, const char *text)
                 *      being regarded as "dead".
                 */
        case SSL_ERROR_SYSCALL:
-               radlog(L_ERR, "SSL: %s failed in a system call (%d), TLS session fails.",
+               ERROR("SSL: %s failed in a system call (%d), TLS session fails.",
                       text, ret);
                return 0;
 
        case SSL_ERROR_SSL:
-               radlog(L_ERR, "SSL: %s failed inside of TLS (%d), TLS session fails.",
+               ERROR("SSL: %s failed inside of TLS (%d), TLS session fails.",
                       text, ret);
                return 0;
 
@@ -325,7 +444,7 @@ static int int_ssl_check(REQUEST *request, SSL *s, int ret, const char *text)
                 *      them - so "politely inform" the caller that
                 *      the code needs updating here.
                 */
-               radlog(L_ERR, "SSL: FATAL SSL error ..... %d\n", e);
+               ERROR("SSL: FATAL SSL error ..... %d\n", e);
                return 0;
        }
 
@@ -349,6 +468,8 @@ int tls_handshake_recv(REQUEST *request, tls_session_t *ssn)
 {
        int err;
 
+       if (ssn->invalid_hb_used) return 0;
+
        err = BIO_write(ssn->into_ssl, ssn->dirty_in.data, ssn->dirty_in.used);
        if (err != (int) ssn->dirty_in.used) {
                RDEBUG("Failed writing %d to SSL BIO: %d", ssn->dirty_in.used,
@@ -373,16 +494,16 @@ int tls_handshake_recv(REQUEST *request, tls_session_t *ssn)
        if (SSL_is_init_finished(ssn->ssl)) {
                DEBUG2("SSL Connection Established\n");
        }
-       if (SSL_in_init(ssn->ssl)) {
+       if (SSL_in_init(ssn->ssl)) {
                DEBUG2("In SSL Handshake Phase\n");
        }
-       if (SSL_in_before(ssn->ssl)) {
+       if (SSL_in_before(ssn->ssl)) {
                DEBUG2("Before SSL Handshake Phase\n");
        }
-       if (SSL_in_accept_init(ssn->ssl)) {
+       if (SSL_in_accept_init(ssn->ssl)) {
                DEBUG2("In SSL Accept mode \n");
        }
-       if (SSL_in_connect_init(ssn->ssl)) {
+       if (SSL_in_connect_init(ssn->ssl)) {
                DEBUG2("In SSL Connect mode \n");
        }
 
@@ -415,7 +536,7 @@ int tls_handshake_recv(REQUEST *request, tls_session_t *ssn)
 }
 
 /*
- *     Take clear-text user data, and encrypt it into the output buffer,
+ *     Take cleartext user data, and encrypt it into the output buffer,
  *     to send to the client at the other end of the SSL connection.
  */
 int tls_handshake_send(REQUEST *request, tls_session_t *ssn)
@@ -470,12 +591,14 @@ void session_init(tls_session_t *ssn)
 }
 
 void session_close(tls_session_t *ssn)
-{      
+{
        SSL_set_quiet_shutdown(ssn->ssl, 1);
        SSL_shutdown(ssn->ssl);
 
-       if(ssn->ssl)
+       if (ssn->ssl) {
                SSL_free(ssn->ssl);
+               ssn->ssl = NULL;
+       }
 
        record_close(&ssn->clean_in);
        record_close(&ssn->clean_out);
@@ -484,25 +607,6 @@ void session_close(tls_session_t *ssn)
        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;
@@ -518,7 +622,7 @@ static void record_close(record_t *rec)
  *     Copy data to the intermediate buffer, before we send
  *     it somewhere.
  */
-static unsigned int record_plus(record_t *rec, const void *ptr,
+static unsigned int record_plus(record_t *rec, void const *ptr,
                                unsigned int size)
 {
        unsigned int added = MAX_RECORD_SIZE - rec->used;
@@ -558,8 +662,8 @@ static unsigned int record_minus(record_t *rec, void *ptr,
 
 void tls_session_information(tls_session_t *tls_session)
 {
-       const char *str_write_p, *str_version, *str_content_type = "";
-       const char *str_details1 = "", *str_details2= "";
+       char const *str_write_p, *str_version, *str_content_type = "";
+       char const *str_details1 = "", *str_details2= "";
        REQUEST *request;
 
        /*
@@ -572,8 +676,7 @@ void tls_session_information(tls_session_t *tls_session)
 
        str_write_p = tls_session->info.origin ? ">>>" : "<<<";
 
-       switch (tls_session->info.version)
-       {
+       switch (tls_session->info.version) {
        case SSL2_VERSION:
                str_version = "SSL 2.0";
                break;
@@ -701,8 +804,7 @@ void tls_session_information(tls_session_t *tls_session)
                        str_details1 = "???";
 
                        if (tls_session->info.record_len > 0)
-                       switch (tls_session->info.handshake_type)
-                       {
+                       switch (tls_session->info.handshake_type) {
                        case SSL3_MT_HELLO_REQUEST:
                                str_details1 = ", HelloRequest";
                                break;
@@ -745,115 +847,82 @@ void tls_session_information(tls_session_t *tls_session)
                 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_FILENAME,
-         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_FILENAME,
-         offsetof(fr_tls_server_conf_t, private_key_file), NULL, NULL },
-       { "certificate_file", PW_TYPE_FILENAME,
-         offsetof(fr_tls_server_conf_t, certificate_file), NULL, NULL },
-       { "CA_file", PW_TYPE_FILENAME,
-         offsetof(fr_tls_server_conf_t, ca_file), NULL, NULL },
-       { "private_key_password", PW_TYPE_STRING_PTR,
-         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,
-         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},
-       { "make_cert_command", PW_TYPE_STRING_PTR,
-         offsetof(fr_tls_server_conf_t, make_cert_command), 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, (const void *) cache_config },
+       { "cache", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) cache_config },
 
-       { "verify", PW_TYPE_SUBSECTION, 0, NULL, (const void *) 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, (const void *) ocsp_config },
+       { "ocsp", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) ocsp_config },
 #endif
 
        { NULL, -1, 0, NULL, NULL }        /* end the list */
@@ -861,53 +930,33 @@ static CONF_PARSER tls_server_config[] = {
 
 
 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_FILENAME,
-         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_FILENAME,
-         offsetof(fr_tls_server_conf_t, private_key_file), NULL, NULL },
-       { "certificate_file", PW_TYPE_FILENAME,
-         offsetof(fr_tls_server_conf_t, certificate_file), NULL, NULL },
-       { "CA_file", PW_TYPE_FILENAME,
-         offsetof(fr_tls_server_conf_t, ca_file), NULL, NULL },
-       { "private_key_password", PW_TYPE_STRING_PTR,
-         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
 
-       { NULL, -1, 0, NULL, NULL }        /* end the list */
+       { NULL, -1, 0, NULL, NULL }        /* end the list */
 };
 
 
@@ -919,21 +968,23 @@ static int load_dh_params(SSL_CTX *ctx, char *file)
        DH *dh = NULL;
        BIO *bio;
 
+       if (!file) return 0;
+
        if ((bio = BIO_new_file(file, "r")) == NULL) {
-               radlog(L_ERR, "rlm_eap_tls: Unable to open DH file - %s", file);
+               ERROR("tls: Unable to open DH file - %s", file);
                return -1;
        }
 
        dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
        BIO_free(bio);
        if (!dh) {
-               DEBUG2W("rlm_eap_tls: Unable to set DH parameters.  DH cipher suites may not work!");
-               DEBUG2W("Fix this by running the OpenSSL command listed in eap.conf");
+               WARN("tls: Unable to set DH parameters.  DH cipher suites may not work!");
+               WARN("Fix this by running the OpenSSL command listed in eap.conf");
                return 0;
        }
 
        if (SSL_CTX_set_tmp_dh(ctx, dh) < 0) {
-               radlog(L_ERR, "rlm_eap_tls: Unable to set DH parameters");
+               ERROR("tls: Unable to set DH parameters");
                DH_free(dh);
                return -1;
        }
@@ -953,7 +1004,7 @@ static int generate_eph_rsa_key(SSL_CTX *ctx)
        rsa = RSA_generate_key(512, RSA_F4, NULL, NULL);
 
        if (!SSL_CTX_set_tmp_rsa(ctx, rsa)) {
-               radlog(L_ERR, "rlm_eap_tls: Couldn't set ephemeral RSA key");
+               ERROR("tls: Couldn't set ephemeral RSA key");
                return -1;
        }
 
@@ -965,6 +1016,7 @@ static int generate_eph_rsa_key(SSL_CTX *ctx)
  * needs to be dynamic so we can supply a "free" function
  */
 static int FR_TLS_EX_INDEX_VPS = -1;
+int FR_TLS_EX_INDEX_CERTS = -1;
 
 /*
  *     Print debugging messages, and free data.
@@ -984,7 +1036,7 @@ static void cbtls_remove_session(SSL_CTX *ctx, SSL_SESSION *sess)
        size = sess->session_id_length;
        if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
 
-       fr_bin2hex(sess->session_id, buffer, size);
+       fr_bin2hex(buffer, sess->session_id, size);
 
        DEBUG2("  SSL: Removing session %s from the cache", buffer);
        conf = (fr_tls_server_conf_t *)SSL_CTX_get_app_data(ctx);
@@ -993,18 +1045,16 @@ static void cbtls_remove_session(SSL_CTX *ctx, SSL_SESSION *sess)
                char filename[256];
 
                /* remove session and any cached VPs */
-               rv = snprintf(filename, sizeof(filename), "%s%c%s.asn1",
-                       conf->session_cache_path, FR_DIR_SEP, buffer
-                       );
+               snprintf(filename, sizeof(filename), "%s%c%s.asn1",
+                        conf->session_cache_path, FR_DIR_SEP, buffer);
                rv = unlink(filename);
                if (rv != 0) {
-                       DEBUG2("  SSL: could not remove persisted session file %s: %s", filename, strerror(errno));
+                       DEBUG2("  SSL: could not remove persisted session file %s: %s", filename, fr_syserror(errno));
                }
                /* VPs might be absent; might not have been written to disk yet */
-               rv = snprintf(filename, sizeof(filename), "%s%c%s.vps",
-                       conf->session_cache_path, FR_DIR_SEP, buffer
-                       );
-               rv = unlink(filename);
+               snprintf(filename, sizeof(filename), "%s%c%s.vps",
+                        conf->session_cache_path, FR_DIR_SEP, buffer);
+               unlink(filename);
        }
 
        return;
@@ -1020,7 +1070,7 @@ static int cbtls_new_session(SSL *ssl, SSL_SESSION *sess)
        size = sess->session_id_length;
        if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
 
-       fr_bin2hex(sess->session_id, buffer, size);
+       fr_bin2hex(buffer, sess->session_id, size);
 
        DEBUG2("  SSL: adding session %s to cache", buffer);
 
@@ -1038,8 +1088,10 @@ static int cbtls_new_session(SSL *ssl, SSL_SESSION *sess)
                        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;
@@ -1053,11 +1105,11 @@ static int cbtls_new_session(SSL *ssl, SSL_SESSION *sess)
                }
 
                /* open output file */
-               rv = snprintf(filename, sizeof(filename), "%s%c%s.asn1",
-                             conf->session_cache_path, FR_DIR_SEP, buffer);
+               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);
                if (fd < 0) {
-                       DEBUG2("  SSL: could not open session file %s: %s", filename, strerror(errno));
+                       DEBUG2("  SSL: could not open session file %s: %s", filename, fr_syserror(errno));
                        goto error;
                }
 
@@ -1066,7 +1118,7 @@ static int cbtls_new_session(SSL *ssl, SSL_SESSION *sess)
                while (todo > 0) {
                        rv = write(fd, p, todo);
                        if (rv < 1) {
-                               DEBUG2("  SSL: failed writing session: %s", strerror(errno));
+                               DEBUG2("  SSL: failed writing session: %s", fr_syserror(errno));
                                close(fd);
                                goto error;
                        }
@@ -1078,7 +1130,7 @@ static int cbtls_new_session(SSL *ssl, SSL_SESSION *sess)
        }
 
 error:
-       if (sess_blob) talloc_free(sess_blob);
+       free(sess_blob);
 
        return 0;
 }
@@ -1090,6 +1142,7 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl,
        size_t size;
        char buffer[2 * MAX_SESSION_SIZE + 1];
        fr_tls_server_conf_t *conf;
+       TALLOC_CTX *talloc_ctx;
 
        SSL_SESSION *sess = NULL;
        unsigned char *sess_data = NULL;
@@ -1098,11 +1151,12 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl,
        size = len;
        if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
 
-       fr_bin2hex(data, buffer, size);
+       fr_bin2hex(buffer, data, size);
 
        DEBUG2("  SSL: Client requested cached session %s", buffer);
 
        conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
+       talloc_ctx = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TALLOC);
        if (conf && conf->session_cache_path) {
                int rv, fd, todo;
                char filename[256];
@@ -1111,10 +1165,9 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl,
                VALUE_PAIR *vp;
 
                /* read in the cached VPs from the .vps file */
-               rv = snprintf(filename, sizeof(filename), "%s%c%s.vps",
-                       conf->session_cache_path, FR_DIR_SEP, buffer
-                       );
-               rv = pairlist_read(filename, &pairlist, 1);
+               snprintf(filename, sizeof(filename), "%s%c%s.vps",
+                        conf->session_cache_path, FR_DIR_SEP, buffer);
+               rv = pairlist_read(NULL, filename, &pairlist, 1);
                if (rv < 0) {
                        /* not safe to un-persist a session w/o VPs */
                        DEBUG2("  SSL: could not load persisted VPs for session %s", buffer);
@@ -1122,23 +1175,22 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl,
                }
 
                /* load the actual SSL session */
-               rv = snprintf(filename, sizeof(filename), "%s%c%s.asn1",
-                       conf->session_cache_path, FR_DIR_SEP, buffer
-                       );
+               snprintf(filename, sizeof(filename), "%s%c%s.asn1",
+                        conf->session_cache_path, FR_DIR_SEP, buffer);
                fd = open(filename, O_RDONLY);
-               if (fd == -1) {
-                       DEBUG2("  SSL: could not find persisted session file %s: %s", filename, strerror(errno));
+               if (fd < 0) {
+                       DEBUG2("  SSL: could not find persisted session file %s: %s", filename, fr_syserror(errno));
                        goto err;
                }
 
                rv = fstat(fd, &st);
-               if (rv == -1) {
-                       DEBUG2("  SSL: could not stat persisted session file %s: %s", filename, strerror(errno));
+               if (rv < 0) {
+                       DEBUG2("  SSL: could not stat persisted session file %s: %s", filename, fr_syserror(errno));
                        close(fd);
                        goto err;
                }
 
-               sess_data = talloc_array(conf, unsigned char, st.st_size);
+               sess_data = talloc_array(NULL, unsigned char, st.st_size);
                if (!sess_data) {
                  DEBUG2("  SSL: could not alloc buffer for persisted session len=%d", (int) st.st_size);
                        close(fd);
@@ -1150,7 +1202,7 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl,
                while (todo > 0) {
                        rv = read(fd, p, todo);
                        if (rv < 1) {
-                               DEBUG2("  SSL: could not read from persisted session: %s", strerror(errno));
+                               DEBUG2("  SSL: could not read from persisted session: %s", fr_syserror(errno));
                                close(fd);
                                goto err;
                        }
@@ -1161,7 +1213,7 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl,
 
                /* openssl mutates &p */
                p = sess_data;
-               sess = d2i_SSL_SESSION(NULL, (const unsigned char **) &p, st.st_size);
+               sess = d2i_SSL_SESSION(NULL, (unsigned char const **)(void **) &p, st.st_size);
 
                if (!sess) {
                        DEBUG2("  SSL: OpenSSL failed to load persisted session: %s", ERR_error_string(ERR_get_error(), NULL));
@@ -1169,7 +1221,7 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl,
                }
 
                /* cache the VPs into the session */
-               vp = paircopy(pairlist->reply);
+               vp = paircopy(talloc_ctx, pairlist->reply);
                SSL_SESSION_set_ex_data(sess, FR_TLS_EX_INDEX_VPS, vp);
                DEBUG2("  SSL: Successfully restored session %s", buffer);
        }
@@ -1256,19 +1308,23 @@ static int ocsp_check(X509_STORE *store, X509 *issuer_cert, X509 *client_cert,
         */
 
        /* 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 (!host || !port || !path) {
-               DEBUG2("[ocsp] - Host / port / path missing.  Not doing OCSP.");
+               DEBUG2("[ocsp] - Host / port / path missing.  Not doing OCSP");
                ocsp_ok = 2;
                goto ocsp_skip;
        }
-       
+
        DEBUG2("[ocsp] --> Responder URL = http://%s:%s%s", host, port, path);
 
        /* Setup BIO socket to OCSP responder */
@@ -1283,7 +1339,7 @@ static int ocsp_check(X509_STORE *store, X509 *issuer_cert, X509 *client_cert,
        /* Send OCSP request and wait for response */
        resp = OCSP_sendreq_bio(cbio, path, req);
        if (!resp) {
-               radlog(L_ERR, "Error: Couldn't get OCSP response");
+               ERROR("Couldn't get OCSP response");
                ocsp_ok = 2;
                goto ocsp_end;
        }
@@ -1293,14 +1349,14 @@ static int ocsp_check(X509_STORE *store, X509 *issuer_cert, X509 *client_cert,
 
        rc = BIO_do_connect(cbio);
        if ((rc <= 0) && ((!conf->ocsp_timeout) || !BIO_should_retry(cbio))) {
-               radlog(L_ERR, "Error: Couldn't connect to OCSP responder");
+               ERROR("Couldn't connect to OCSP responder");
                ocsp_ok = 2;
                goto ocsp_end;
        }
 
        ctx = OCSP_sendreq_new(cbio, path, req, -1);
        if (!ctx) {
-               radlog(L_ERR, "Error: Couldn't send OCSP request");
+               ERROR("Couldn't send OCSP request");
                ocsp_ok = 2;
                goto ocsp_end;
        }
@@ -1318,7 +1374,7 @@ static int ocsp_check(X509_STORE *store, X509 *issuer_cert, X509 *client_cert,
        } while ((rc == -1) && BIO_should_retry(cbio));
 
        if (conf->ocsp_timeout && (rc == -1) && BIO_should_retry(cbio)) {
-               radlog(L_ERR, "Error: OCSP response timed out");
+               ERROR("OCSP response timed out");
                ocsp_ok = 2;
                goto ocsp_end;
        }
@@ -1326,7 +1382,7 @@ static int ocsp_check(X509_STORE *store, X509 *issuer_cert, X509 *client_cert,
        OCSP_REQ_CTX_free(ctx);
 
        if (rc == 0) {
-               radlog(L_ERR, "Error: Couldn't get OCSP response");
+               ERROR("Couldn't get OCSP response");
                ocsp_ok = 2;
                goto ocsp_end;
        }
@@ -1336,23 +1392,23 @@ static int ocsp_check(X509_STORE *store, X509 *issuer_cert, X509 *client_cert,
        status = OCSP_response_status(resp);
        DEBUG2("[ocsp] --> Response status: %s",OCSP_response_status_str(status));
        if(status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
-               radlog(L_ERR, "Error: OCSP response status: %s", OCSP_response_status_str(status));
+               ERROR("OCSP response status: %s", OCSP_response_status_str(status));
                goto ocsp_end;
        }
        bresp = OCSP_response_get1_basic(resp);
        if(conf->ocsp_use_nonce && OCSP_check_nonce(req, bresp)!=1) {
-               radlog(L_ERR, "Error: OCSP response has wrong nonce value");
+               ERROR("OCSP response has wrong nonce value");
                goto ocsp_end;
        }
        if(OCSP_basic_verify(bresp, NULL, store, 0)!=1){
-               radlog(L_ERR, "Error: Couldn't verify OCSP basic response");
+               ERROR("Couldn't verify OCSP basic response");
                goto ocsp_end;
        }
 
        /*      Verify OCSP cert status */
        if(!OCSP_resp_find_status(bresp, certid, &status, &reason,
                                                      &rev, &thisupd, &nextupd)) {
-               radlog(L_ERR, "ERROR: No Status found.\n");
+               ERROR("No Status found.\n");
                goto ocsp_end;
        }
 
@@ -1404,8 +1460,8 @@ ocsp_end:
                break;
        case 2:
                if (conf->ocsp_softfail) {
-                       DEBUG2("[ocsp] --> Unable to check certificate; assuming valid.");
-                       DEBUG2("[ocsp] --> Warning! This may be insecure.");
+                       DEBUG2("[ocsp] --> Unable to check certificate; assuming valid");
+                       DEBUG2("[ocsp] --> Warning! This may be insecure");
                        ocsp_ok = 1;
                } else {
                        DEBUG2("[ocsp] --> Unable to check certificate; failing!");
@@ -1424,13 +1480,15 @@ ocsp_end:
 /*
  *     For creating certificate attributes.
  */
-static const char *cert_attr_names[6][2] = {
+static char const *cert_attr_names[8][2] = {
   { "TLS-Client-Cert-Serial",          "TLS-Cert-Serial" },
   { "TLS-Client-Cert-Expiration",      "TLS-Cert-Expiration" },
   { "TLS-Client-Cert-Subject",         "TLS-Cert-Subject" },
   { "TLS-Client-Cert-Issuer",          "TLS-Cert-Issuer" },
   { "TLS-Client-Cert-Common-Name",     "TLS-Cert-Common-Name" },
-  { "TLS-Client-Cert-Subject-Alt-Name-Email",  "TLS-Cert-Subject-Alt-Name-Email" }
+  { "TLS-Client-Cert-Subject-Alt-Name-Email",  "TLS-Cert-Subject-Alt-Name-Email" },
+  { "TLS-Client-Cert-Subject-Alt-Name-Dns",    "TLS-Cert-Subject-Alt-Name-Dns" },
+  { "TLS-Client-Cert-Subject-Alt-Name-Upn",    "TLS-Cert-Subject-Alt-Name-Upn" }
 };
 
 #define FR_TLS_SERIAL          (0)
@@ -1439,6 +1497,8 @@ static const char *cert_attr_names[6][2] = {
 #define FR_TLS_ISSUER          (3)
 #define FR_TLS_CN              (4)
 #define FR_TLS_SAN_EMAIL               (5)
+#define FR_TLS_SAN_DNS          (6)
+#define FR_TLS_SAN_UPN          (7)
 
 /*
  *     Before trusting a certificate, you must make sure that the
@@ -1469,10 +1529,14 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
 {
        char subject[1024]; /* Used for the subject name */
        char issuer[1024]; /* Used for the issuer name */
+       char attribute[1024];
+       char value[1024];
        char common_name[1024];
        char cn_str[1024];
        char buf[64];
        X509 *client_cert;
+       X509_CINF *client_inf;
+       STACK_OF(X509_EXTENSION) *ext_list;
        SSL *ssl;
        int err, depth, lookup, loc;
        fr_tls_server_conf_t *conf;
@@ -1486,7 +1550,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
        X509_STORE *ocsp_store = NULL;
        X509 *issuer_cert;
 #endif
-       tls_session_t *ssn;
+       TALLOC_CTX *talloc_ctx;
 
        client_cert = X509_STORE_CTX_get_current_cert(ctx);
        err = X509_STORE_CTX_get_error(ctx);
@@ -1509,17 +1573,15 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
        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);
 #endif
-       ssn = (tls_session_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_SSN);
+
+       talloc_ctx = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TALLOC);
 
        /*
         *      Get the Serial Number
@@ -1533,7 +1595,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
         *      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;
@@ -1542,7 +1604,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                        sprintf(p, "%02x", (unsigned int)sn->data[i]);
                        p += 2;
                }
-               pairmake(ssn, certs, cert_attr_names[FR_TLS_SERIAL][lookup], buf, T_OP_SET);
+               pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_SERIAL][lookup], buf, T_OP_SET);
        }
 
 
@@ -1551,11 +1613,11 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
         */
        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';
-               pairmake(ssn, certs, cert_attr_names[FR_TLS_EXPIRATION][lookup], buf, T_OP_SET);
+               pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_EXPIRATION][lookup], buf, T_OP_SET);
        }
 
        /*
@@ -1565,17 +1627,15 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
        X509_NAME_oneline(X509_get_subject_name(client_cert), subject,
                          sizeof(subject));
        subject[sizeof(subject) - 1] = '\0';
-       if (identity && (lookup <= 1) && subject[0] &&
-           (strlen(subject) < MAX_STRING_LEN)) {
-               pairmake(ssn, certs, cert_attr_names[FR_TLS_SUBJECT][lookup], subject, T_OP_SET);
+       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] &&
-           (strlen(issuer) < MAX_STRING_LEN)) {
-               pairmake(ssn, certs, cert_attr_names[FR_TLS_ISSUER][lookup], issuer, T_OP_SET);
+       if (certs && identity && (lookup <= 1) && issuer[0]) {
+               pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_ISSUER][lookup], issuer, T_OP_SET);
        }
 
        /*
@@ -1584,17 +1644,15 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
        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] &&
-           (strlen(common_name) < MAX_STRING_LEN)) {
-               pairmake(ssn, certs, cert_attr_names[FR_TLS_CN][lookup], common_name, T_OP_SET);
+       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);
        }
 
-#ifdef GEN_EMAIL
        /*
         *      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;
@@ -1605,13 +1663,34 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                                GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
 
                                switch (name->type) {
+#ifdef GEN_EMAIL
                                case GEN_EMAIL:
-                                       if (ASN1_STRING_length(name->d.rfc822Name) >= MAX_STRING_LEN)
-                                               break;
-
-                                       pairmake(ssn, certs, cert_attr_names[FR_TLS_SAN_EMAIL][lookup],
+                                       pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_SAN_EMAIL][lookup],
                                                 (char *) ASN1_STRING_data(name->d.rfc822Name), T_OP_SET);
                                        break;
+#endif /* GEN_EMAIL */
+#ifdef GEN_DNS
+                               case GEN_DNS:
+                                       pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_SAN_DNS][lookup],
+                                                (char *) ASN1_STRING_data(name->d.dNSName), T_OP_SET);
+                                       break;
+#endif /* GEN_DNS */
+#ifdef GEN_OTHERNAME
+                               case GEN_OTHERNAME:
+                                       /* look for a MS UPN */
+                                       if (NID_ms_upn == OBJ_obj2nid(name->d.otherName->type_id)) {
+                                           /* we've got a UPN - Must be ASN1-encoded UTF8 string */
+                                           if (name->d.otherName->value->type == V_ASN1_UTF8STRING) {
+                                               pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_SAN_UPN][lookup],
+                                                        (char *) ASN1_STRING_data(name->d.otherName->value->value.utf8string), T_OP_SET);
+                                               break;
+                                           } else {
+                                               RWARN("Invalid UPN in Subject Alt Name (should be UTF-8)\n");
+                                               break;
+                                           }
+                                       }
+                                       break;
+#endif /* GEN_OTHERNAME */
                                default:
                                        /* XXX TODO handle other SAN types */
                                        break;
@@ -1621,7 +1700,6 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                if (names != NULL)
                        sk_GENERAL_NAME_free(names);
        }
-#endif /* GEN_EMAIL */
 
        /*
         *      If the CRL has expired, that might still be OK.
@@ -1634,27 +1712,81 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
        }
 
        if (!my_ok) {
-               const char *p = X509_verify_cert_error_string(err);
-               radlog(L_ERR,"--> verify error:num=%d:%s\n",err, p);
-               RDEBUGE("SSL says error %d : %s", err, p);
+               char const *p = X509_verify_cert_error_string(err);
+               ERROR("--> verify error:num=%d:%s\n",err, p);
+               REDEBUG("SSL says error %d : %s", err, p);
                return my_ok;
        }
 
+       if (lookup == 0) {
+               client_inf = client_cert->cert_info;
+               ext_list = client_inf->extensions;
+       } else {
+               ext_list = NULL;
+       }
+
+       /*
+        *      Grab the X509 extensions, and create attributes out of them.
+        *      For laziness, we re-use the OpenSSL names
+        */
+       if (sk_X509_EXTENSION_num(ext_list) > 0) {
+               int i, len;
+               char *p;
+               BIO *out;
+
+               out = BIO_new(BIO_s_mem());
+               strlcpy(attribute, "TLS-Client-Cert-", sizeof(attribute));
+
+               for (i = 0; i < sk_X509_EXTENSION_num(ext_list); i++) {
+                       ASN1_OBJECT *obj;
+                       X509_EXTENSION *ext;
+                       VALUE_PAIR *vp;
+
+                       ext = sk_X509_EXTENSION_value(ext_list, i);
+
+                       obj = X509_EXTENSION_get_object(ext);
+                       i2a_ASN1_OBJECT(out, obj);
+                       len = BIO_read(out, attribute + 16 , sizeof(attribute) - 16 - 1);
+                       if (len <= 0) continue;
+
+                       attribute[16 + len] = '\0';
+
+                       X509V3_EXT_print(out, ext, 0, 0);
+                       len = BIO_read(out, value , sizeof(value) - 1);
+                       if (len <= 0) continue;
+
+                       value[len] = '\0';
+
+                       /*
+                        *      Mash the OpenSSL name to our name, and
+                        *      create the attribute.
+                        */
+                       for (p = value + 16; *p != '\0'; p++) {
+                               if (*p == ' ') *p = '-';
+                       }
+
+                       vp = pairmake(talloc_ctx, certs, attribute, value, T_OP_ADD);
+                       if (vp) debug_pair_list(vp);
+               }
+
+               BIO_free_all(out);
+       }
+
        switch (ctx->error) {
 
        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
-               radlog(L_ERR, "issuer= %s\n", issuer);
+               ERROR("issuer= %s\n", issuer);
                break;
        case X509_V_ERR_CERT_NOT_YET_VALID:
        case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
-               radlog(L_ERR, "notBefore=");
+               ERROR("notBefore=");
 #if 0
                ASN1_TIME_print(bio_err, X509_get_notBefore(ctx->current_cert));
 #endif
                break;
        case X509_V_ERR_CERT_HAS_EXPIRED:
        case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
-               radlog(L_ERR, "notAfter=");
+               ERROR("notAfter=");
 #if 0
                ASN1_TIME_print(bio_err, X509_get_notAfter(ctx->current_cert));
 #endif
@@ -1673,7 +1805,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                 */
                if (conf->check_cert_issuer &&
                    (strcmp(issuer, conf->check_cert_issuer) != 0)) {
-                       radlog(L_AUTH, "rlm_eap_tls: Certificate issuer (%s) does not match specified value (%s)!", issuer, conf->check_cert_issuer);
+                       AUTH("tls: Certificate issuer (%s) does not match specified value (%s)!", issuer, conf->check_cert_issuer);
                        my_ok = 0;
                }
 
@@ -1683,15 +1815,13 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                 *      previous checks passed.
                 */
                if (my_ok && conf->check_cert_cn) {
-                       if (!radius_xlat(cn_str, sizeof(cn_str), conf->check_cert_cn, request, NULL, NULL)) {
-                               radlog(L_ERR, "rlm_eap_tls (%s): xlat failed.",
-                                      conf->check_cert_cn);
+                       if (radius_xlat(cn_str, sizeof(cn_str), request, conf->check_cert_cn, NULL, NULL) < 0) {
                                /* if this fails, fail the verification */
                                my_ok = 0;
                        } else {
                                RDEBUG2("checking certificate CN (%s) with xlat'ed value (%s)", common_name, cn_str);
                                if (strcmp(cn_str, common_name) != 0) {
-                                       radlog(L_AUTH, "rlm_eap_tls: Certificate CN (%s) does not match specified value (%s)!", common_name, cn_str);
+                                       AUTH("tls: Certificate CN (%s) does not match specified value (%s)!", common_name, cn_str);
                                        my_ok = 0;
                                }
                        }
@@ -1701,7 +1831,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                if (my_ok && conf->ocsp_enable){
                        RDEBUG2("--> Starting OCSP Request");
                        if(X509_STORE_CTX_get1_issuer(&issuer_cert, ctx, client_cert)!=1) {
-                               radlog(L_ERR, "Error: Couldn't get issuer_cert for %s", common_name);
+                               ERROR("Couldn't get issuer_cert for %s", common_name);
                        }
                        my_ok = ocsp_check(ocsp_store, issuer_cert, client_cert, conf);
                }
@@ -1717,14 +1847,15 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                        fd = mkstemp(filename);
                        if (fd < 0) {
                                RDEBUG("Failed creating file in %s: %s",
-                                      conf->verify_tmp_dir, strerror(errno));
+                                      conf->verify_tmp_dir, fr_syserror(errno));
                                break;
                        }
 
                        fp = fdopen(fd, "w");
                        if (!fp) {
+                               close(fd);
                                RDEBUG("Failed opening file %s: %s",
-                                      filename, strerror(errno));
+                                      filename, fr_syserror(errno));
                                break;
                        }
 
@@ -1742,13 +1873,10 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                                goto do_unlink;
                        }
 
-                       RDEBUG("Verifying client certificate: %s",
-                              conf->verify_client_cert_cmd);
-                       if (radius_exec_program(conf->verify_client_cert_cmd,
-                                               request, 1, NULL, 0,
-                                               request->packet->vps,
-                                               NULL, 1) != 0) {
-                               radlog(L_AUTH, "rlm_eap_tls: Certificate CN (%s) fails external verification!", common_name);
+                       RDEBUG("Verifying client certificate: %s", conf->verify_client_cert_cmd);
+                       if (radius_exec_program(request, conf->verify_client_cert_cmd, true, true, NULL, 0,
+                                               EXEC_TIMEOUT, request->packet->vps, NULL) != 0) {
+                               AUTH("tls: Certificate CN (%s) fails external verification!", common_name);
                                my_ok = 0;
                        } else {
                                RDEBUG("Client certificate CN %s passed external validation", common_name);
@@ -1793,8 +1921,8 @@ static X509_STORE *init_revocation_store(fr_tls_server_conf_t *conf)
        /* Load the CAs we trust */
        if (conf->ca_file || conf->ca_path)
                if(!X509_STORE_load_locations(store, conf->ca_file, conf->ca_path)) {
-                       radlog(L_ERR, "rlm_eap: X509_STORE error %s", ERR_error_string(ERR_get_error(), NULL));
-                       radlog(L_ERR, "rlm_eap_tls: Error reading Trusted root CA list %s",conf->ca_file );
+                       ERROR("tls: X509_STORE error %s", ERR_error_string(ERR_get_error(), NULL));
+                       ERROR("tls: Error reading Trusted root CA list %s",conf->ca_file );
                        return NULL;
                }
 
@@ -1808,7 +1936,7 @@ static X509_STORE *init_revocation_store(fr_tls_server_conf_t *conf)
 
 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
 #ifndef OPENSSL_NO_ECDH
-static int set_ecdh_curve(SSL_CTX *ctx, const char *ecdh_curve)
+static int set_ecdh_curve(SSL_CTX *ctx, char const *ecdh_curve)
 {
        int      nid;
        EC_KEY  *ecdh;
@@ -1817,13 +1945,13 @@ static int set_ecdh_curve(SSL_CTX *ctx, const char *ecdh_curve)
 
        nid = OBJ_sn2nid(ecdh_curve);
        if (!nid) {
-               radlog(L_ERR, "Unknown ecdh_curve \"%s\"", ecdh_curve);
+               ERROR("Unknown ecdh_curve \"%s\"", ecdh_curve);
                return -1;
        }
 
        ecdh = EC_KEY_new_by_curve_name(nid);
        if (!ecdh) {
-               radlog(L_ERR, "Unable to create new curve \"%s\"", ecdh_curve);
+               ERROR("Unable to create new curve \"%s\"", ecdh_curve);
                return -1;
        }
 
@@ -1853,11 +1981,87 @@ static void sess_free_vps(UNUSED void *parent, void *data_ptr,
        VALUE_PAIR *vp = data_ptr;
        if (!vp) return;
 
-       DEBUG2("  Freeing cached session VPs %p", vp);
+       DEBUG2("  Freeing cached session VPs");;
 
        pairfree(&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("  Freeing cached session Certificates");
+
+       pairfree(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
+ * or initialising any modules.
+ */
+void tls_global_init(void)
+{
+       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;
+               size_t i;
+
+               /* Check for bad versions */
+               v = (uint64_t) SSLeay();
+
+               for (i = 0; i < (sizeof(libssl_defects) / sizeof(*libssl_defects)); i++) {
+                       libssl_defect_t *defect = &libssl_defects[i];
+
+                       if ((v >= defect->low) && (v <= defect->high)) {
+                               ERROR("Refusing to start with libssl version %s (in range %s)",
+                                     ssl_version(), ssl_version_range(defect->low, defect->high));
+                               ERROR("Security advisory %s (%s)", defect->id, defect->name);
+                               ERROR("%s", defect->comment);
+
+                               bad = true;
+                       }
+               }
+
+               if (bad) {
+                       INFO("Once you have verified libssl has been correctly patched, "
+                            "set security.allow_vulnerable_openssl = '%s'", libssl_defects[0].id);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/** Free any memory alloced by libssl
+ *
+ */
+void tls_global_cleanup(void)
+{
+       ERR_remove_state(0);
+       ENGINE_cleanup();
+       CONF_modules_unload(1);
+       ERR_free_strings();
+       EVP_cleanup();
+       CRYPTO_cleanup_all_ex_data();
+}
 
 /*
  *     Create Global context SSL and use it in every new session
@@ -1866,7 +2070,7 @@ static void sess_free_vps(UNUSED void *parent, void *data_ptr,
  *     - 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;
@@ -1875,13 +2079,6 @@ static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf, int client)
        int type;
 
        /*
-        *      Add all the default ciphers and message digests
-        *      Create our context.
-        */
-       SSL_library_init();
-       SSL_load_error_strings();
-
-       /*
         *      SHA256 is in all versions of OpenSSL, but isn't
         *      initialized by default.  It's needed for WiMAX
         *      certificates.
@@ -1891,6 +2088,14 @@ static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf, int client)
 #endif
 
        ctx = SSL_CTX_new(TLSv1_method());
+       if (!ctx) {
+               int err;
+               while ((err = ERR_get_error())) {
+                       DEBUG("Failed creating SSL context: %s",
+                             ERR_error_string(err, NULL));
+                       return NULL;
+               }
+       }
 
        /*
         * Save the config on the context so that callbacks which
@@ -1917,93 +2122,118 @@ static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf, int client)
                 * for our special string which indicates we should get the password
                 * programmatically.
                 */
-               const char* special_string = "Apple:UseCertAdmin";
-               if (strncmp(conf->private_key_password,
-                                       special_string,
-                                       strlen(special_string)) == 0)
-               {
+               char const* special_string = "Apple:UseCertAdmin";
+               if (strncmp(conf->private_key_password, special_string, strlen(special_string)) == 0) {
                        char cmd[256];
-                       const long max_password_len = 128;
-                       snprintf(cmd, sizeof(cmd) - 1,
-                                        "/usr/sbin/certadmin --get-private-key-passphrase \"%s\"",
-                                        conf->private_key_file);
+                       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);
 
-                       DEBUG2("rlm_eap: Getting private key passphrase using command \"%s\"", cmd);
+                       DEBUG2("tls: Getting private key passphrase using command \"%s\"", cmd);
 
                        FILE* cmd_pipe = popen(cmd, "r");
                        if (!cmd_pipe) {
-                               radlog(L_ERR, "TLS: %s command failed.  Unable to get private_key_password", cmd);
-                               radlog(L_ERR, "Error reading private_key_file %s", conf->private_key_file);
+                               ERROR("TLS: %s command failed.  Unable to get private_key_password", cmd);
+                               ERROR("Error reading private_key_file %s", conf->private_key_file);
                                return NULL;
                        }
 
-                       talloc_free(conf->private_key_password);
-                       conf->private_key_password = talloc_array(conf, char, max_password_len);
-                       if (!conf->private_key_password) {
-                               radlog(L_ERR, "TLS: Can't allocate space for private_key_password");
-                               radlog(L_ERR, "TLS: Error reading private_key_file %s", conf->private_key_file);
+                       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';
-                       DEBUG2("rlm_eap:  Password from command = \"%s\"", conf->private_key_password);
+                       password[strlen(password) - 1] = '\0';
+
+                       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) ||
            (conf->psk_password && !*conf->psk_password)) {
-               radlog(L_ERR, "Invalid PSK Configuration: psk_identity or psk_password are empty");
+               ERROR("Invalid PSK Configuration: psk_identity or psk_password are empty");
                return NULL;
        }
 
        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 ||
                    conf->ca_file || conf->ca_path) {
-                       radlog(L_ERR, "When PSKs are used, No certificate configuration is permitted");
+                       ERROR("When PSKs are used, No certificate configuration is permitted");
                        return NULL;
                }
 
                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);
                if (strlen(conf->psk_password) > (2 * PSK_MAX_PSK_LEN)) {
-                       radlog(L_ERR, "psk_hexphrase is too long (max %d)",
+                       ERROR("psk_hexphrase is too long (max %d)",
                               PSK_MAX_PSK_LEN);
-                       return NULL;                    
+                       return NULL;
                }
 
-               hex_len = fr_hex2bin(conf->psk_password,
-                                    (uint8_t *) buffer, 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)) {
-                       radlog(L_ERR, "psk_hexphrase is not all hex");
-                       return NULL;                    
+                       ERROR("psk_hexphrase is not all hex");
+                       return NULL;
                }
 
                goto post_ca;
        }
 #else
-       client = client;        /* -Wunused */
+       (void) client;  /* -Wunused */
 #endif
 
        /*
@@ -2019,14 +2249,14 @@ static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf, int client)
 
        if (type == SSL_FILETYPE_PEM) {
                if (!(SSL_CTX_use_certificate_chain_file(ctx, conf->certificate_file))) {
-                       radlog(L_ERR, "Error reading certificate file %s:%s",
+                       ERROR("Error reading certificate file %s:%s",
                               conf->certificate_file,
                               ERR_error_string(ERR_get_error(), NULL));
                        return NULL;
                }
 
        } else if (!(SSL_CTX_use_certificate_file(ctx, conf->certificate_file, type))) {
-               radlog(L_ERR, "Error reading certificate file %s:%s",
+               ERROR("Error reading certificate file %s:%s",
                       conf->certificate_file,
                       ERR_error_string(ERR_get_error(), NULL));
                return NULL;
@@ -2036,8 +2266,8 @@ static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf, int client)
 load_ca:
        if (conf->ca_file || conf->ca_path) {
                if (!SSL_CTX_load_verify_locations(ctx, conf->ca_file, conf->ca_path)) {
-                       radlog(L_ERR, "rlm_eap: SSL error %s", ERR_error_string(ERR_get_error(), NULL));
-                       radlog(L_ERR, "rlm_eap_tls: Error reading Trusted root CA list %s",conf->ca_file );
+                       ERROR("tls: SSL error %s", ERR_error_string(ERR_get_error(), NULL));
+                       ERROR("tls: Error reading Trusted root CA list %s",conf->ca_file );
                        return NULL;
                }
        }
@@ -2045,17 +2275,17 @@ load_ca:
 
        if (conf->private_key_file) {
                if (!(SSL_CTX_use_PrivateKey_file(ctx, conf->private_key_file, type))) {
-                       radlog(L_ERR, "Failed reading private key file %s:%s",
+                       ERROR("Failed reading private key file %s:%s",
                               conf->private_key_file,
                               ERR_error_string(ERR_get_error(), NULL));
                        return NULL;
                }
-               
+
                /*
                 * Check if the loaded private key is the right one
                 */
                if (!SSL_CTX_check_private_key(ctx)) {
-                       radlog(L_ERR, "Private key does not match the certificate public key");
+                       ERROR("Private key does not match the certificate public key");
                        return NULL;
                }
        }
@@ -2124,7 +2354,7 @@ post_ca:
 
        /*
         *      Callbacks, etc. for session resumption.
-        */                                             
+        */
        if (conf->session_cache_enable) {
                SSL_CTX_sess_set_new_cb(ctx, cbtls_new_session);
                SSL_CTX_sess_set_get_cb(ctx, cbtls_get_session);
@@ -2133,6 +2363,8 @@ 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, sess_free_vps);
+               if (FR_TLS_EX_INDEX_CERTS < 0)
+                       FR_TLS_EX_INDEX_CERTS = SSL_SESSION_get_ex_new_index(0, NULL, NULL, NULL, sess_free_certs);
        }
 
        /*
@@ -2140,13 +2372,13 @@ post_ca:
         */
 #ifdef X509_V_FLAG_CRL_CHECK
        if (conf->check_crl) {
-         certstore = SSL_CTX_get_cert_store(ctx);
-         if (certstore == NULL) {
-           radlog(L_ERR, "rlm_eap: SSL error %s", ERR_error_string(ERR_get_error(), NULL));
-           radlog(L_ERR, "rlm_eap_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
 
@@ -2164,10 +2396,12 @@ post_ca:
        }
 
        /* Load randomness */
-       if (!(RAND_load_file(conf->random_file, 1024*1024))) {
-               radlog(L_ERR, "rlm_eap: SSL error %s", ERR_error_string(ERR_get_error(), NULL));
-               radlog(L_ERR, "rlm_eap_tls: Error loading randomness");
-               return NULL;
+       if (conf->random_file) {
+               if (!(RAND_load_file(conf->random_file, 1024*10))) {
+                       ERROR("tls: SSL error %s", ERR_error_string(ERR_get_error(), NULL));
+                       ERROR("tls: Error loading randomness");
+                       return NULL;
+               }
        }
 
        /*
@@ -2175,7 +2409,7 @@ post_ca:
         */
        if (conf->cipher_list) {
                if (!SSL_CTX_set_cipher_list(ctx, conf->cipher_list)) {
-                       radlog(L_ERR, "rlm_eap_tls: Error setting cipher list");
+                       ERROR("tls: Error setting cipher list");
                        return NULL;
                }
        }
@@ -2232,10 +2466,8 @@ post_ca:
  *     added to automatically free the data when the CONF_SECTION
  *     is freed.
  */
-static void tls_server_conf_free(fr_tls_server_conf_t *conf)
+static int _tls_server_conf_free(fr_tls_server_conf_t *conf)
 {
-       if (!conf) return;
-
        if (conf->ctx) SSL_CTX_free(conf->ctx);
 
 #ifdef HAVE_OPENSSL_OCSP_H
@@ -2246,7 +2478,22 @@ static void tls_server_conf_free(fr_tls_server_conf_t *conf)
 #ifndef NDEBUG
        memset(conf, 0, sizeof(*conf));
 #endif
-       talloc_free(conf);
+       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;
 }
 
 
@@ -2260,19 +2507,15 @@ fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs)
         */
        conf = cf_data_find(cs, "tls-conf");
        if (conf) {
-               DEBUG(" debug: Using cached TLS configuration from previous invocation");
+               DEBUG("Using cached TLS configuration from previous invocation");
                return conf;
        }
 
-       conf = talloc_zero(cs, fr_tls_server_conf_t);
-       if (!conf) {
-               radlog(L_ERR, "Out of memory");
-               return NULL;
-       }
+       conf = tls_server_conf_alloc(cs);
 
        if (cf_section_parse(cs, conf, tls_server_config) < 0) {
        error:
-               tls_server_conf_free(conf);
+               talloc_free(conf);
                return NULL;
        }
 
@@ -2281,40 +2524,20 @@ fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs)
         */
        if (conf->fragment_size < 100) conf->fragment_size = 100;
 
-       /*
-        *      This magic makes the administrators life HUGELY easier
-        *      on initial deployments.
-        *
-        *      If the server starts up in debugging mode, AND the
-        *      bootstrap command is configured, AND it exists, AND
-        *      there is no server certificate
-        */
-       if (conf->make_cert_command && (debug_flag >= 2)) {
-               struct stat buf;
-
-               if ((stat(conf->make_cert_command, &buf) == 0) &&
-                   (stat(conf->certificate_file, &buf) < 0) &&
-                   (errno == ENOENT) &&
-                   (radius_exec_program(conf->make_cert_command, NULL, 1,
-                                        NULL, 0, NULL, NULL, 0) != 0)) {
-                       goto error;
-               }
-       }
-
        if (!conf->private_key_file) {
-               radlog(L_ERR, "TLS Server requires a private key file");
+               ERROR("TLS Server requires a private key file");
                goto error;
        }
 
        if (!conf->certificate_file) {
-               radlog(L_ERR, "TLS Server requires a certificate file");
+               ERROR("TLS Server requires a certificate file");
                goto error;
        }
 
        /*
         *      Initialize TLS
         */
-       conf->ctx = init_tls_ctx(conf, 0);
+       conf->ctx = tls_init_ctx(conf, 0);
        if (conf->ctx == NULL) {
                goto error;
        }
@@ -2328,9 +2551,13 @@ fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs)
                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) {
@@ -2339,20 +2566,20 @@ fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs)
 
        if (conf->verify_tmp_dir) {
                if (chmod(conf->verify_tmp_dir, S_IRWXU) < 0) {
-                       radlog(L_ERR, "Failed changing permissions on %s: %s", conf->verify_tmp_dir, strerror(errno));
+                       ERROR("Failed changing permissions on %s: %s", conf->verify_tmp_dir, fr_syserror(errno));
                        goto error;
                }
        }
 
        if (conf->verify_client_cert_cmd && !conf->verify_tmp_dir) {
-               radlog(L_ERR, "You MUST set the verify directory in order to use verify_client_cmd");
+               ERROR("You MUST set the verify directory in order to use verify_client_cmd");
                goto error;
        }
 
        /*
         *      Cache conf in cs in case we're asked to parse this again.
         */
-       cf_data_add(cs, "tls-conf", conf, (void *)(void *) tls_server_conf_free);
+       cf_data_add(cs, "tls-conf", conf, NULL);
 
        return conf;
 }
@@ -2363,19 +2590,15 @@ fr_tls_server_conf_t *tls_client_conf_parse(CONF_SECTION *cs)
 
        conf = cf_data_find(cs, "tls-conf");
        if (conf) {
-               DEBUG(" debug: Using cached TLS configuration from previous invocation");
+               DEBUG("Using cached TLS configuration from previous invocation");
                return conf;
        }
 
-       conf = talloc_zero(cs, fr_tls_server_conf_t);
-       if (!conf) {
-               radlog(L_ERR, "Out of memory");
-               return NULL;
-       }
+       conf = tls_server_conf_alloc(cs);
 
        if (cf_section_parse(cs, conf, tls_client_config) < 0) {
        error:
-               tls_server_conf_free(conf);
+               talloc_free(conf);
                return NULL;
        }
 
@@ -2387,20 +2610,25 @@ fr_tls_server_conf_t *tls_client_conf_parse(CONF_SECTION *cs)
        /*
         *      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) {
                goto error;
        }
 
-       cf_data_add(cs, "tls-conf", conf, (void *)(void *) tls_server_conf_free);
+       cf_data_add(cs, "tls-conf", conf, NULL);
 
        return conf;
 }
@@ -2409,10 +2637,13 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
 {
        VALUE_PAIR *vp, *vps = NULL;
        fr_tls_server_conf_t *conf;
+       TALLOC_CTX *talloc_ctx;
 
        conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssn->ssl, FR_TLS_EX_INDEX_CONF);
        rad_assert(conf != NULL);
 
+       talloc_ctx = SSL_get_ex_data(ssn->ssl, FR_TLS_EX_INDEX_TALLOC);
+
        /*
         *      If there's no session resumption, delete the entry
         *      from the cache.  This means either it's disabled
@@ -2434,10 +2665,10 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
                 *      not allowed,
                 */
                if (SSL_session_reused(ssn->ssl)) {
-                       RDEBUG("FAIL: Forcibly stopping session resumption as it is not allowed.");
+                       RDEBUG("FAIL: Forcibly stopping session resumption as it is not allowed");
                        return -1;
                }
-               
+
                /*
                 *      Else resumption IS allowed, so we store the
                 *      user data in the cache.
@@ -2450,15 +2681,18 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
                size = ssn->ssl->session->session_id_length;
                if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
 
-               fr_bin2hex(ssn->ssl->session->session_id, buffer, size);
+               fr_bin2hex(buffer, ssn->ssl->session->session_id, size);
 
-               vp = paircopy2(request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
+               vp = paircopy2(talloc_ctx, request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
                if (vp) pairadd(&vps, vp);
-               
-               vp = paircopy2(request->packet->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY);
+
+               vp = paircopy2(talloc_ctx, request->packet->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY);
                if (vp) pairadd(&vps, vp);
-               
-               vp = paircopy2(request->reply->vps, PW_CACHED_SESSION_POLICY, 0, TAG_ANY);
+
+               vp = paircopy2(talloc_ctx, request->reply->vps, PW_CHARGEABLE_USER_IDENTITY, 0, TAG_ANY);
+               if (vp) pairadd(&vps, vp);
+
+               vp = paircopy2(talloc_ctx, request->reply->vps, PW_CACHED_SESSION_POLICY, 0, TAG_ANY);
                if (vp) pairadd(&vps, vp);
 
                certs = (VALUE_PAIR **)SSL_get_ex_data(ssn->ssl, FR_TLS_EX_INDEX_CERTS);
@@ -2467,7 +2701,11 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
                 *      Hmm... the certs should probably be session data.
                 */
                if (certs) {
-                       pairadd(&vps, paircopy(*certs));
+                       /*
+                        *      @todo: some go into reply, others into
+                        *      request
+                        */
+                       pairadd(&vps, paircopy(talloc_ctx, *certs));
                }
 
                if (vps) {
@@ -2484,20 +2722,23 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
                                        );
                                vp_file = fopen(filename, "w");
                                if (vp_file == NULL) {
-                                       RDEBUG2("Could not write session VPs to persistent cache: %s", strerror(errno));
+                                       RDEBUG2("Could not write session VPs to persistent cache: %s", fr_syserror(errno));
                                } else {
+                                       vp_cursor_t cursor;
                                        /* generate a dummy user-style entry which is easy to read back */
                                        fprintf(vp_file, "# SSL cached session\n");
                                        fprintf(vp_file, "%s\n", buffer);
-                                       for (vp=vps; vp; vp = vp->next) {
+                                       for (vp = fr_cursor_init(&cursor, &vps);
+                                            vp;
+                                            vp = fr_cursor_next(&cursor)) {
                                                vp_prints(buf, sizeof(buf), vp);
-                                               fprintf(vp_file, "\t%s%s\n", buf, vp->next ? "," : "");
+                                               fprintf(vp_file, "\t%s,\n", buf);
                                        }
                                        fclose(vp_file);
                                }
                        }
                } else {
-                       RDEBUG2W("No information to cache: session caching will be disabled for session %s", buffer);
+                       RWDEBUG2("No information to cache: session caching will be disabled for session %s", buffer);
                        SSL_CTX_remove_session(ssn->ctx,
                                               ssn->ssl->session);
                }
@@ -2513,21 +2754,23 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
                size = ssn->ssl->session->session_id_length;
                if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
 
-               fr_bin2hex(ssn->ssl->session->session_id, buffer, size);
+               fr_bin2hex(buffer, ssn->ssl->session->session_id, size);
 
-       
                vps = SSL_SESSION_get_ex_data(ssn->ssl->session,
                                             FR_TLS_EX_INDEX_VPS);
                if (!vps) {
-                       RDEBUGW("No information in cached session %s", buffer);
+                       RWDEBUG("No information in cached session %s", buffer);
                        return -1;
 
                } else {
-                       RDEBUG("Adding cached attributes for session %s:",
-                              buffer);
+                       vp_cursor_t cursor;
+
+                       RDEBUG("Adding cached attributes for session %s:", buffer);
                        debug_pair_list(vps);
 
-                       for (vp = vps; vp != NULL; vp = vp->next) {
+                       for (vp = fr_cursor_init(&cursor, &vps);
+                            vp;
+                            vp = fr_cursor_next(&cursor)) {
                                /*
                                 *      TLS-* attrs get added back to
                                 *      the request list.
@@ -2536,10 +2779,10 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
                                    (vp->da->attr >= 1910) &&
                                    (vp->da->attr < 1929)) {
                                        pairadd(&request->packet->vps,
-                                               paircopyvp(vp));
+                                               paircopyvp(request->packet, vp));
                                } else {
                                        pairadd(&request->reply->vps,
-                                               paircopyvp(vp));
+                                               paircopyvp(request->reply, vp));
                                }
                        }
 
@@ -2578,11 +2821,11 @@ void tls_fail(tls_session_t *ssn)
 
 fr_tls_status_t tls_application_data(tls_session_t *ssn,
                                     REQUEST *request)
-                               
+
 {
        int err;
 
-       /*      
+       /*
         *      Decrypt the complete record.
         */
        err = BIO_write(ssn->into_ssl, ssn->dirty_in.data,
@@ -2593,14 +2836,14 @@ fr_tls_status_t tls_application_data(tls_session_t *ssn,
                       ssn->dirty_in.used, err);
                return FR_TLS_FAIL;
        }
-       
+
        /*
         *      Clear the dirty buffer now that we are done with it
         *      and init the clean_out buffer to store decrypted data
         */
        record_init(&ssn->dirty_in);
        record_init(&ssn->clean_out);
-       
+
        /*
         *      Read (and decrypt) the tunneled data from the
         *      SSL session, and put it into the decrypted
@@ -2608,12 +2851,12 @@ fr_tls_status_t tls_application_data(tls_session_t *ssn,
         */
        err = SSL_read(ssn->ssl, ssn->clean_out.data,
                       sizeof(ssn->clean_out.data));
-       
+
        if (err < 0) {
                int code;
 
                RDEBUG("SSL_read Error");
-               
+
                code = SSL_get_error(ssn->ssl, err);
                switch (code) {
                case SSL_ERROR_WANT_READ:
@@ -2625,7 +2868,8 @@ fr_tls_status_t tls_application_data(tls_session_t *ssn,
                        break;
 
                default:
-                       DEBUG("Error in fragmentation logic: ?");
+                       DEBUG("Error in fragmentation logic: %s",
+                             ERR_error_string(code, NULL));
 
                        /*
                         *      FIXME: Call int_ssl_check?
@@ -2634,16 +2878,16 @@ fr_tls_status_t tls_application_data(tls_session_t *ssn,
                }
                return FR_TLS_FAIL;
        }
-       
+
        if (err == 0) {
-               RDEBUGW("No data inside of the tunnel.");
+               RWDEBUG("No data inside of the tunnel");
        }
-       
+
        /*
         *      Passed all checks, successfully decrypted data
         */
        ssn->clean_out.used = err;
-       
+
        return FR_TLS_OK;
 }
 
@@ -2659,16 +2903,16 @@ fr_tls_status_t tls_ack_handler(tls_session_t *ssn, REQUEST *request)
        RDEBUG2("Received TLS ACK");
 
        if (ssn == NULL){
-               radlog_request(L_ERR, 0, request, "FAIL: Unexpected ACK received.  Could not obtain session information.");
+               RERROR("FAIL: Unexpected ACK received.  Could not obtain session information");
                return FR_TLS_INVALID;
        }
        if (ssn->info.initialized == 0) {
-               RDEBUG("No SSL info available. Waiting for more SSL data.");
+               RDEBUG("No SSL info available. Waiting for more SSL data");
                return FR_TLS_REQUEST;
        }
        if ((ssn->info.content_type == handshake) &&
            (ssn->info.origin == 0)) {
-               radlog_request(L_ERR, 0, request, "FAIL: ACK without earlier message.");
+               RERROR("FAIL: ACK without earlier message");
                return FR_TLS_INVALID;
        }
 
@@ -2698,17 +2942,18 @@ fr_tls_status_t tls_ack_handler(tls_session_t *ssn, REQUEST *request)
        case application_data:
                RDEBUG2("ACK handshake fragment handler in application data");
                return FR_TLS_REQUEST;
-                                               
+
                /*
                 *      For the rest of the conditions, switch over
                 *      to the default section below.
                 */
        default:
                RDEBUG2("ACK default");
-               radlog_request(L_ERR, 0, request, "Invalid ACK received: %d",
+               RERROR("Invalid ACK received: %d",
                       ssn->info.content_type);
                return FR_TLS_INVALID;
        }
 }
 
 #endif /* WITH_TLS */
+