int sock_make_secure(nsocket *sock, nssl_context *ctx) { #ifdef ENABLE_SSL int ret; SSL_CTX *ssl_ctx; if (ctx) { ssl_ctx = ctx->ctx; } else { ssl_ctx = sock->default_ctx; } sock->ssl = SSL_new(ssl_ctx); if (!sock->ssl) { sock->error = ERROR_SSL_STRING; /* Usually goes wrong because: */ fprintf(stderr, "Have you called sock_init()!?\n"); return SOCK_ERROR; } SSL_set_fd(sock->ssl, sock->fd); ret = SSL_connect(sock->ssl); if (ret == -1) { sock->error = ERROR_SSL_STRING; SSL_free(sock->ssl); sock->ssl = NULL; return SOCK_ERROR; } #if 0 /* Tommi Komulainen <*****@*****.**> has donated his SSL * cert verification from the mutt IMAP/SSL code under the * LGPL... it will plug in here */ ret = sock_check_certicate(sock); if (ret) { SSL_shutdown(sock->ssl); SSL_free(sock->ssl); sock->ssl = NULL; return ret; } #endif if (notify_cb) (*notify_cb)(notify_ud, sock_secure_details, SSL_get_version(sock->ssl)); DEBUG(DEBUG_SOCKET, "SSL connected: version %s\n", SSL_get_version(sock->ssl)); return 0; #else sock->error = _("This application does not have SSL support."); return SOCK_ERROR; #endif }
Datum ssl_version(PG_FUNCTION_ARGS) { if (MyProcPort->ssl == NULL) PG_RETURN_NULL(); PG_RETURN_TEXT_P(cstring_to_text(SSL_get_version(MyProcPort->ssl))); }
static int get_version(str* res, sip_msg_t* msg) { str version; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { INFO("TLS connection not found in select_version\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; version.s = (char*)SSL_get_version(ssl); version.len = version.s ? strlen(version.s) : 0; if (version.len >= 1024) { ERR("Version string too long\n"); goto err; } memcpy(buf, version.s, version.len); res->s = buf; res->len = version.len; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return -1; }
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); }
const char* io_strio(struct io *io) { static char buf[128]; char ssl[128]; ssl[0] = '\0'; #ifdef IO_SSL if (io->ssl) { (void)snprintf(ssl, sizeof ssl, " ssl=%s:%s:%d", SSL_get_version(io->ssl), SSL_get_cipher_name(io->ssl), SSL_get_cipher_bits(io->ssl, NULL)); } #endif if (io->iobuf == NULL) (void)snprintf(buf, sizeof buf, "<io:%p fd=%d to=%d fl=%s%s>", io, io->sock, io->timeout, io_strflags(io->flags), ssl); else (void)snprintf(buf, sizeof buf, "<io:%p fd=%d to=%d fl=%s%s ib=%zu ob=%zu>", io, io->sock, io->timeout, io_strflags(io->flags), ssl, io_pending(io), io_queued(io)); return (buf); }
int tls_get_conninfo(struct tls *ctx) { const char * tmp; tls_free_conninfo(ctx->conninfo); if (ctx->ssl_peer_cert != NULL) { if (tls_get_peer_cert_hash(ctx, &ctx->conninfo->hash) == -1) goto err; if (tls_get_peer_cert_subject(ctx, &ctx->conninfo->subject) == -1) goto err; if (tls_get_peer_cert_issuer(ctx, &ctx->conninfo->issuer) == -1) goto err; if (tls_get_peer_cert_times(ctx, &ctx->conninfo->notbefore, &ctx->conninfo->notafter) == -1) goto err; } if ((tmp = SSL_get_version(ctx->ssl_conn)) == NULL) goto err; ctx->conninfo->version = strdup(tmp); if (ctx->conninfo->version == NULL) goto err; if ((tmp = SSL_get_cipher(ctx->ssl_conn)) == NULL) goto err; ctx->conninfo->cipher = strdup(tmp); if (ctx->conninfo->cipher == NULL) goto err; return (0); err: tls_free_conninfo(ctx->conninfo); return (-1); }
/** * Callback used for debugging */ static void sslLogCallback(const SSL *ssl, int where, int ret) { const char *retstr = ""; int should_log = 1; /* Ignore low-level SSL stuff */ if (where & SSL_CB_ALERT) { should_log = 1; } if (where == SSL_CB_HANDSHAKE_START || where == SSL_CB_HANDSHAKE_DONE) { should_log = 1; } if ((where & SSL_CB_EXIT) && ret == 0) { should_log = 1; } if (!should_log) { return; } retstr = SSL_alert_type_string(ret); printf("ST(0x%x). %s. R(0x%x)%s\n", where, SSL_state_string_long(ssl), ret, retstr); if (where == SSL_CB_HANDSHAKE_DONE) { printf("Using SSL version %s. Cipher=%s\n", SSL_get_version(ssl), SSL_get_cipher_name(ssl)); } }
datum_t ssl_version(PG_FUNC_ARGS) { if (proc_port->ssl == NULL) RET_NULL(); RET_TEXT_P(cstring_to_text(SSL_get_version(proc_port->ssl))); }
const char * be_tls_get_version(Port *port) { if (port->ssl) return SSL_get_version(port->ssl); else return NULL; }
void be_tls_get_version(Port *port, char *ptr, size_t len) { if (port->ssl) strlcpy(ptr, SSL_get_version(port->ssl), len); else ptr[0] = '\0'; }
std::string SSLSocket::getEncryptionInfo() const noexcept { if (!ssl) return Util::emptyString; string cipher = SSL_get_cipher_name(ssl); string protocol = SSL_get_version(ssl); return protocol + " / " + cipher; }
static void set_cipher_info(TLS_REC *tls, SSL *ssl) { g_return_if_fail(tls != NULL); g_return_if_fail(ssl != NULL); tls_rec_set_protocol_version(tls, SSL_get_version(ssl)); tls_rec_set_cipher(tls, SSL_CIPHER_get_name(SSL_get_current_cipher(ssl))); tls_rec_set_cipher_size(tls, SSL_get_cipher_bits(ssl, NULL)); }
void describeConnection(SSL* ssl) { char buff[128]; const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); CHECK(cipher != NULL); char *desc = SSL_CIPHER_description(cipher,buff,128); CHECK(desc != NULL); fprintf(stderr,"renegotiation: %s\n", SSL_get_secure_renegotiation_support(ssl)?"allowed":"disallowed"); fprintf(stderr,"%s: %s", SSL_get_version(ssl), desc); }
const char * ssl_to_text(const SSL *ssl) { static char buf[256]; (void)snprintf(buf, sizeof buf, "version=%s, cipher=%s, bits=%d", SSL_get_version(ssl), SSL_get_cipher_name(ssl), SSL_get_cipher_bits(ssl, NULL)); return (buf); }
CipherInfo TCPConnection::GetCipherInfo() { if (!is_ssl_) { throw std::logic_error("Session is not SSL/TLS. Cipher info cannot be retrieved."); } auto ssl_handle = ssl_socket_.native_handle(); AnsiString name = SSL_get_cipher_name(ssl_handle); AnsiString version = SSL_get_version(ssl_handle); int bits = SSL_get_cipher_bits(ssl_handle, 0); return CipherInfo(name, version, bits); }
ssize_t tls_get_connection_info(struct tls *ctx, char *buf, size_t buflen) { SSL *conn = ctx->ssl_conn; const char *ocsp_pfx = "", *ocsp_info = ""; const char *proto = "-", *cipher = "-"; char dh[64]; int used_dh_bits = ctx->used_dh_bits, used_ecdh_nid = ctx->used_ecdh_nid; if (conn != NULL) { proto = SSL_get_version(conn); cipher = SSL_get_cipher(conn); #ifdef SSL_get_server_tmp_key if (ctx->flags & TLS_CLIENT) { EVP_PKEY *pk = NULL; int ok = SSL_get_server_tmp_key(conn, &pk); int pk_type = EVP_PKEY_id(pk); if (ok && pk) { if (pk_type == EVP_PKEY_DH) { DH *dh = EVP_PKEY_get0(pk); used_dh_bits = DH_size(dh) * 8; } else if (pk_type == EVP_PKEY_EC) { EC_KEY *ecdh = EVP_PKEY_get0(pk); const EC_GROUP *eg = EC_KEY_get0_group(ecdh); used_ecdh_nid = EC_GROUP_get_curve_name(eg); } EVP_PKEY_free(pk); } } #endif } if (used_dh_bits) { snprintf(dh, sizeof dh, "/DH=%d", used_dh_bits); } else if (used_ecdh_nid) { snprintf(dh, sizeof dh, "/ECDH=%s", OBJ_nid2sn(used_ecdh_nid)); } else { dh[0] = 0; } if (ctx->ocsp_result) { ocsp_info = ctx->ocsp_result; ocsp_pfx = "/OCSP="; } return snprintf(buf, buflen, "%s/%s%s%s%s", proto, cipher, dh, ocsp_pfx, ocsp_info); }
/* ssl_negotiate: After SSL state has been initialised, attempt to negotiate * SSL over the wire, including certificate checks. */ static int ssl_negotiate (CONNECTION *conn, sslsockdata* ssldata) { int err; const char* errmsg; #if OPENSSL_VERSION_NUMBER >= 0x00906000L /* This only exists in 0.9.6 and above. Without it we may get interrupted * reads or writes. Bummer. */ SSL_set_mode (ssldata->ssl, SSL_MODE_AUTO_RETRY); #endif if ((err = SSL_connect (ssldata->ssl)) != 1) { switch (SSL_get_error (ssldata->ssl, err)) { case SSL_ERROR_SYSCALL: errmsg = _("I/O error"); break; case SSL_ERROR_SSL: errmsg = ERR_error_string (ERR_get_error (), NULL); break; default: errmsg = _("unknown error"); } mutt_error (_("SSL failed: %s"), errmsg); mutt_sleep (1); return -1; } ssldata->cert = SSL_get_peer_certificate (ssldata->ssl); if (!ssldata->cert) { mutt_error (_("Unable to get certificate from peer")); mutt_sleep (1); return -1; } if (!ssl_check_certificate (conn, ssldata)) return -1; mutt_message (_("%s connection using %s (%s)"), SSL_get_version(ssldata->ssl), SSL_get_cipher_version (ssldata->ssl), SSL_get_cipher_name (ssldata->ssl)); mutt_sleep (0); return 0; }
/* ssl_negotiate: After SSL state has been initialized, attempt to negotiate * SSL over the wire, including certificate checks. */ static int ssl_negotiate (CONNECTION *conn, sslsockdata* ssldata) { int err; const char* errmsg; SSL_set_mode (ssldata->ssl, SSL_MODE_AUTO_RETRY); if ((err = SSL_connect (ssldata->ssl)) != 1) { switch (SSL_get_error (ssldata->ssl, err)) { case SSL_ERROR_SYSCALL: errmsg = _("I/O error"); break; case SSL_ERROR_SSL: errmsg = ERR_error_string (ERR_get_error (), NULL); break; default: errmsg = _("unknown error"); } mutt_error (_("SSL failed: %s"), errmsg); mutt_sleep (1); return -1; } ssldata->cert = SSL_get_peer_certificate (ssldata->ssl); if (!ssldata->cert) { mutt_error (_("Unable to get certificate from peer")); mutt_sleep (1); return -1; } if (!ssl_check_certificate (conn, ssldata)) return -1; /* L10N: %1$s is version (e.g. "TLSv1.2") %2$s is cipher_version (e.g. "TLSv1/SSLv3") %3$s is cipher_name (e.g. "ECDHE-RSA-AES128-GCM-SHA256") */ mutt_message (_("%s connection using %s (%s)"), SSL_get_version(ssldata->ssl), SSL_get_cipher_version (ssldata->ssl), SSL_get_cipher_name (ssldata->ssl)); mutt_sleep (0); return 0; }
/** * 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); lua_pushstring(L, SSL_get_version(ssl->ssl)); return 4; }
static void print_details(SSL *c_ssl, const char *prefix) { SSL_CIPHER *ciph; X509 *cert; ciph=SSL_get_current_cipher(c_ssl); BIO_printf(bio_stdout,"%s%s, cipher %s %s", prefix, SSL_get_version(c_ssl), SSL_CIPHER_get_version(ciph), SSL_CIPHER_get_name(ciph)); cert=SSL_get_peer_certificate(c_ssl); if (cert != NULL) { EVP_PKEY *pkey = X509_get_pubkey(cert); if (pkey != NULL) { if (0) ; #ifndef OPENSSL_NO_RSA else if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL && pkey->pkey.rsa->n != NULL) { BIO_printf(bio_stdout, ", %d bit RSA", BN_num_bits(pkey->pkey.rsa->n)); } #endif #ifndef OPENSSL_NO_DSA else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL && pkey->pkey.dsa->p != NULL) { BIO_printf(bio_stdout, ", %d bit DSA", BN_num_bits(pkey->pkey.dsa->p)); } #endif EVP_PKEY_free(pkey); } X509_free(cert); } /* The SSL API does not allow us to look at temporary RSA/DH keys, * otherwise we should print their lengths too */ BIO_printf(bio_stdout,"\n"); }
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; }
/* ************************************** * * Information functions * * Print information for the end user. * ***************************************/ void print_details (struct key_state_ssl * ks_ssl, const char *prefix) { const SSL_CIPHER *ciph; X509 *cert; char s1[256]; char s2[256]; s1[0] = s2[0] = 0; ciph = SSL_get_current_cipher (ks_ssl->ssl); openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s %s", prefix, SSL_get_version (ks_ssl->ssl), SSL_CIPHER_get_version (ciph), SSL_CIPHER_get_name (ciph)); cert = SSL_get_peer_certificate (ks_ssl->ssl); if (cert != NULL) { EVP_PKEY *pkey = X509_get_pubkey (cert); if (pkey != NULL) { if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL && pkey->pkey.rsa->n != NULL) { openvpn_snprintf (s2, sizeof (s2), ", %d bit RSA", BN_num_bits (pkey->pkey.rsa->n)); } else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL && pkey->pkey.dsa->p != NULL) { openvpn_snprintf (s2, sizeof (s2), ", %d bit DSA", BN_num_bits (pkey->pkey.dsa->p)); } EVP_PKEY_free (pkey); } X509_free (cert); } /* The SSL API does not allow us to look at temporary RSA/DH keys, * otherwise we should print their lengths too */ msg (D_HANDSHAKE, "%s%s", s1, s2); }
/** * We directly initiate a TLS handshake with the server. If the server is old * version (does not speak TLS) the connection will be denied. * @note the socket file descriptor in #conn_info must be connected and *not* * non-blocking * @return -1 in case of error */ int TLSTry(ConnectionInfo *conn_info) { if (PRIVKEY == NULL || PUBKEY == NULL) { Log(LOG_LEVEL_ERR, "No public/private key pair is loaded," " please create one using cf-key"); return -1; } assert(SSLCLIENTCONTEXT != NULL); conn_info->ssl = SSL_new(SSLCLIENTCONTEXT); if (conn_info->ssl == NULL) { Log(LOG_LEVEL_ERR, "SSL_new: %s", TLSErrorString(ERR_get_error())); return -1; } /* Pass conn_info inside the ssl struct for TLSVerifyCallback(). */ SSL_set_ex_data(conn_info->ssl, CONNECTIONINFO_SSL_IDX, conn_info); /* Initiate the TLS handshake over the already open TCP socket. */ SSL_set_fd(conn_info->ssl, conn_info->sd); int ret = SSL_connect(conn_info->ssl); if (ret <= 0) { TLSLogError(conn_info->ssl, LOG_LEVEL_ERR, "Failed to establish TLS connection", ret); return -1; } Log(LOG_LEVEL_VERBOSE, "TLS version negotiated: %8s; Cipher: %s,%s", SSL_get_version(conn_info->ssl), SSL_get_cipher_name(conn_info->ssl), SSL_get_cipher_version(conn_info->ssl)); Log(LOG_LEVEL_VERBOSE, "TLS session established, checking trust..."); return 0; }
static void ConnSSL_LogCertInfo( CONNECTION *c ) { #ifdef HAVE_LIBSSL SSL *ssl = c->ssl_state.ssl; assert(ssl); Log(LOG_INFO, "Connection %d: initialized %s using cipher %s.", c->sock, SSL_get_version(ssl), SSL_get_cipher(ssl)); #endif #ifdef HAVE_LIBGNUTLS gnutls_session_t sess = c->ssl_state.gnutls_session; gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess); Log(LOG_INFO, "Connection %d: initialized %s using cipher %s-%s.", c->sock, gnutls_protocol_get_name(gnutls_protocol_get_version(sess)), gnutls_cipher_get_name(cipher), gnutls_mac_get_name(gnutls_mac_get(sess))); #endif }
int tlsops_version(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { str version; 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_version\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; version.s = (char*)SSL_get_version(ssl); version.len = version.s ? strlen(version.s) : 0; if (version.len >= 1024) { LM_ERR("version string too long\n"); goto err; } memcpy(buf, version.s, version.len); res->rs.s = buf; res->rs.len = version.len; res->flags = PV_VAL_STR; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return pv_get_null(msg, param, res); }
#ifdef USE_SSL if (port->ssl) ereport(LOG, (errmsg("replication connection authorized: user=%s SSL enabled (protocol=%s, cipher=%s, compression=%s)", port->user_name, SSL_get_version(port->ssl), SSL_get_cipher(port->ssl), SSL_get_current_compression(port->ssl) ? _("on") : _("off")))); else #endif ereport(LOG, (errmsg("replication connection authorized: user=%s", port->user_name)));
/* * PerformAuthentication -- authenticate a remote client * * returns: nothing. Will not return at all if there's any failure. */ static void PerformAuthentication(Port *port) { /* This should be set already, but let's make sure */ ClientAuthInProgress = true; /* limit visibility of log messages */ /* * In EXEC_BACKEND case, we didn't inherit the contents of pg_hba.conf * etcetera from the postmaster, and have to load them ourselves. * * FIXME: [fork/exec] Ugh. Is there a way around this overhead? */ #ifdef EXEC_BACKEND if (!load_hba()) { /* * It makes no sense to continue if we fail to load the HBA file, * since there is no way to connect to the database in this case. */ ereport(FATAL, (errmsg("could not load pg_hba.conf"))); } if (!load_ident()) { /* * It is ok to continue if we fail to load the IDENT file, although it * means that you cannot log in using any of the authentication * methods that need a user name mapping. load_ident() already logged * the details of error to the log. */ } #endif /* * Set up a timeout in case a buggy or malicious client fails to respond * during authentication. Since we're inside a transaction and might do * database access, we have to use the statement_timeout infrastructure. */ enable_timeout_after(STATEMENT_TIMEOUT, AuthenticationTimeout * 1000); /* * Now perform authentication exchange. */ ClientAuthentication(port); /* might not return, if failure */ /* * Done with authentication. Disable the timeout, and log if needed. */ disable_timeout(STATEMENT_TIMEOUT, false); if (Log_connections) { if (am_walsender) { #ifdef USE_SSL if (port->ssl) ereport(LOG, (errmsg("replication connection authorized: user=%s SSL enabled (protocol=%s, cipher=%s, compression=%s)", port->user_name, SSL_get_version(port->ssl), SSL_get_cipher(port->ssl), SSL_get_current_compression(port->ssl) ? _("on") : _("off")))); else #endif ereport(LOG, (errmsg("replication connection authorized: user=%s", port->user_name))); } else { #ifdef USE_SSL if (port->ssl) ereport(LOG, (errmsg("connection authorized: user=%s database=%s SSL enabled (protocol=%s, cipher=%s, compression=%s)", port->user_name, port->database_name, SSL_get_version(port->ssl), SSL_get_cipher(port->ssl), SSL_get_current_compression(port->ssl) ? _("on") : _("off")))); else #endif ereport(LOG, (errmsg("connection authorized: user=%s database=%s", port->user_name, port->database_name))); } } set_ps_display("startup", false); ClientAuthInProgress = false; /* client_min_messages is active now */ }
/* * 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); }
/****************************** transfer data */ static int transfer(CLI *c) { int num, err; int check_SSL_pending; enum {CL_OPEN, CL_INIT, CL_RETRY, CL_CLOSED} ssl_closing=CL_OPEN; int watchdog=0; /* a counter to detect an infinite loop */ c->sock_ptr=c->ssl_ptr=0; sock_rd=sock_wr=ssl_rd=ssl_wr=1; c->sock_bytes=c->ssl_bytes=0; do { /* main loop */ /* set flag to try and read any buffered SSL data * if we made room in the buffer by writing to the socket */ check_SSL_pending=0; /****************************** setup c->fds structure */ s_poll_zero(&c->fds); /* Initialize the structure */ if(sock_rd && c->sock_ptr<BUFFSIZE) /* socket input buffer not full*/ s_poll_add(&c->fds, c->sock_rfd->fd, 1, 0); if((ssl_rd && c->ssl_ptr<BUFFSIZE) || /* SSL input buffer not full */ ((c->sock_ptr || ssl_closing==CL_RETRY) && want_rd)) /* want to SSL_write or SSL_shutdown but read from the * underlying socket needed for the SSL protocol */ s_poll_add(&c->fds, c->ssl_rfd->fd, 1, 0); if(c->ssl_ptr) /* SSL input buffer not empty */ s_poll_add(&c->fds, c->sock_wfd->fd, 0, 1); if(c->sock_ptr || /* socket input buffer not empty */ ssl_closing==CL_INIT /* need to send close_notify */ || ((c->ssl_ptr<BUFFSIZE || ssl_closing==CL_RETRY) && want_wr)) /* want to SSL_read or SSL_shutdown but write to the * underlying socket needed for the SSL protocol */ s_poll_add(&c->fds, c->ssl_wfd->fd, 0, 1); /****************************** wait for an event */ err=s_poll_wait(&c->fds, (sock_rd && ssl_rd) /* both peers open */ || c->ssl_ptr /* data buffered to write to socket */ || c->sock_ptr /* data buffered to write to SSL */ ? c->opt->timeout_idle : c->opt->timeout_close); switch(err) { case -1: sockerror("transfer: s_poll_wait"); return -1; case 0: /* timeout */ if((sock_rd && ssl_rd) || c->ssl_ptr || c->sock_ptr) { s_log(LOG_INFO, "s_poll_wait timeout: connection reset"); return -1; } else { /* already closing connection */ s_log(LOG_INFO, "s_poll_wait timeout: connection close"); return 0; /* OK */ } } if(!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) { s_log(LOG_ERR, "INTERNAL ERROR: " "s_poll_wait returned %d, but no descriptor is ready", err); return -1; } /****************************** send SSL close_notify message */ if(ssl_closing==CL_INIT || (ssl_closing==CL_RETRY && ((want_rd && ssl_can_rd) || (want_wr && ssl_can_wr)))) { switch(SSL_shutdown(c->ssl)) { /* Send close_notify */ case 1: /* the shutdown was successfully completed */ s_log(LOG_INFO, "SSL_shutdown successfully sent close_notify"); ssl_closing=CL_CLOSED; /* done! */ break; case 0: /* the shutdown is not yet finished */ s_log(LOG_DEBUG, "SSL_shutdown retrying"); ssl_closing=CL_RETRY; /* retry next time */ break; case -1: /* a fatal error occurred */ sslerror("SSL_shutdown"); return -1; } } /****************************** write to socket */ if(sock_wr && sock_can_wr) { /* for stunnel to tell web server the remote ip address */ add_remote_ip_to_header(c); num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr); switch(num) { case -1: /* error */ if(parse_socket_error("writesocket")) return -1; break; case 0: s_log(LOG_DEBUG, "No data written to the socket: retrying"); break; default: memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num); if(c->ssl_ptr==BUFFSIZE) /* buffer was previously full */ check_SSL_pending=1; /* check for data buffered by SSL */ c->ssl_ptr-=num; c->sock_bytes+=num; watchdog=0; /* reset watchdog */ } } /****************************** write to SSL */ if(ssl_wr && c->sock_ptr && ( /* output buffer not empty */ ssl_can_wr || (want_rd && ssl_can_rd) /* SSL_write wants to read from the underlying descriptor */ )) { num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr); switch(err=SSL_get_error(c->ssl, num)) { case SSL_ERROR_NONE: memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num); c->sock_ptr-=num; c->ssl_bytes+=num; watchdog=0; /* reset watchdog */ break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_write returned WANT_WRITE: retrying"); break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_write returned WANT_READ: retrying"); break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_write returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: /* really an error */ if(num && parse_socket_error("SSL_write")) return -1; break; case SSL_ERROR_ZERO_RETURN: /* close_notify received */ s_log(LOG_DEBUG, "SSL closed on SSL_write"); ssl_rd=0; break; case SSL_ERROR_SSL: sslerror("SSL_write"); return -1; default: s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err); return -1; } } /****************************** read from socket */ if(sock_rd && sock_can_rd) { num=readsocket(c->sock_rfd->fd, c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr); switch(num) { case -1: if(parse_socket_error("readsocket")) return -1; break; case 0: /* close */ s_log(LOG_DEBUG, "Socket closed on read"); sock_rd=0; break; default: c->sock_ptr+=num; watchdog=0; /* reset watchdog */ } } /****************************** read from SSL */ if(ssl_rd && c->ssl_ptr<BUFFSIZE && ( /* input buffer not full */ ssl_can_rd || (want_wr && ssl_can_wr) || /* SSL_read wants to write to the underlying descriptor */ (check_SSL_pending && SSL_pending(c->ssl)) /* write made space from full buffer */ )) { num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr); switch(err=SSL_get_error(c->ssl, num)) { case SSL_ERROR_NONE: c->ssl_ptr+=num; watchdog=0; /* reset watchdog */ break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_read returned WANT_WRITE: retrying"); break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_read returned WANT_READ: retrying"); break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_read returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: if(!num) { /* EOF */ if(c->sock_ptr) { s_log(LOG_ERR, "SSL socket closed with %d byte(s) in buffer", c->sock_ptr); return -1; /* reset the socket */ } s_log(LOG_DEBUG, "SSL socket closed on SSL_read"); ssl_rd=ssl_wr=0; /* buggy or SSLv2 peer: no close_notify */ ssl_closing=CL_CLOSED; /* don't try to send it back */ } else if(parse_socket_error("SSL_read")) return -1; break; case SSL_ERROR_ZERO_RETURN: /* close_notify received */ s_log(LOG_DEBUG, "SSL closed on SSL_read"); ssl_rd=0; break; case SSL_ERROR_SSL: sslerror("SSL_read"); return -1; default: s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err); return -1; } } /****************************** check write shutdown conditions */ if(sock_wr && !ssl_rd && !c->ssl_ptr) { s_log(LOG_DEBUG, "Socket write shutdown"); sock_wr=0; /* no further write allowed */ shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */ } if(ssl_wr && (!sock_rd || SSL_get_shutdown(c->ssl)) && !c->sock_ptr) { s_log(LOG_DEBUG, "SSL write shutdown"); ssl_wr=0; /* no further write allowed */ if(strcmp(SSL_get_version(c->ssl), "SSLv2")) { /* SSLv3, TLSv1 */ ssl_closing=CL_INIT; /* initiate close_notify */ } else { /* no alerts in SSLv2 including close_notify alert */ shutdown(c->sock_rfd->fd, SHUT_RD); /* notify the kernel */ shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */ SSL_set_shutdown(c->ssl, /* notify the OpenSSL library */ SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); ssl_rd=0; /* no further read allowed */ ssl_closing=CL_CLOSED; /* closed */ } } if(ssl_closing==CL_RETRY) { /* SSL shutdown */ if(!want_rd && !want_wr) { /* close_notify alert was received */ s_log(LOG_DEBUG, "SSL doesn't need to read or write"); ssl_closing=CL_CLOSED; } if(watchdog>5) { s_log(LOG_NOTICE, "Too many retries on SSL shutdown"); ssl_closing=CL_CLOSED; } } /****************************** check watchdog */ if(++watchdog>100) { /* loop executes without transferring any data */ s_log(LOG_ERR, "transfer() loop executes not transferring any data"); s_log(LOG_ERR, "please report the problem to [email protected]"); s_log(LOG_ERR, "socket open: rd=%s wr=%s, ssl open: rd=%s wr=%s", sock_rd ? "yes" : "no", sock_wr ? "yes" : "no", ssl_rd ? "yes" : "no", ssl_wr ? "yes" : "no"); s_log(LOG_ERR, "socket ready: rd=%s wr=%s, ssl ready: rd=%s wr=%s", sock_can_rd ? "yes" : "no", sock_can_wr ? "yes" : "no", ssl_can_rd ? "yes" : "no", ssl_can_wr ? "yes" : "no"); s_log(LOG_ERR, "ssl want: rd=%s wr=%s", want_rd ? "yes" : "no", want_wr ? "yes" : "no"); s_log(LOG_ERR, "socket input buffer: %d byte(s), " "ssl input buffer: %d byte(s)", c->sock_ptr, c->ssl_ptr); s_log(LOG_ERR, "check_SSL_pending=%d, ssl_closing=%d", check_SSL_pending, ssl_closing); return -1; } } while(sock_wr || ssl_closing!=CL_CLOSED); return 0; /* OK */ }
extern "C" const char* CryptoNative_SslGetVersion(SSL* ssl) { return SSL_get_version(ssl); }