const char *OpenSSLQueryCipher(STREAM *S) { void *ptr; if (! S) return(NULL); ptr=STREAMGetItem(S,"LIBUSEFUL-SSL-CTX"); if (! ptr) return(NULL); #ifdef HAVE_LIBSSL const SSL_CIPHER *Cipher; char *Tempstr=NULL; Cipher=SSL_get_current_cipher((const SSL *) ptr); if (Cipher) { Tempstr=FormatStr(Tempstr,"%d bit %s",SSL_CIPHER_get_bits(Cipher,NULL), SSL_CIPHER_get_name(Cipher)); STREAMSetValue(S,"SSL-Cipher",Tempstr); Tempstr=SetStrLen(Tempstr,1024); Tempstr=SSL_CIPHER_description(Cipher, Tempstr, 1024); STREAMSetValue(S,"SSL-Cipher-Details",Tempstr); } DestroyString(Tempstr); return(STREAMGetValue(S,"SSL-Cipher")); #else return(NULL); #endif }
static int openssl_ssl_current_cipher(lua_State *L) { SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl"); const SSL_CIPHER* c = SSL_get_current_cipher(s); if (c) { int bits, algbits; char err[LUAL_BUFFERSIZE] = {0};; lua_newtable(L); AUXILIAR_SET(L, -1, "name", SSL_CIPHER_get_name(c), string); AUXILIAR_SET(L, -1, "version", SSL_CIPHER_get_version(c), string); #if OPENSSL_VERSION_NUMBER > 0x10000000L AUXILIAR_SET(L, -1, "id", SSL_CIPHER_get_id(c), integer); #endif bits = SSL_CIPHER_get_bits(c, &algbits); AUXILIAR_SET(L, -1, "bits", bits, integer); AUXILIAR_SET(L, -1, "algbits", algbits, integer); AUXILIAR_SET(L, -1, "description", SSL_CIPHER_description((SSL_CIPHER*)c, err, sizeof(err)), string); return 1; } return 0; }
static int tlso_session_strength( tls_session *sess ) { tlso_session *s = (tlso_session *)sess; return SSL_CIPHER_get_bits(SSL_get_current_cipher(s), NULL); }
static const char * openssl_iostream_get_security_string(struct ssl_iostream *ssl_io) { const SSL_CIPHER *cipher; #ifdef HAVE_SSL_COMPRESSION const COMP_METHOD *comp; #endif const char *comp_str; int bits, alg_bits; if (!ssl_io->handshaked) return ""; cipher = SSL_get_current_cipher(ssl_io->ssl); bits = SSL_CIPHER_get_bits(cipher, &alg_bits); #ifdef HAVE_SSL_COMPRESSION comp = SSL_get_current_compression(ssl_io->ssl); comp_str = comp == NULL ? "" : t_strconcat(" ", SSL_COMP_get_name(comp), NULL); #else comp_str = ""; #endif return t_strdup_printf("%s with cipher %s (%d/%d bits)%s", SSL_get_version(ssl_io->ssl), SSL_CIPHER_get_name(cipher), bits, alg_bits, comp_str); }
static int get_bits(str* res, int* i, sip_msg_t* msg) { str bits; int b; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { INFO("TLS connection not found in select_bits\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; b = SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), 0); bits.s = int2str(b, &bits.len); if (bits.len >= 1024) { ERR("Bits string too long\n"); goto err; } memcpy(buf, bits.s, bits.len); res->s = buf; res->len = bits.len; if (i) *i = b; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return -1; }
static int ssl_socket_open (CONNECTION * conn) { sslsockdata *data; int maxbits; if (raw_socket_open (conn) < 0) return -1; data = (sslsockdata *) safe_calloc (1, sizeof (sslsockdata)); conn->sockdata = data; data->ctx = SSL_CTX_new (SSLv23_client_method ()); /* disable SSL protocols as needed */ if (!option(OPTTLSV1)) { SSL_CTX_set_options(data->ctx, SSL_OP_NO_TLSv1); } /* TLSv1.1/1.2 support was added in OpenSSL 1.0.1, but some OS distros such * as Fedora 17 are on OpenSSL 1.0.0. */ #ifdef SSL_OP_NO_TLSv1_1 if (!option(OPTTLSV1_1)) { SSL_CTX_set_options(data->ctx, SSL_OP_NO_TLSv1_1); } #endif #ifdef SSL_OP_NO_TLSv1_2 if (!option(OPTTLSV1_2)) { SSL_CTX_set_options(data->ctx, SSL_OP_NO_TLSv1_2); } #endif if (!option(OPTSSLV2)) { SSL_CTX_set_options(data->ctx, SSL_OP_NO_SSLv2); } if (!option(OPTSSLV3)) { SSL_CTX_set_options(data->ctx, SSL_OP_NO_SSLv3); } ssl_get_client_cert(data, conn); data->ssl = SSL_new (data->ctx); SSL_set_fd (data->ssl, conn->fd); if (ssl_negotiate(conn, data)) { mutt_socket_close (conn); return -1; } data->isopen = 1; conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (data->ssl), &maxbits); return 0; }
/** * Adds Ciphers to the Cipher List structure * * @param options Options for this run * @param ssl_method SSL method to populate ciphers for. * @return Boolean: true = success | false = error */ int populate_ciphers(struct sslCheckOptions *options, const SSL_METHOD *ssl_method) { struct sslCipher *cipher_ptr; int i; // STACK_OF is a sign that you should be using C++ :) STACK_OF(SSL_CIPHER) *cipher_list; SSL_CTX *ctx; SSL *ssl = NULL; ctx = SSL_CTX_new(ssl_method); if (ctx == NULL) { printf("%sERROR: Could not create CTX object.%s\n", COL_RED, RESET); return false; } SSL_CTX_set_cipher_list(ctx, "ALL:COMPLEMENTOFALL"); ssl = SSL_new(ctx); if (ssl == NULL) { printf("%sERROR: Could not create SSL object.%s\n", COL_RED, RESET); SSL_CTX_free(ctx); return false; } cipher_list = SSL_get_ciphers(ssl); if (options->ciphers != NULL) { cipher_ptr = options->ciphers; while (cipher_ptr->next != NULL) cipher_ptr = cipher_ptr->next; } // Create Cipher Struct Entries... for (i = 0; i < sk_SSL_CIPHER_num(cipher_list); i++) { if (options->ciphers == NULL) { options->ciphers = malloc(sizeof(struct sslCipher)); cipher_ptr = options->ciphers; } else { cipher_ptr->next = malloc(sizeof(struct sslCipher)); cipher_ptr = cipher_ptr->next; } memset(cipher_ptr, 0, sizeof(struct sslCipher)); cipher_ptr->next = NULL; // Add cipher information... cipher_ptr->sslMethod = ssl_method; cipher_ptr->name = SSL_CIPHER_get_name(sk_SSL_CIPHER_value(cipher_list, i)); cipher_ptr->version = SSL_CIPHER_get_version(sk_SSL_CIPHER_value(cipher_list, i)); SSL_CIPHER_description(sk_SSL_CIPHER_value(cipher_list, i), cipher_ptr->description, sizeof(cipher_ptr->description) - 1); cipher_ptr->bits = SSL_CIPHER_get_bits(sk_SSL_CIPHER_value(cipher_list, i), &cipher_ptr->alg_bits); } SSL_free(ssl); SSL_CTX_free(ctx); return true; }
int pn_ssl_get_ssf(pn_ssl_t *ssl0) { const SSL_CIPHER *c; pni_ssl_t *ssl = get_ssl_internal(ssl0); if (ssl && ssl->ssl && (c = SSL_get_current_cipher( ssl->ssl ))) { return SSL_CIPHER_get_bits(c, NULL); } return 0; }
/* SSL info callback, this is used to trace engine state changes * and to check when the handshake is finished, so we can display * some cipher and session information and process callbacks. */ void ssl_info(SSL *ssl, int where, int ret) { int sock; X509 *cert; char buf[256]; ssl_appdata *data; SSL_CIPHER *cipher; int secret, processed; /* We're doing non-blocking IO, so we check here if the handshake has finished */ if (where & SSL_CB_HANDSHAKE_DONE) { if (!(data = (ssl_appdata *) SSL_get_app_data(ssl))) return; /* Callback for completed handshake. Cheaper and more convenient than using H_tls */ sock = SSL_get_fd(ssl); if (data->cb) data->cb(sock); /* Call TLS binds. We allow scripts to take over or disable displaying of certificate information. */ if (check_tcl_tls(sock)) return; putlog(data->loglevel, "*", "TLS: handshake successful. Secure connection " "established."); if ((cert = SSL_get_peer_certificate(ssl))) ssl_showcert(cert, data->loglevel); else putlog(data->loglevel, "*", "TLS: peer did not present a certificate"); /* Display cipher information */ cipher = SSL_get_current_cipher(ssl); processed = SSL_CIPHER_get_bits(cipher, &secret); putlog(data->loglevel, "*", "TLS: cipher used: %s %s; %d bits (%d secret)", SSL_CIPHER_get_name(cipher), SSL_CIPHER_get_version(cipher), processed, secret); /* secret are the actually secret bits. If processed and secret differ, the rest of the bits are fixed, i.e. for limited export ciphers */ /* More verbose information, for debugging only */ SSL_CIPHER_description(cipher, buf, sizeof buf); debug1("TLS: cipher details: %s", buf); } /* Display the state of the engine for debugging purposes */ debug1("TLS: state change: %s", SSL_state_string_long(ssl)); }
int tls_init_data_session(const int fd, const int passive) { const SSL_CIPHER *cipher; int ret; int ret_; (void) passive; if (tls_ctx == NULL) { logfile(LOG_ERR, MSG_TLS_NO_CTX); tls_error(__LINE__, 0); } if (tls_data_cnx != NULL) { tls_close_session(&tls_data_cnx); } else if ((tls_data_cnx = SSL_new(tls_ctx)) == NULL) { tls_error(__LINE__, 0); } if (SSL_set_fd(tls_data_cnx, fd) != 1) { tls_error(__LINE__, 0); } SSL_set_accept_state(tls_data_cnx); for (;;) { ret = SSL_accept(tls_data_cnx); if (ret <= 0) { ret_ = SSL_get_error(tls_data_cnx, ret); if (ret == -1 && (ret_ == SSL_ERROR_WANT_READ || ret_ == SSL_ERROR_WANT_WRITE)) { continue; } logfile(LOG_INFO, MSG_LOGOUT); _EXIT(EXIT_FAILURE); } break; } # if ONLY_ACCEPT_REUSED_SSL_SESSIONS if (broken_client_compat == 0 && SSL_session_reused(tls_data_cnx) == 0) { tls_error(__LINE__, 0); } # endif if ((cipher = SSL_get_current_cipher(tls_data_cnx)) != NULL) { int strength_bits = SSL_CIPHER_get_bits(cipher, NULL); logfile(LOG_INFO, MSG_TLS_INFO, SSL_CIPHER_get_version(cipher), SSL_CIPHER_get_name(cipher), strength_bits); if (strength_bits < MINIMAL_CIPHER_STRENGTH_BITS) { die(534, LOG_ERR, MSG_TLS_WEAK); } } return 0; }
static VALUE ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher) { VALUE ary; int bits, alg_bits; ary = rb_ary_new2(4); rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_name(cipher))); rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_version(cipher))); bits = SSL_CIPHER_get_bits(cipher, &alg_bits); rb_ary_push(ary, INT2FIX(bits)); rb_ary_push(ary, INT2FIX(alg_bits)); return ary; }
struct chiper_info * _SSL_get_cipher_info (SSL * ssl) { SSL_CIPHER *c; c = SSL_get_current_cipher (ssl); strncpy (chiper_info.version, SSL_CIPHER_get_version (c), sizeof (chiper_info.version)); strncpy (chiper_info.chiper, SSL_CIPHER_get_name (c), sizeof (chiper_info.chiper)); SSL_CIPHER_get_bits (c, &chiper_info.chiper_bits); return (&chiper_info); }
return the certificate even if it wasn't validated."); static PyObject *PySSL_cipher (PySSLObject *self) { PyObject *retval, *v; SSL_CIPHER *current; char *cipher_name; char *cipher_protocol; if (self->ssl == NULL) return Py_None; current = SSL_get_current_cipher(self->ssl); if (current == NULL) return Py_None; retval = PyTuple_New(3); if (retval == NULL) return NULL; cipher_name = (char *) SSL_CIPHER_get_name(current); if (cipher_name == NULL) { PyTuple_SET_ITEM(retval, 0, Py_None); } else { v = PyUnicode_FromString(cipher_name); if (v == NULL) goto fail0; PyTuple_SET_ITEM(retval, 0, v); } cipher_protocol = SSL_CIPHER_get_version(current); if (cipher_protocol == NULL) { PyTuple_SET_ITEM(retval, 1, Py_None); } else { v = PyUnicode_FromString(cipher_protocol); if (v == NULL) goto fail0; PyTuple_SET_ITEM(retval, 1, v); } v = PyLong_FromLong(SSL_CIPHER_get_bits(current, NULL)); if (v == NULL) goto fail0; PyTuple_SET_ITEM(retval, 2, v); return retval; fail0: Py_DECREF(retval); return NULL; }
/** * Return information about the connection. */ static int meth_info(lua_State *L) { int bits = 0; int algbits = 0; char buf[256] = {0}; const SSL_CIPHER *cipher; p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); cipher = SSL_get_current_cipher(ssl->ssl); if (!cipher) return 0; SSL_CIPHER_description(cipher, buf, sizeof(buf)); bits = SSL_CIPHER_get_bits(cipher, &algbits); lua_pushstring(L, buf); lua_pushnumber(L, bits); lua_pushnumber(L, algbits); return 3; }
void SSLGetSessionCipher(SSL* pSSLSession, char* pszBuffer, int iBufferSize) { SSL_CIPHER* pCipher = SSL_get_current_cipher(pSSLSession); SetEmptyString(pszBuffer); if(pCipher) { SysSNPrintf(pszBuffer, iBufferSize, "protocol=%s, cipher=%s(%d)", SSL_CIPHER_get_version(pCipher), SSL_CIPHER_get_name(pCipher), SSL_CIPHER_get_bits(pCipher, NULL)); } }
int ssl_session_vars(SSL *ssl) { char *x; SSL_SESSION *session; int n; int m; const SSL_CIPHER *cipher; unsigned char u; unsigned char c; if (!env_str("SSL_PROTOCOL",SSL_get_version(ssl))) return 0; session = SSL_get_session(ssl); x = session->session_id; n = session->session_id_length; if (!stralloc_ready(&btemp,2 * n)) return 0; btemp.len = 2 * n; while (n--) { u = x[n]; c = '0' + (u & 15); if (c > '0' + 9) c += 'a' - '0' - 10; btemp.s[2 * n + 1] = c; u >>= 4; c = '0' + (u & 15); if (c > '0' + 9) c += 'a' - '0' - 10; btemp.s[2 * n] = c; } if (!env_val("SSL_SESSION_ID",btemp.s,btemp.len)) return 0; if (!env_str("SSL_CIPHER",SSL_get_cipher_name(ssl))) return 0; cipher = SSL_get_current_cipher(ssl); if (!cipher) return 0; n = SSL_CIPHER_get_bits(cipher,&m); if (!env_str("SSL_CIPHER_EXPORT",n < 56 ? "true" : "false")) return 0; if (!env_val("SSL_CIPHER_USEKEYSIZE",strnum,fmt_ulong(strnum,n))) return 0; if (!env_val("SSL_CIPHER_ALGKEYSIZE",strnum,fmt_ulong(strnum,m))) return 0; if (!env_str("SSL_VERSION_INTERFACE","ucspi-ssl")) return 0; if (!env_str("SSL_VERSION_LIBRARY",OPENSSL_VERSION_TEXT)) return 0; return 1; }
static void print_cipher(CLI * c) { SSL_CIPHER *cipher; const COMP_METHOD *compression, *expansion; if (global_options.debug_level < LOG_INFO) return; cipher = (SSL_CIPHER *) SSL_get_current_cipher(c->ssl); s_log(LOG_INFO, "Negotiated %s ciphersuite: %s (%d-bit encryption)", SSL_CIPHER_get_version(cipher), SSL_CIPHER_get_name(cipher), SSL_CIPHER_get_bits(cipher, NULL)); #if OPENSSL_VERSION_NUMBER>=0x0090800fL compression = SSL_get_current_compression(c->ssl); expansion = SSL_get_current_expansion(c->ssl); s_log(LOG_INFO, "Compression: %s, expansion: %s", compression ? SSL_COMP_get_name(compression) : "null", expansion ? SSL_COMP_get_name(expansion) : "null"); #endif }
NOEXPORT void print_cipher(CLI *c) { /* print negotiated cipher */ SSL_CIPHER *cipher; #if !defined(OPENSSL_NO_COMP) && OPENSSL_VERSION_NUMBER>=0x0090800fL const COMP_METHOD *compression, *expansion; #endif if(global_options.debug_level<LOG_INFO) /* performance optimization */ return; cipher=(SSL_CIPHER *)SSL_get_current_cipher(c->ssl); s_log(LOG_INFO, "Negotiated %s ciphersuite: %s (%d-bit encryption)", SSL_CIPHER_get_version(cipher), SSL_CIPHER_get_name(cipher), SSL_CIPHER_get_bits(cipher, NULL)); #if !defined(OPENSSL_NO_COMP) && OPENSSL_VERSION_NUMBER>=0x0090800fL compression=SSL_get_current_compression(c->ssl); expansion=SSL_get_current_expansion(c->ssl); s_log(LOG_INFO, "Compression: %s, expansion: %s", compression ? SSL_COMP_get_name(compression) : "null", expansion ? SSL_COMP_get_name(expansion) : "null"); #endif }
bool SSLConnection::doOpen() { if (!did_init) return false; ctx = SSL_CTX_new (SSLv23_client_method ()); /* disable SSL protocols as needed */ if (!UseTLS1) { SSL_CTX_set_options (ctx, SSL_OP_NO_TLSv1); } if (!UseSSL3) { SSL_CTX_set_options (ctx, SSL_OP_NO_SSLv3); } if (!UseTLS1 && !UseSSL3) return false; getClientCert (); ssl = SSL_new (ctx); SSL_set_fd (ssl,fd); if (!negotiate ()) return false; int maxbits; ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (ssl),&maxbits); buffer_t msg; buffer_init(&msg); buffer_add_str(&msg,_("SSL/TLS connection using "),-1); buffer_add_str(&msg,SSL_get_cipher_version(ssl),-1); buffer_add_str(&msg," (",2); buffer_add_str(&msg,SSL_get_cipher_name(ssl),-1); buffer_add_ch(&msg,')'); displayProgress.emit(&msg); buffer_free(&msg); return true; }
int tls_init_new_session(void) { const SSL_CIPHER *cipher; int ret; int ret_; if (tls_ctx == NULL || (tls_cnx = SSL_new(tls_ctx)) == NULL) { tls_error(__LINE__, 0); } if (SSL_set_fd(tls_cnx, clientfd) != 1) { tls_error(__LINE__, 0); } SSL_set_accept_state(tls_cnx); for (;;) { ret = SSL_accept(tls_cnx); if (ret != 1) { ret_ = SSL_get_error(tls_cnx, ret); if (ret == -1 && (ret_ == SSL_ERROR_WANT_READ || ret_ == SSL_ERROR_WANT_WRITE)) { continue; } die(400, LOG_WARNING, MSG_TLS_NEEDED); } break; } if ((cipher = SSL_get_current_cipher(tls_cnx)) != NULL) { int strength_bits = SSL_CIPHER_get_bits(cipher, NULL); logfile(LOG_INFO, MSG_TLS_INFO, SSL_CIPHER_get_version(cipher), SSL_CIPHER_get_name(cipher), strength_bits); if (strength_bits < MINIMAL_CIPHER_STRENGTH_BITS) { die(534, LOG_ERR, MSG_TLS_WEAK); } } return 0; }
int tlsops_bits(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { str bits; int b; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { LM_INFO("TLS connection not found in select_bits\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; b = SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), 0); bits.s = int2str(b, &bits.len); if (bits.len >= 1024) { LM_ERR("bits string too long\n"); goto err; } memcpy(buf, bits.s, bits.len); res->rs.s = buf; res->rs.len = bits.len; res->ri = b; res->flags = PV_VAL_STR | PV_VAL_INT; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return pv_get_null(msg, param, res); }
/* * This is the actual startup routine for the connection. We expect that the * buffers are flushed and the "220 Ready to start TLS" was received by us, * so that we can immediately start the TLS handshake process. */ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) { int sts; int protomask; const char *cipher_list; SSL_SESSION *session = 0; SSL_CIPHER_const SSL_CIPHER *cipher; X509 *peercert; TLS_SESS_STATE *TLScontext; TLS_APPL_STATE *app_ctx = props->ctx; char *myserverid; int log_mask = app_ctx->log_mask; /* * When certificate verification is required, log trust chain validation * errors even when disabled by default for opportunistic sessions. For * DANE this only applies when using trust-anchor associations. */ if (TLS_MUST_TRUST(props->tls_level) && (!TLS_DANE_BASED(props->tls_level) || TLS_DANE_HASTA(props->dane))) log_mask |= TLS_LOG_UNTRUSTED; if (log_mask & TLS_LOG_VERBOSE) msg_info("setting up TLS connection to %s", props->namaddr); /* * First make sure we have valid protocol and cipher parameters * * Per-session protocol restrictions must be applied to the SSL connection, * as restrictions in the global context cannot be cleared. */ protomask = tls_protocol_mask(props->protocols); if (protomask == TLS_PROTOCOL_INVALID) { /* tls_protocol_mask() logs no warning. */ msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session", props->namaddr, props->protocols); return (0); } /* DANE requires SSLv3 or later, not SSLv2. */ if (TLS_DANE_BASED(props->tls_level)) protomask |= TLS_PROTOCOL_SSLv2; /* * Per session cipher selection for sessions with mandatory encryption * * The cipherlist is applied to the global SSL context, since it is likely * to stay the same between connections, so we make use of a 1-element * cache to return the same result for identical inputs. */ cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, props->cipher_exclusions); if (cipher_list == 0) { msg_warn("%s: %s: aborting TLS session", props->namaddr, vstring_str(app_ctx->why)); return (0); } if (log_mask & TLS_LOG_VERBOSE) msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list); /* * OpenSSL will ignore cached sessions that use the wrong protocol. So we * do not need to filter out cached sessions with the "wrong" protocol, * rather OpenSSL will simply negotiate a new session. * * We salt the session lookup key with the protocol list, so that sessions * found in the cache are plausibly acceptable. * * By the time a TLS client is negotiating ciphers it has already offered to * re-use a session, it is too late to renege on the offer. So we must * not attempt to re-use sessions whose ciphers are too weak. We salt the * session lookup key with the cipher list, so that sessions found in the * cache are always acceptable. * * With DANE, (more generally any TLScontext where we specified explicit * trust-anchor or end-entity certificates) the verification status of * the SSL session depends on the specified list. Since we verify the * certificate only during the initial handshake, we must segregate * sessions with different TA lists. Note, that TA re-verification is * not possible with cached sessions, since these don't hold the complete * peer trust chain. Therefore, we compute a digest of the sorted TA * parameters and append it to the serverid. */ myserverid = tls_serverid_digest(props, protomask, cipher_list); /* * Allocate a new TLScontext for the new connection and get an SSL * structure. Add the location of TLScontext to the SSL to later retrieve * the information inside the tls_verify_certificate_callback(). * * If session caching was enabled when TLS was initialized, the cache type * is stored in the client SSL context. */ TLScontext = tls_alloc_sess_context(log_mask, props->namaddr); TLScontext->cache_type = app_ctx->cache_type; TLScontext->serverid = myserverid; TLScontext->stream = props->stream; TLScontext->mdalg = props->mdalg; /* Alias DANE digest info from props */ TLScontext->dane = props->dane; if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) { msg_warn("Could not allocate 'TLScontext->con' with SSL_new()"); tls_print_errors(); tls_free_context(TLScontext); return (0); } if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { msg_warn("Could not set application data for 'TLScontext->con'"); tls_print_errors(); tls_free_context(TLScontext); return (0); } /* * Apply session protocol restrictions. */ if (protomask != 0) SSL_set_options(TLScontext->con, TLS_SSL_OP_PROTOMASK(protomask)); /* * XXX To avoid memory leaks we must always call SSL_SESSION_free() after * calling SSL_set_session(), regardless of whether or not the session * will be reused. */ if (TLScontext->cache_type) { session = load_clnt_session(TLScontext); if (session) { SSL_set_session(TLScontext->con, session); SSL_SESSION_free(session); /* 200411 */ } } #ifdef TLSEXT_MAXLEN_host_name if (TLS_DANE_BASED(props->tls_level) && strlen(props->host) <= TLSEXT_MAXLEN_host_name) { /* * With DANE sessions, send an SNI hint. We don't care whether the * server reports finding a matching certificate or not, so no * callback is required to process the server response. Our use of * SNI is limited to giving servers that are (mis)configured to use * SNI the best opportunity to find the certificate they promised via * the associated TLSA RRs. (Generally, server administrators should * avoid SNI, and there are no plans to support SNI in the Postfix * SMTP server). * * Since the hostname is DNSSEC-validated, it must be a DNS FQDN and * thererefore valid for use with SNI. Failure to set a valid SNI * hostname is a memory allocation error, and thus transient. Since * we must not cache the session if we failed to send the SNI name, * we have little choice but to abort. */ if (!SSL_set_tlsext_host_name(TLScontext->con, props->host)) { msg_warn("%s: error setting SNI hostname to: %s", props->namaddr, props->host); tls_free_context(TLScontext); return (0); } if (log_mask & TLS_LOG_DEBUG) msg_info("%s: SNI hostname: %s", props->namaddr, props->host); } #endif /* * Before really starting anything, try to seed the PRNG a little bit * more. */ tls_int_seed(); (void) tls_ext_seed(var_tls_daemon_rand_bytes); /* * Initialize the SSL connection to connect state. This should not be * necessary anymore since 0.9.3, but the call is still in the library * and maintaining compatibility never hurts. */ SSL_set_connect_state(TLScontext->con); /* * Connect the SSL connection with the network socket. */ if (SSL_set_fd(TLScontext->con, vstream_fileno(props->stream)) != 1) { msg_info("SSL_set_fd error to %s", props->namaddr); tls_print_errors(); uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* * Turn on non-blocking I/O so that we can enforce timeouts on network * I/O. */ non_blocking(vstream_fileno(props->stream), NON_BLOCKING); /* * If the debug level selected is high enough, all of the data is dumped: * TLS_LOG_TLSPKTS will dump the SSL negotiation, TLS_LOG_ALLPKTS will * dump everything. * * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? * Well there is a BIO below the SSL routines that is automatically * created for us, so we can use it for debugging purposes. */ if (log_mask & TLS_LOG_TLSPKTS) BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb); tls_dane_set_callback(app_ctx->ssl_ctx, TLScontext); /* * Start TLS negotiations. This process is a black box that invokes our * call-backs for certificate verification. * * Error handling: If the SSL handhake fails, we print out an error message * and remove all TLS state concerning this session. */ sts = tls_bio_connect(vstream_fileno(props->stream), props->timeout, TLScontext); if (sts <= 0) { if (ERR_peek_error() != 0) { msg_info("SSL_connect error to %s: %d", props->namaddr, sts); tls_print_errors(); } else if (errno != 0) { msg_info("SSL_connect error to %s: %m", props->namaddr); } else { msg_info("SSL_connect error to %s: lost connection", props->namaddr); } uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* Turn off packet dump if only dumping the handshake */ if ((log_mask & TLS_LOG_ALLPKTS) == 0) BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); /* * The caller may want to know if this session was reused or if a new * session was negotiated. */ TLScontext->session_reused = SSL_session_reused(TLScontext->con); if ((log_mask & TLS_LOG_CACHE) && TLScontext->session_reused) msg_info("%s: Reusing old session", TLScontext->namaddr); /* * Do peername verification if requested and extract useful information * from the certificate for later use. */ if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) { TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT; /* * Peer name or fingerprint verification as requested. * Unconditionally set peer_CN, issuer_CN and peer_cert_fprint. Check * fingerprint first, and avoid logging verified as untrusted in the * call to verify_extract_name(). */ verify_extract_print(TLScontext, peercert, props); verify_extract_name(TLScontext, peercert, props); if (TLScontext->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE | TLS_LOG_PEERCERT)) msg_info("%s: subject_CN=%s, issuer_CN=%s, " "fingerprint=%s, pkey_fingerprint=%s", props->namaddr, TLScontext->peer_CN, TLScontext->issuer_CN, TLScontext->peer_cert_fprint, TLScontext->peer_pkey_fprint); X509_free(peercert); } else { TLScontext->issuer_CN = mystrdup(""); TLScontext->peer_CN = mystrdup(""); TLScontext->peer_cert_fprint = mystrdup(""); TLScontext->peer_pkey_fprint = mystrdup(""); } /* * Finally, collect information about protocol and cipher for logging */ TLScontext->protocol = SSL_get_version(TLScontext->con); cipher = SSL_get_current_cipher(TLScontext->con); TLScontext->cipher_name = SSL_CIPHER_get_name(cipher); TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher, &(TLScontext->cipher_algbits)); /* * The TLS engine is active. Switch to the tls_timed_read/write() * functions and make the TLScontext available to those functions. */ tls_stream_start(props->stream, TLScontext); /* * All the key facts in a single log entry. */ if (log_mask & TLS_LOG_SUMMARY) msg_info("%s TLS connection established to %s: %s with cipher %s " "(%d/%d bits)", !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" : TLS_CERT_IS_MATCHED(TLScontext) ? "Verified" : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", props->namaddr, TLScontext->protocol, TLScontext->cipher_name, TLScontext->cipher_usebits, TLScontext->cipher_algbits); tls_int_seed(); return (TLScontext); }
/* * starts SSL/TLS encryption for the current session. */ int starttls(int sock) { int retval, bits, alg_bits;/*r; */ SSL *newssl; pthread_setspecific(ThreadSSL, NULL); if (!ssl_ctx) { return(1); } if (!(newssl = SSL_new(ssl_ctx))) { syslog(LOG_WARNING, "SSL_new failed: %s\n", ERR_reason_error_string(ERR_get_error())); return(2); } if (!(SSL_set_fd(newssl, sock))) { syslog(LOG_WARNING, "SSL_set_fd failed: %s\n", ERR_reason_error_string(ERR_get_error())); SSL_free(newssl); return(3); } retval = SSL_accept(newssl); if (retval < 1) { /* * Can't notify the client of an error here; they will * discover the problem at the SSL layer and should * revert to unencrypted communications. */ long errval; const char *ssl_error_reason = NULL; errval = SSL_get_error(newssl, retval); ssl_error_reason = ERR_reason_error_string(ERR_get_error()); if (ssl_error_reason == NULL) { syslog(LOG_WARNING, "SSL_accept failed: errval=%ld, retval=%d %s\n", errval, retval, strerror(errval)); } else { syslog(LOG_WARNING, "SSL_accept failed: %s\n", ssl_error_reason); } sleeeeeeeeeep(1); retval = SSL_accept(newssl); } if (retval < 1) { long errval; const char *ssl_error_reason = NULL; errval = SSL_get_error(newssl, retval); ssl_error_reason = ERR_reason_error_string(ERR_get_error()); if (ssl_error_reason == NULL) { syslog(LOG_WARNING, "SSL_accept failed: errval=%ld, retval=%d (%s)\n", errval, retval, strerror(errval)); } else { syslog(LOG_WARNING, "SSL_accept failed: %s\n", ssl_error_reason); } SSL_free(newssl); newssl = NULL; return(4); } else { syslog(LOG_INFO, "SSL_accept success\n"); } /*r = */BIO_set_close(newssl->rbio, BIO_NOCLOSE); bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(newssl), &alg_bits); syslog(LOG_INFO, "SSL/TLS using %s on %s (%d of %d bits)\n", SSL_CIPHER_get_name(SSL_get_current_cipher(newssl)), SSL_CIPHER_get_version(SSL_get_current_cipher(newssl)), bits, alg_bits); pthread_setspecific(ThreadSSL, newssl); syslog(LOG_INFO, "SSL started\n"); return(0); }
/* Switch on a filedescriptor */ int ggz_tls_enable_fd(int fd, GGZTLSType mode, GGZTLSVerificationType verify) { int ret, ret2; STACK_OF(SSL_CIPHER) *stack; SSL_CIPHER *cipher; int bits; char *cipherlist; SSL *_tls; int _tls_active; struct list_entry *entry; _state = 1; _tls_active = 0; if((mode != GGZ_TLS_CLIENT) && (mode != GGZ_TLS_SERVER)) { TLSERROR("Wrong mode."); return 0; } if(!_tlsctx) tls_init(verify); _tls = SSL_new(_tlsctx); if(_tls) { cipherlist = NULL; stack = SSL_get_ciphers(_tls); while((cipher = (SSL_CIPHER*)sk_pop(stack)) != NULL) { printf("* Cipher: %s\n", SSL_CIPHER_get_name(cipher)); printf(" Bits: %i\n", SSL_CIPHER_get_bits(cipher, &bits)); printf(" Used bits: %i\n", bits); printf(" Version: %s\n", SSL_CIPHER_get_version(cipher)); printf(" Description: %s\n", SSL_CIPHER_description(cipher, NULL, 0)); if(cipherlist) { cipherlist = (char*)realloc(cipherlist, (strlen(cipherlist) + 1) + strlen(SSL_CIPHER_get_name(cipher)) + 1); strcat(cipherlist, ":"); strcat(cipherlist, SSL_CIPHER_get_name(cipher)); } else { cipherlist = (char*)malloc(strlen(SSL_CIPHER_get_name(cipher)) + 1); strcpy(cipherlist, SSL_CIPHER_get_name(cipher)); } } printf("Available ciphers: %s\n", cipherlist); ret = SSL_set_cipher_list(_tls, cipherlist); if(!ret) TLSERROR("Cipher selection failed."); ret = SSL_set_fd(_tls, fd); if(!ret) TLSERROR("Assignment to connection failed."); else { SSL_set_read_ahead(_tls, 1); if(mode == GGZ_TLS_SERVER) { tls_certkey(_tls); if(_state) { SSL_set_accept_state(_tls); ret = SSL_accept(_tls); } } else { SSL_set_connect_state(_tls); ret = SSL_connect(_tls); } if((ret != 1) || (!_state)) { printf("Ret: %i, State: %i\n", ret, _state); TLSERROR("Handshake failed."); ret2 = ERR_get_error(); printf("EXT: %s\n%s\n%s\n%s\n%s\n", tls_exterror(_tls, ret), ERR_error_string(ret2, NULL), ERR_lib_error_string(ret2), ERR_func_error_string(ret2), ERR_reason_error_string(ret2)); } else { printf(">>>>> Handshake successful.\n"); if((mode == GGZ_TLS_SERVER) || (verify == GGZ_TLS_VERIFY_NONE)) _tls_active = 1; else { printf(">>>>> Client side, thus checking Certificate.\n"); printf("Negotiated cipher: %s\n", SSL_get_cipher(_tls)); printf("Shared ciphers: %s\n", SSL_get_shared_ciphers(_tls, NULL, 0)); if(SSL_get_peer_certificate(_tls)) { if(SSL_get_verify_result(_tls) == X509_V_OK) { _tls_active = 1; } else { printf("Error code: %li\n", SSL_get_verify_result(_tls)); TLSERROR("Invalid certificate, or certificate is not self-signed."); } } else TLSERROR("Couldn't get certificate."); } } entry = (struct list_entry*)ggz_malloc(sizeof(struct list_entry)); entry->tls = _tls; entry->fd = fd; entry->active = _tls_active; ggz_list_insert(openssllist, entry); return 1; } } return 0; }
static void setup_ssl(tcptest_t *item) { static int ssl_init_complete = 0; struct servent *sp; char portinfo[100]; X509 *peercert; char *certcn, *certstart, *certend; int err; strbuffer_t *sslinfo; char msglin[2048]; item->sslrunning = 1; if (!ssl_init_complete) { /* Setup entropy */ if (RAND_status() != 1) { char path[PATH_MAX]; /* Path for the random file */ /* load entropy from files */ RAND_load_file(RAND_file_name(path, sizeof (path)), -1); /* load entropy from egd sockets */ RAND_egd("/var/run/egd-pool"); RAND_egd("/dev/egd-pool"); RAND_egd("/etc/egd-pool"); RAND_egd("/var/spool/prngd/pool"); /* shuffle $RANDFILE (or ~/.rnd if unset) */ RAND_write_file(RAND_file_name(path, sizeof (path))); if (RAND_status() != 1) { errprintf("Failed to find enough entropy on your system"); item->errcode = CONTEST_ESSL; return; } } SSL_load_error_strings(); SSL_library_init(); ssl_init_complete = 1; } if (item->sslctx == NULL) { switch (item->ssloptions->sslversion) { case SSLVERSION_V2: item->sslctx = SSL_CTX_new(SSLv2_client_method()); break; case SSLVERSION_V3: item->sslctx = SSL_CTX_new(SSLv3_client_method()); break; case SSLVERSION_TLS1: item->sslctx = SSL_CTX_new(TLSv1_client_method()); break; default: item->sslctx = SSL_CTX_new(SSLv23_client_method()); break; } if (!item->sslctx) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Cannot create SSL context - IP %s, service %s: %s\n", inet_ntoa(item->addr.sin_addr), item->svcinfo->svcname, sslerrmsg); item->sslrunning = 0; item->errcode = CONTEST_ESSL; return; } /* Workaround SSL bugs */ SSL_CTX_set_options(item->sslctx, SSL_OP_ALL); SSL_CTX_set_quiet_shutdown(item->sslctx, 1); /* Limit set of ciphers, if user wants to */ if (item->ssloptions->cipherlist) SSL_CTX_set_cipher_list(item->sslctx, item->ssloptions->cipherlist); if (item->ssloptions->clientcert) { int status; char certfn[PATH_MAX]; SSL_CTX_set_default_passwd_cb(item->sslctx, cert_password_cb); SSL_CTX_set_default_passwd_cb_userdata(item->sslctx, item); sprintf(certfn, "%s/certs/%s", xgetenv("XYMONHOME"), item->ssloptions->clientcert); status = SSL_CTX_use_certificate_chain_file(item->sslctx, certfn); if (status == 1) { status = SSL_CTX_use_PrivateKey_file(item->sslctx, certfn, SSL_FILETYPE_PEM); } if (status != 1) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Cannot load SSL client certificate/key %s: %s\n", item->ssloptions->clientcert, sslerrmsg); item->sslrunning = 0; item->errcode = CONTEST_ESSL; return; } } } if (item->ssldata == NULL) { item->ssldata = SSL_new(item->sslctx); if (!item->ssldata) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("SSL_new failed - IP %s, service %s: %s\n", inet_ntoa(item->addr.sin_addr), item->svcinfo->svcname, sslerrmsg); item->sslrunning = 0; SSL_CTX_free(item->sslctx); item->errcode = CONTEST_ESSL; return; } /* Verify that the client certificate is working */ if (item->ssloptions->clientcert) { X509 *x509; x509 = SSL_get_certificate(item->ssldata); if(x509 != NULL) { EVP_PKEY *pktmp = X509_get_pubkey(x509); EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(item->ssldata)); EVP_PKEY_free(pktmp); } if (!SSL_CTX_check_private_key(item->sslctx)) { errprintf("Private/public key mismatch for certificate %s\n", item->ssloptions->clientcert); item->sslrunning = 0; item->errcode = CONTEST_ESSL; return; } } /* SSL setup is done. Now attach the socket FD to the SSL protocol handler */ if (SSL_set_fd(item->ssldata, item->fd) != 1) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Could not initiate SSL on connection - IP %s, service %s: %s\n", inet_ntoa(item->addr.sin_addr), item->svcinfo->svcname, sslerrmsg); item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); item->errcode = CONTEST_ESSL; return; } } sp = getservbyport(item->addr.sin_port, "tcp"); if (sp) { sprintf(portinfo, "%s (%d/tcp)", sp->s_name, item->addr.sin_port); } else { sprintf(portinfo, "%d/tcp", item->addr.sin_port); } if ((err = SSL_connect(item->ssldata)) != 1) { char sslerrmsg[256]; switch (SSL_get_error (item->ssldata, err)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: item->sslrunning = SSLSETUP_PENDING; break; case SSL_ERROR_SYSCALL: ERR_error_string(ERR_get_error(), sslerrmsg); /* Filter out the bogus SSL error */ if (strstr(sslerrmsg, "error:00000000:") == NULL) { errprintf("IO error in SSL_connect to %s on host %s: %s\n", portinfo, inet_ntoa(item->addr.sin_addr), sslerrmsg); } item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); break; case SSL_ERROR_SSL: ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Unspecified SSL error in SSL_connect to %s on host %s: %s\n", portinfo, inet_ntoa(item->addr.sin_addr), sslerrmsg); item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); break; default: ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Unknown error %d in SSL_connect to %s on host %s: %s\n", err, portinfo, inet_ntoa(item->addr.sin_addr), sslerrmsg); item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); break; } return; } /* If we get this far, the SSL handshake has completed. So grab the certificate */ peercert = SSL_get_peer_certificate(item->ssldata); if (!peercert) { errprintf("Cannot get peer certificate for %s on host %s\n", portinfo, inet_ntoa(item->addr.sin_addr)); item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); return; } sslinfo = newstrbuffer(0); certcn = X509_NAME_oneline(X509_get_subject_name(peercert), NULL, 0); certstart = strdup(xymon_ASN1_UTCTIME(X509_get_notBefore(peercert))); certend = strdup(xymon_ASN1_UTCTIME(X509_get_notAfter(peercert))); snprintf(msglin, sizeof(msglin), "Server certificate:\n\tsubject:%s\n\tstart date: %s\n\texpire date:%s\n", certcn, certstart, certend); addtobuffer(sslinfo, msglin); item->certsubject = strdup(certcn); item->certexpires = sslcert_expiretime(certend); xfree(certcn); xfree(certstart); xfree(certend); X509_free(peercert); /* We list the available ciphers in the SSL cert data */ { int i; STACK_OF(SSL_CIPHER) *sk; addtobuffer(sslinfo, "\nAvailable ciphers:\n"); sk = SSL_get_ciphers(item->ssldata); for (i=0; i<sk_SSL_CIPHER_num(sk); i++) { int b1, b2; char *cph; b1 = SSL_CIPHER_get_bits(sk_SSL_CIPHER_value(sk,i), &b2); cph = SSL_CIPHER_get_name(sk_SSL_CIPHER_value(sk,i)); snprintf(msglin, sizeof(msglin), "Cipher %d: %s (%d bits)\n", i, cph, b1); addtobuffer(sslinfo, msglin); if ((item->mincipherbits == 0) || (b1 < item->mincipherbits)) item->mincipherbits = b1; } } item->certinfo = grabstrbuffer(sslinfo); }
/* mutt_ssl_starttls: Negotiate TLS over an already opened connection. * TODO: Merge this code better with ssl_socket_open. */ int mutt_ssl_starttls (CONNECTION* conn) { sslsockdata* ssldata; int maxbits; long ssl_options = 0; if (ssl_init()) goto bail; ssldata = (sslsockdata*) safe_calloc (1, sizeof (sslsockdata)); /* the ssl_use_xxx protocol options don't apply. We must use TLS in TLS. * * However, we need to be able to negotiate amongst various TLS versions, * which at present can only be done with the SSLv23_client_method; * TLSv1_client_method gives us explicitly TLSv1.0, not 1.1 or 1.2 (True as * of OpenSSL 1.0.1c) */ if (! (ssldata->ctx = SSL_CTX_new (SSLv23_client_method()))) { dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL_CTX\n")); goto bail_ssldata; } #ifdef SSL_OP_NO_TLSv1_2 if (!option(OPTTLSV1_2)) ssl_options |= SSL_OP_NO_TLSv1_2; #endif #ifdef SSL_OP_NO_TLSv1_1 if (!option(OPTTLSV1_1)) ssl_options |= SSL_OP_NO_TLSv1_1; #endif #ifdef SSL_OP_NO_TLSv1 if (!option(OPTTLSV1)) ssl_options |= SSL_OP_NO_TLSv1; #endif /* these are always set */ #ifdef SSL_OP_NO_SSLv3 ssl_options |= SSL_OP_NO_SSLv3; #endif #ifdef SSL_OP_NO_SSLv2 ssl_options |= SSL_OP_NO_SSLv2; #endif if (! SSL_CTX_set_options(ssldata->ctx, ssl_options)) { dprint(1, (debugfile, "mutt_ssl_starttls: Error setting options to %ld\n", ssl_options)); goto bail_ctx; } ssl_get_client_cert(ssldata, conn); if (! (ssldata->ssl = SSL_new (ssldata->ctx))) { dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL\n")); goto bail_ctx; } if (SSL_set_fd (ssldata->ssl, conn->fd) != 1) { dprint (1, (debugfile, "mutt_ssl_starttls: Error setting fd\n")); goto bail_ssl; } if (ssl_negotiate (conn, ssldata)) goto bail_ssl; ssldata->isopen = 1; /* hmm. watch out if we're starting TLS over any method other than raw. */ conn->sockdata = ssldata; conn->conn_read = ssl_socket_read; conn->conn_write = ssl_socket_write; conn->conn_close = tls_close; conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (ssldata->ssl), &maxbits); return 0; bail_ssl: FREE (&ssldata->ssl); bail_ctx: FREE (&ssldata->ctx); bail_ssldata: FREE (&ssldata); bail: return -1; }
/* * This is the actual startup routine for the connection. We expect that the * buffers are flushed and the "220 Ready to start TLS" was received by us, * so that we can immediately start the TLS handshake process. */ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) { const char *myname = "tls_client_start"; int sts; int protomask; const char *cipher_list; SSL_SESSION *session; SSL_CIPHER *cipher; X509 *peercert; TLS_SESS_STATE *TLScontext; TLS_APPL_STATE *app_ctx = props->ctx; ACL_VSTRING *myserverid; if (props->log_level >= 1) acl_msg_info("%s(%d): setting up TLS connection to %s", myname, __LINE__, props->namaddr); /* * First make sure we have valid protocol and cipher parameters * * The cipherlist will be applied to the global SSL context, where it can be * repeatedly reset if necessary, but the protocol restrictions will be * is applied to the SSL connection, because protocol restrictions in the * global context cannot be cleared. */ /* * OpenSSL will ignore cached sessions that use the wrong protocol. So we * do not need to filter out cached sessions with the "wrong" protocol, * rather OpenSSL will simply negotiate a new session. * * Still, we salt the session lookup key with the protocol list, so that * sessions found in the cache are always acceptable. */ protomask = tls_protocol_mask(props->protocols); if (protomask == TLS_PROTOCOL_INVALID) { /* tls_protocol_mask() logs no warning. */ acl_msg_warn("%s(%d): nameaddr: %s: Invalid TLS protocol list \"%s\": aborting TLS session", myname, __LINE__, props->namaddr, props->protocols); return (0); } myserverid = acl_vstring_alloc(100); acl_vstring_sprintf_append(myserverid, "%s&p=%d", props->serverid, protomask); /* * Per session cipher selection for sessions with mandatory encryption * * By the time a TLS client is negotiating ciphers it has already offered to * re-use a session, it is too late to renege on the offer. So we must * not attempt to re-use sessions whose ciphers are too weak. We salt the * session lookup key with the cipher list, so that sessions found in the * cache are always acceptable. */ cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, props->cipher_exclusions); if (cipher_list == 0) { acl_msg_warn("%s(%d): %s: %s: aborting TLS session", myname, __LINE__, props->namaddr, acl_vstring_str(app_ctx->why)); acl_vstring_free(myserverid); return (0); } if (props->log_level >= 2) acl_msg_info("%s(%d): %s: TLS cipher list \"%s\"", myname, __LINE__, props->namaddr, cipher_list); acl_vstring_sprintf_append(myserverid, "&c=%s", cipher_list); /* * Allocate a new TLScontext for the new connection and get an SSL * structure. Add the location of TLScontext to the SSL to later retrieve * the information inside the tls_verify_certificate_callback(). * * If session caching was enabled when TLS was initialized, the cache type * is stored in the client SSL context. */ TLScontext = tls_alloc_sess_context(props->log_level, props->namaddr); TLScontext->cache_type = app_ctx->cache_type; TLScontext->serverid = acl_vstring_export(myserverid); if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) { acl_msg_warn("%s(%d): Could not allocate 'TLScontext->con' with SSL_new()", myname, __LINE__); tls_print_errors(); tls_free_context(TLScontext); return (0); } if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { acl_msg_warn("%s(%d): Could not set application data for 'TLScontext->con'", myname, __LINE__); tls_print_errors(); tls_free_context(TLScontext); return (0); } /* * Apply session protocol restrictions. */ if (protomask != 0) SSL_set_options(TLScontext->con, ((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L) | ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L) | ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L)); /* * The TLS connection is realized by a BIO_pair, so obtain the pair. * * XXX There is no need to make internal_bio a member of the TLScontext * structure. It will be attached to TLScontext->con, and destroyed along * with it. The network_bio, however, needs to be freed explicitly. */ if (!BIO_new_bio_pair(&TLScontext->internal_bio, TLS_BIO_BUFSIZE, &TLScontext->network_bio, TLS_BIO_BUFSIZE)) { acl_msg_warn("%s(%d): Could not obtain BIO_pair", myname, __LINE__); tls_print_errors(); tls_free_context(TLScontext); return (0); } /* * XXX To avoid memory leaks we must always call SSL_SESSION_free() after * calling SSL_set_session(), regardless of whether or not the session * will be reused. */ if (TLScontext->cache_type) { session = load_clnt_session(TLScontext); if (session) { SSL_set_session(TLScontext->con, session); SSL_SESSION_free(session); /* 200411 */ #if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L) /* * Ugly Hack: OpenSSL before 0.9.6a does not store the verify * result in sessions for the client side. We modify the session * directly which is version specific, but this bug is version * specific, too. * * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before beta1 * have this bug, it has been fixed during development of 0.9.6a. * The development version of 0.9.7 can have this bug, too. It * has been fixed on 2000/11/29. */ SSL_set_verify_result(TLScontext->con, session->verify_result); #endif } } /* * Before really starting anything, try to seed the PRNG a little bit * more. */ tls_int_seed(); if (var_tls_daemon_rand_bytes > 0) (void) tls_ext_seed(var_tls_daemon_rand_bytes); /* * Initialize the SSL connection to connect state. This should not be * necessary anymore since 0.9.3, but the call is still in the library * and maintaining compatibility never hurts. */ SSL_set_connect_state(TLScontext->con); /* * Connect the SSL connection with the Postfix side of the BIO-pair for * reading and writing. */ SSL_set_bio(TLScontext->con, TLScontext->internal_bio, TLScontext->internal_bio); /* * If the debug level selected is high enough, all of the data is dumped: * 3 will dump the SSL negotiation, 4 will dump everything. * * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? * Well there is a BIO below the SSL routines that is automatically * created for us, so we can use it for debugging purposes. */ if (props->log_level >= 3) BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb); /* * Start TLS negotiations. This process is a black box that invokes our * call-backs for certificate verification. * * Error handling: If the SSL handhake fails, we print out an error message * and remove all TLS state concerning this session. */ sts = tls_bio_connect(ACL_VSTREAM_SOCK(props->stream), props->timeout, TLScontext); if (sts <= 0) { acl_msg_info("%s(%d): SSL_connect error to %s: %d", myname, __LINE__, props->namaddr, sts); tls_print_errors(); uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* Only log_level==4 dumps everything */ if (props->log_level < 4) BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); /* * The caller may want to know if this session was reused or if a new * session was negotiated. */ TLScontext->session_reused = SSL_session_reused(TLScontext->con); if (props->log_level >= 2 && TLScontext->session_reused) acl_msg_info("%s(%d): %s: Reusing old session", myname, __LINE__, TLScontext->namaddr); /* * Do peername verification if requested and extract useful information * from the certificate for later use. */ if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) { TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT; /* * Peer name or fingerprint verification as requested. * Unconditionally set peer_CN, issuer_CN and peer_fingerprint. */ verify_extract_name(TLScontext, peercert, props); verify_extract_print(TLScontext, peercert, props); X509_free(peercert); } else { TLScontext->issuer_CN = acl_mystrdup(""); TLScontext->peer_CN = acl_mystrdup(""); TLScontext->peer_fingerprint = acl_mystrdup(""); } /* * Finally, collect information about protocol and cipher for logging */ TLScontext->protocol = SSL_get_version(TLScontext->con); cipher = SSL_get_current_cipher(TLScontext->con); TLScontext->cipher_name = SSL_CIPHER_get_name(cipher); TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher, &(TLScontext->cipher_algbits)); /* * The TLS engine is active. Switch to the tls_timed_read/write() * functions and make the TLScontext available to those functions. */ tls_stream_start(props->stream, TLScontext); /* * All the key facts in a single log entry. */ if (props->log_level >= 1) acl_msg_info("%s(%d): %s TLS connection established to %s: %s with cipher %s " "(%d/%d bits)", myname, __LINE__, TLS_CERT_IS_MATCHED(TLScontext) ? "Verified" : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", props->namaddr, TLScontext->protocol, TLScontext->cipher_name, TLScontext->cipher_usebits, TLScontext->cipher_algbits); tls_int_seed(); return (TLScontext); }
/* * This is the actual startup routine for the connection. We expect that the * buffers are flushed and the "220 Ready to start TLS" was received by us, * so that we can immediately start the TLS handshake process. */ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) { int sts; int protomask; const char *cipher_list; SSL_SESSION *session; const SSL_CIPHER *cipher; X509 *peercert; TLS_SESS_STATE *TLScontext; TLS_APPL_STATE *app_ctx = props->ctx; VSTRING *myserverid; int log_mask = app_ctx->log_mask; /* * When certificate verification is required, log trust chain validation * errors even when disabled by default for opportunistic sessions. */ if (props->tls_level >= TLS_LEV_VERIFY) log_mask |= TLS_LOG_UNTRUSTED; if (log_mask & TLS_LOG_VERBOSE) msg_info("setting up TLS connection to %s", props->namaddr); /* * First make sure we have valid protocol and cipher parameters * * The cipherlist will be applied to the global SSL context, where it can be * repeatedly reset if necessary, but the protocol restrictions will be * is applied to the SSL connection, because protocol restrictions in the * global context cannot be cleared. */ /* * OpenSSL will ignore cached sessions that use the wrong protocol. So we * do not need to filter out cached sessions with the "wrong" protocol, * rather OpenSSL will simply negotiate a new session. * * Still, we salt the session lookup key with the protocol list, so that * sessions found in the cache are always acceptable. */ protomask = tls_protocol_mask(props->protocols); if (protomask == TLS_PROTOCOL_INVALID) { /* tls_protocol_mask() logs no warning. */ msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session", props->namaddr, props->protocols); return (0); } myserverid = vstring_alloc(100); vstring_sprintf_append(myserverid, "%s&p=%d", props->serverid, protomask); /* * Per session cipher selection for sessions with mandatory encryption * * By the time a TLS client is negotiating ciphers it has already offered to * re-use a session, it is too late to renege on the offer. So we must * not attempt to re-use sessions whose ciphers are too weak. We salt the * session lookup key with the cipher list, so that sessions found in the * cache are always acceptable. */ cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, props->cipher_exclusions); if (cipher_list == 0) { msg_warn("%s: %s: aborting TLS session", props->namaddr, vstring_str(app_ctx->why)); vstring_free(myserverid); return (0); } if (log_mask & TLS_LOG_VERBOSE) msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list); vstring_sprintf_append(myserverid, "&c=%s", cipher_list); /* * Finally, salt the session key with the OpenSSL library version, * (run-time, rather than compile-time, just in case that matters). */ vstring_sprintf_append(myserverid, "&l=%ld", (long) SSLeay()); /* * Allocate a new TLScontext for the new connection and get an SSL * structure. Add the location of TLScontext to the SSL to later retrieve * the information inside the tls_verify_certificate_callback(). * * If session caching was enabled when TLS was initialized, the cache type * is stored in the client SSL context. */ TLScontext = tls_alloc_sess_context(log_mask, props->namaddr); TLScontext->cache_type = app_ctx->cache_type; TLScontext->serverid = vstring_export(myserverid); TLScontext->stream = props->stream; if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) { msg_warn("Could not allocate 'TLScontext->con' with SSL_new()"); tls_print_errors(); tls_free_context(TLScontext); return (0); } if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { msg_warn("Could not set application data for 'TLScontext->con'"); tls_print_errors(); tls_free_context(TLScontext); return (0); } /* * Apply session protocol restrictions. */ if (protomask != 0) SSL_set_options(TLScontext->con, ((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L) | ((protomask & TLS_PROTOCOL_TLSv1_1) ? SSL_OP_NO_TLSv1_1 : 0L) | ((protomask & TLS_PROTOCOL_TLSv1_2) ? SSL_OP_NO_TLSv1_2 : 0L) | ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L) | ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L)); /* * XXX To avoid memory leaks we must always call SSL_SESSION_free() after * calling SSL_set_session(), regardless of whether or not the session * will be reused. */ if (TLScontext->cache_type) { session = load_clnt_session(TLScontext); if (session) { SSL_set_session(TLScontext->con, session); SSL_SESSION_free(session); /* 200411 */ #if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L) /* * Ugly Hack: OpenSSL before 0.9.6a does not store the verify * result in sessions for the client side. We modify the session * directly which is version specific, but this bug is version * specific, too. * * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before beta1 * have this bug, it has been fixed during development of 0.9.6a. * The development version of 0.9.7 can have this bug, too. It * has been fixed on 2000/11/29. */ SSL_set_verify_result(TLScontext->con, session->verify_result); #endif } } /* * Before really starting anything, try to seed the PRNG a little bit * more. */ tls_int_seed(); (void) tls_ext_seed(var_tls_daemon_rand_bytes); /* * Initialize the SSL connection to connect state. This should not be * necessary anymore since 0.9.3, but the call is still in the library * and maintaining compatibility never hurts. */ SSL_set_connect_state(TLScontext->con); /* * Connect the SSL connection with the network socket. */ if (SSL_set_fd(TLScontext->con, vstream_fileno(props->stream)) != 1) { msg_info("SSL_set_fd error to %s", props->namaddr); tls_print_errors(); uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* * Turn on non-blocking I/O so that we can enforce timeouts on network * I/O. */ non_blocking(vstream_fileno(props->stream), NON_BLOCKING); /* * If the debug level selected is high enough, all of the data is dumped: * TLS_LOG_TLSPKTS will dump the SSL negotiation, TLS_LOG_ALLPKTS will * dump everything. * * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? * Well there is a BIO below the SSL routines that is automatically * created for us, so we can use it for debugging purposes. */ if (log_mask & TLS_LOG_TLSPKTS) BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb); /* * Start TLS negotiations. This process is a black box that invokes our * call-backs for certificate verification. * * Error handling: If the SSL handhake fails, we print out an error message * and remove all TLS state concerning this session. */ sts = tls_bio_connect(vstream_fileno(props->stream), props->timeout, TLScontext); if (sts <= 0) { if (ERR_peek_error() != 0) { msg_info("SSL_connect error to %s: %d", props->namaddr, sts); tls_print_errors(); } else if (errno != 0) { msg_info("SSL_connect error to %s: %m", props->namaddr); } else { msg_info("SSL_connect error to %s: lost connection", props->namaddr); } uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* Turn off packet dump if only dumping the handshake */ if ((log_mask & TLS_LOG_ALLPKTS) == 0) BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); /* * The caller may want to know if this session was reused or if a new * session was negotiated. */ TLScontext->session_reused = SSL_session_reused(TLScontext->con); if ((log_mask & TLS_LOG_CACHE) && TLScontext->session_reused) msg_info("%s: Reusing old session", TLScontext->namaddr); /* * Do peername verification if requested and extract useful information * from the certificate for later use. */ if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) { TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT; /* * Peer name or fingerprint verification as requested. * Unconditionally set peer_CN, issuer_CN and peer_fingerprint. */ verify_extract_name(TLScontext, peercert, props); verify_extract_print(TLScontext, peercert, props); if (TLScontext->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE | TLS_LOG_PEERCERT)) msg_info("%s: subject_CN=%s, issuer_CN=%s, " "fingerprint %s, pkey_fingerprint=%s", props->namaddr, TLScontext->peer_CN, TLScontext->issuer_CN, TLScontext->peer_fingerprint, TLScontext->peer_pkey_fprint); X509_free(peercert); } else { TLScontext->issuer_CN = mystrdup(""); TLScontext->peer_CN = mystrdup(""); TLScontext->peer_fingerprint = mystrdup(""); TLScontext->peer_pkey_fprint = mystrdup(""); } /* * Finally, collect information about protocol and cipher for logging */ TLScontext->protocol = SSL_get_version(TLScontext->con); cipher = SSL_get_current_cipher(TLScontext->con); TLScontext->cipher_name = SSL_CIPHER_get_name(cipher); TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher, &(TLScontext->cipher_algbits)); /* * The TLS engine is active. Switch to the tls_timed_read/write() * functions and make the TLScontext available to those functions. */ tls_stream_start(props->stream, TLScontext); /* * All the key facts in a single log entry. */ if (log_mask & TLS_LOG_SUMMARY) msg_info("%s TLS connection established to %s: %s with cipher %s " "(%d/%d bits)", TLS_CERT_IS_MATCHED(TLScontext) ? "Verified" : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", props->namaddr, TLScontext->protocol, TLScontext->cipher_name, TLScontext->cipher_usebits, TLScontext->cipher_algbits); tls_int_seed(); return (TLScontext); }
/** * ssl_setup - Set up SSL on the Connection * @param conn Connection * @retval 0 Success * @retval -1 Failure */ static int ssl_setup(struct Connection *conn) { struct SslSockData *ssldata = NULL; int maxbits; ssldata = mutt_mem_calloc(1, sizeof(struct SslSockData)); conn->sockdata = ssldata; ssldata->sctx = SSL_CTX_new(SSLv23_client_method()); if (!ssldata->sctx) { /* L10N: an SSL context is a data structure returned by the OpenSSL function SSL_CTX_new(). In this case it returned NULL: an error condition. */ mutt_error(_("Unable to create SSL context")); ssl_dprint_err_stack(); goto free_sasldata; } /* disable SSL protocols as needed */ #ifdef SSL_OP_NO_TLSv1_2 if (!C_SslUseTlsv12) SSL_CTX_set_options(ssldata->sctx, SSL_OP_NO_TLSv1_2); #endif #ifdef SSL_OP_NO_TLSv1_1 if (!C_SslUseTlsv11) SSL_CTX_set_options(ssldata->sctx, SSL_OP_NO_TLSv1_1); #endif #ifdef SSL_OP_NO_TLSv1 if (!C_SslUseTlsv1) SSL_CTX_set_options(ssldata->sctx, SSL_OP_NO_TLSv1); #endif if (!C_SslUseSslv3) SSL_CTX_set_options(ssldata->sctx, SSL_OP_NO_SSLv3); if (!C_SslUseSslv2) SSL_CTX_set_options(ssldata->sctx, SSL_OP_NO_SSLv2); if (C_SslUsesystemcerts) { if (!SSL_CTX_set_default_verify_paths(ssldata->sctx)) { mutt_debug(LL_DEBUG1, "Error setting default verify paths\n"); goto free_ctx; } } if (C_CertificateFile && !ssl_load_certificates(ssldata->sctx)) mutt_debug(LL_DEBUG1, "Error loading trusted certificates\n"); ssl_get_client_cert(ssldata, conn); if (C_SslCiphers) { SSL_CTX_set_cipher_list(ssldata->sctx, C_SslCiphers); } if (ssl_set_verify_partial(ssldata->sctx)) { mutt_error(_("Warning: error enabling ssl_verify_partial_chains")); } ssldata->ssl = SSL_new(ssldata->sctx); SSL_set_fd(ssldata->ssl, conn->fd); if (ssl_negotiate(conn, ssldata)) goto free_ssl; ssldata->isopen = 1; conn->ssf = SSL_CIPHER_get_bits(SSL_get_current_cipher(ssldata->ssl), &maxbits); return 0; free_ssl: SSL_free(ssldata->ssl); ssldata->ssl = 0; free_ctx: SSL_CTX_free(ssldata->sctx); ssldata->sctx = 0; free_sasldata: FREE(&ssldata); return -1; }
spocp_result_t tls_start(conn_t * conn, ruleset_t * rs) { SSL *ssl; SSL_CTX *ctx = (SSL_CTX *) conn->srv->ctx; int maxbits, r, n = 0; char *sid_ctx = "spocp"; SSL_CIPHER *cipher; if (conn->ssl != NULL) { tls_error(SPOCP_WARNING, conn, "STARTTLS received on already encrypted connection"); return SPOCP_STATE_VIOLATION; } if (!(ssl = SSL_new(ctx))) { tls_error(SPOCP_ERR, conn, "Error creating SSL context"); return SPOCP_OPERATIONSERROR; } /* * do these never fail ?? */ SSL_set_session_id_context(ssl, (unsigned char *) sid_ctx, strlen(sid_ctx)); if (SSL_set_fd(ssl, conn->fd) == 0) { traceLog(LOG_ERR,"Couldn't set filedescriptor in SSL"); return SPOCP_OPERATIONSERROR; } n = iobuf_content(conn->in); traceLog(LOG_INFO,"tls_start: %d bytes in input buffer", n); if (n) { traceLog(LOG_INFO,"tls_start: %x%x%x%x", conn->in->r[0], conn->in->r[1], conn->in->r[2], conn->in->r[3]); } LOG(SPOCP_DEBUG) traceLog(LOG_DEBUG,"Waiting for client on %d to initiate handshake", conn->fd); /* * waits for the client to initiate the handshake */ { fd_set rset ; int retval ; FD_ZERO( &rset ); FD_SET( conn->fd, &rset ); traceLog(LOG_DEBUG, "Waiting for the client" ) ; retval = select(conn->fd+1,&rset,NULL,NULL,0) ; } if ((r = SSL_accept(ssl)) <= 0) { int se ; if ((se = SSL_get_error(ssl, r)) == SSL_ERROR_WANT_READ) { traceLog(LOG_DEBUG,"Want_read"); } else if (se == SSL_ERROR_SYSCALL) { unsigned long err ; err = ERR_get_error(); if( err == 0L && r == 0 ) { traceLog(LOG_DEBUG,"EOF observed") ; } else traceLog(LOG_ERR,"I/O error occured (%ld/%d)", err, r); } else { traceLog(LOG_ERR,"SSL_get_error: %d", se); tls_error(SPOCP_ERR, conn, "SSL accept error"); SSL_free(ssl); } conn->status = CNST_ACTIVE; return SPOCP_SSL_ERR; } /* * } */ LOG(SPOCP_DEBUG) { traceLog(LOG_DEBUG,"SSL accept done"); traceLog(LOG_DEBUG,"Checking client certificate"); } if (!check_cert_chain(conn, ssl, rs)) { traceLog(LOG_ERR,"Certificate chain check failed"); SSL_free(ssl); conn->status = CNST_ACTIVE; return SPOCP_CERT_ERR; } /* * So the cert is OK and the hostname is in the DN, but do I want to * talk to this guy ?? */ cipher = SSL_get_current_cipher(ssl); conn->cipher = Strdup((char *) SSL_CIPHER_get_name(cipher)); conn->ssl_vers = Strdup(SSL_CIPHER_get_version(cipher)); if (server_access(conn) == 0) { traceLog(LOG_ERR,"Client not allowed access"); SSL_free(ssl); conn->status = CNST_ACTIVE; return SPOCP_CERT_ERR; } LOG(SPOCP_DEBUG) traceLog(LOG_DEBUG,"SSL accept done"); /* * TLS has been set up. Change input/output to read via TLS instead */ conn->readn = ssl_socket_readn; conn->writen = ssl_socket_writen; conn->close = tls_close; conn->ssl = (void *) ssl; conn->tls_ssf = SSL_CIPHER_get_bits(cipher, &maxbits); conn->status = CNST_ACTIVE; return SPOCP_SUCCESS; }