wi_uinteger_t wi_socket_cipher_bits(wi_socket_t *socket) { #ifdef HAVE_OPENSSL_SSL_H return SSL_get_cipher_bits(socket->ssl, NULL); #else return 0; #endif }
uint32_t wi_socket_cipher_bits(wi_socket_t *socket) { #ifdef WI_SSL return SSL_get_cipher_bits(socket->ssl, NULL); #else return 0; #endif }
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); }
/* * printSSLInfo * * Prints information about the current SSL connection, if SSL is in use */ static void printSSLInfo(void) { #ifdef USE_SSL int sslbits = -1; SSL *ssl; ssl = PQgetssl(pset.db); if (!ssl) return; /* no SSL */ SSL_get_cipher_bits(ssl, &sslbits); printf(_("SSL connection (cipher: %s, bits: %i)\n"), SSL_get_cipher(ssl), sslbits); #else /* * If psql is compiled without SSL but is using a libpq with SSL, we * cannot figure out the specifics about the connection. But we know it's * SSL secured. */ if (PQgetssl(pset.db)) printf(_("SSL connection (unknown cipher)\n")); #endif }
unsigned char * get_ssl_connection_cipher(struct socket *socket) { ssl_t *ssl = socket->ssl; struct string str; if (!init_string(&str)) return NULL; #ifdef USE_OPENSSL add_format_to_string(&str, "%ld-bit %s %s", SSL_get_cipher_bits(ssl, NULL), SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl)); #elif defined(CONFIG_GNUTLS) /* XXX: How to get other relevant parameters? */ add_format_to_string(&str, "%s - %s - %s - %s - %s (compr: %s)", gnutls_protocol_get_name(gnutls_protocol_get_version(*ssl)), gnutls_kx_get_name(gnutls_kx_get(*ssl)), gnutls_cipher_get_name(gnutls_cipher_get(*ssl)), gnutls_mac_get_name(gnutls_mac_get(*ssl)), gnutls_certificate_type_get_name(gnutls_certificate_type_get(*ssl)), gnutls_compression_get_name(gnutls_compression_get(*ssl))); #endif return str.source; }
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)); }
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_cipher_version(ssl), SSL_get_cipher_name(ssl), SSL_get_cipher_bits(ssl, NULL)); return (buf); }
/** wrapper around SSL_connect, using SSL return convention. * It will also log critical errors and certificate debugging info. * @param c - tcp connection with tls (extra_data must be a filled * tcp_extra_data structure). The state must be S_TLS_CONNECTING. * @param error set to the error reason (SSL_ERROR_*). * Note that it can be SSL_ERROR_NONE while the return is < 0 * ("internal" error, not at the SSL level, see below). * @return >=1 on success, 0 and <0 on error. 0 means the underlying SSL * connection was closed/shutdown. < 0 is returned for any * SSL_ERROR (including WANT_READ or WANT_WRITE), but also * for internal non SSL related errors (in this case -2 is * returned and error==SSL_ERROR_NONE). * */ int tls_connect(struct tcp_connection *c, int* error) { SSL *ssl; int ret; X509* cert; struct tls_extra_data* tls_c; int tls_log; *error = SSL_ERROR_NONE; tls_c=(struct tls_extra_data*)c->extra_data; ssl=tls_c->ssl; if (unlikely(tls_c->state != S_TLS_CONNECTING)) { BUG("Invalid connection state %d (bug in TLS code)\n", tls_c->state); goto err; } ret = SSL_connect(ssl); if (unlikely(ret == 1)) { DBG("TLS connect successful\n"); tls_c->state = S_TLS_ESTABLISHED; tls_log = cfg_get(tls, tls_cfg, log); LOG(tls_log, "tls_connect: new connection to %s:%d using %s %s %d\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port, SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl), SSL_get_cipher_bits(ssl, 0) ); LOG(tls_log, "tls_connect: sending socket: %s:%d \n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port ); cert = SSL_get_peer_certificate(ssl); if (cert != 0) { tls_dump_cert_info("tls_connect: server certificate", cert); if (SSL_get_verify_result(ssl) != X509_V_OK) { LOG(tls_log, "WARNING: tls_connect: server certificate " "verification failed!!!\n"); tls_dump_verification_failure(SSL_get_verify_result(ssl)); } X509_free(cert); } else { /* this should not happen, servers always present a cert */ LOG(tls_log, "tls_connect: server did not " "present a certificate\n"); } tls_run_event_routes(c); } else { /* 0 or < 0 */ *error = SSL_get_error(ssl, ret); } return ret; err: /* internal non openssl related errors */ return -2; }
int be_tls_get_cipher_bits(Port *port) { int bits; if (port->ssl) { SSL_get_cipher_bits(port->ssl, &bits); return bits; } else return 0; }
static int check_cipher_strength(SSL *ssl, ImapUserCb user_cb, void *user_arg) { int ok, bits = SSL_get_cipher_bits(ssl, NULL); if (bits > 40) return 1; ok = 0; if (user_cb != NULL) user_cb(IME_TLS_WEAK_CIPHER, user_arg, bits, &ok); return ok; }
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); }
/** wrapper around SSL_accept, usin SSL return convention. * It will also log critical errors and certificate debugging info. * @param c - tcp connection with tls (extra_data must be a filled * tcp_extra_data structure). The state must be S_TLS_ACCEPTING. * @param error set to the error reason (SSL_ERROR_*). * Note that it can be SSL_ERROR_NONE while the return is < 0 * ("internal" error, not at the SSL level, see below). * @return >=1 on success, 0 and <0 on error. 0 means the underlying SSL * connection was closed/shutdown. < 0 is returned for any * SSL_ERROR (including WANT_READ or WANT_WRITE), but also * for internal non SSL related errors (in this case -2 is * returned and error==SSL_ERROR_NONE). * */ int tls_accept(struct tcp_connection *c, int* error) { int ret; SSL *ssl; X509* cert; struct tls_extra_data* tls_c; int tls_log; *error = SSL_ERROR_NONE; tls_c=(struct tls_extra_data*)c->extra_data; ssl=tls_c->ssl; if (unlikely(tls_c->state != S_TLS_ACCEPTING)) { BUG("Invalid connection state %d (bug in TLS code)\n", tls_c->state); goto err; } ret = SSL_accept(ssl); if (unlikely(ret == 1)) { DBG("TLS accept successful\n"); tls_c->state = S_TLS_ESTABLISHED; tls_log = cfg_get(tls, tls_cfg, log); LOG(tls_log, "tls_accept: new connection from %s:%d using %s %s %d\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port, SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl), SSL_get_cipher_bits(ssl, 0) ); LOG(tls_log, "tls_accept: local socket: %s:%d\n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port ); cert = SSL_get_peer_certificate(ssl); if (cert != 0) { tls_dump_cert_info("tls_accept: client certificate", cert); if (SSL_get_verify_result(ssl) != X509_V_OK) { LOG(tls_log, "WARNING: tls_accept: client certificate " "verification failed!!!\n"); tls_dump_verification_failure(SSL_get_verify_result(ssl)); } X509_free(cert); } else { LOG(tls_log, "tls_accept: client did not present a certificate\n"); } } else { /* ret == 0 or < 0 */ *error = SSL_get_error(ssl, ret); } return ret; err: /* internal non openssl related errors */ return -2; }
int verify_ssl_cipher(SSL *ssl) { unsigned char *cipher; #ifdef HAVE_SSLV2_CLIENT_METHOD if (SSL_get_ssl_method(ssl) == SSLv2_client_method()) return S_INSECURE_CIPHER; #endif #ifdef HAVE_SSLV3_CLIENT_METHOD if (SSL_get_ssl_method(ssl) == SSLv3_client_method()) return S_INSECURE_CIPHER; #endif if (SSL_get_cipher_bits(ssl, NULL) < 112) return S_INSECURE_CIPHER; cipher = cast_uchar SSL_get_cipher_name(ssl); if (cipher && strstr(cast_const_char cipher, "RC4-")) return S_INSECURE_CIPHER; return 0; }
const char * ssl_to_text(const SSL *ssl) { static char buf[256]; static char description[128]; char *tls_version = NULL; /* * SSL_get_cipher_version() does not know about the exact TLS version... * you have to pick it up from second field of the SSL cipher description ! */ SSL_CIPHER_description(SSL_get_current_cipher(ssl), description, sizeof description); tls_version = strchr(description, ' ') + 1; tls_version[strcspn(tls_version, " ")] = '\0'; (void)snprintf(buf, sizeof buf, "version=%s (%s), cipher=%s, bits=%d", SSL_get_cipher_version(ssl), tls_version, SSL_get_cipher_name(ssl), SSL_get_cipher_bits(ssl, NULL)); return (buf); }
/* side effect: fills the ssl->fingerprint buffer */ static gboolean ssl_verify_certificate (LmSSL *ssl, const gchar *server) { gboolean retval = TRUE; gboolean match_result = FALSE; LmSSLBase *base; long verify_res; int rc; const EVP_MD *digest = EVP_sha256(); unsigned int digest_len; guchar digest_bin[EVP_MD_size(digest)]; X509 *srv_crt; gchar *cn; X509_NAME *crt_subj; base = LM_SSL_BASE(ssl); g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: Cipher: %s/%s/%i\n", __FILE__, SSL_get_cipher_version(ssl->ssl), SSL_get_cipher_name(ssl->ssl), SSL_get_cipher_bits(ssl->ssl, NULL)); verify_res = SSL_get_verify_result(ssl->ssl); srv_crt = SSL_get_peer_certificate(ssl->ssl); rc = X509_digest(srv_crt, digest, digest_bin, &digest_len); if ((rc != 0) && (digest_len == EVP_MD_size(digest))) { _lm_ssl_base_set_fingerprint(base, digest_bin, digest_len); if (_lm_ssl_base_check_fingerprint(base) != 0) { if (base->func(ssl, LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { return FALSE; } } } else { if (base->func(ssl, LM_SSL_STATUS_GENERIC_ERROR, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { return FALSE; } } g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: SSL_get_verify_result() = %ld\n", __FILE__, verify_res); switch (verify_res) { case X509_V_OK: break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: case X509_V_ERR_UNABLE_TO_GET_CRL: if (base->func(ssl, LM_SSL_STATUS_NO_CERT_FOUND, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: /* special case for self signed certificates? */ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: case X509_V_ERR_INVALID_CA: case X509_V_ERR_CERT_UNTRUSTED: case X509_V_ERR_CERT_REVOKED: if (base->func(ssl, LM_SSL_STATUS_UNTRUSTED_CERT, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_CRL_NOT_YET_VALID: if (base->func(ssl, LM_SSL_STATUS_CERT_NOT_ACTIVATED, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_CRL_HAS_EXPIRED: if (base->func(ssl, LM_SSL_STATUS_CERT_EXPIRED, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } break; default: if (base->func(ssl, LM_SSL_STATUS_GENERIC_ERROR, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } } /*if (retval == FALSE) { g_set_error (error, LM_ERROR, LM_ERROR_CONNECTION_OPEN, ssl_get_x509_err(verify_res), NULL); }*/ crt_subj = X509_get_subject_name(srv_crt); cn = (gchar *) g_malloc0(LM_SSL_CN_MAX + 1); /* FWB: deprecated call, can only get first entry */ if (X509_NAME_get_text_by_NID(crt_subj, NID_commonName, cn, LM_SSL_CN_MAX) > 0) { g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: server = '%s', cn = '%s'\n", __FILE__, server, cn); if (cn != NULL && ssl_match_domain_name(server, cn)) { match_result = TRUE; } else { /* g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: CN does not match server name\n", __FILE__); */ } } else { g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "X509_NAME_get_text_by_NID() failed"); } /* RFC6125: "...However, it is perfectly acceptable for the subject field to be empty, * as long as the certificate contains a subject alternative name ("subjectAltName") * extension that includes at least one subjectAltName entry" */ if (!match_result) { /* FWB: CN doesn't match, try SANs */ int subject_alt_names_nb = -1; int san_counter; STACK_OF(GENERAL_NAME) *subject_alt_names = NULL; // Try to extract the names within the SAN extension from the certificate subject_alt_names = X509_get_ext_d2i((X509 *) srv_crt, NID_subject_alt_name, NULL, NULL); if (subject_alt_names != NULL) { // Check each name within the extension subject_alt_names_nb = sk_GENERAL_NAME_num(subject_alt_names); for (san_counter=0; san_counter<subject_alt_names_nb; san_counter++) { const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(subject_alt_names, san_counter); if (current_name->type == GEN_DNS) { // Current name is a DNS name, let's check it, it's ASCII if (ssl_match_domain_name(server, (const char *)current_name->d.dNSName->data)) { g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: found SAN '%s' - MATCH\n", __FILE__, current_name->d.dNSName->data); match_result = TRUE; /* break; */ } else { g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: found SAN '%s'\n", __FILE__, current_name->d.dNSName->data); } } } } sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free); } if (!match_result) { if (base->func (ssl, LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } } g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s:\n\tIssuer: %s\n\tSubject: %s\n\tFor: %s\n", __FILE__, X509_NAME_oneline(X509_get_issuer_name(srv_crt), NULL, 0), X509_NAME_oneline(X509_get_subject_name(srv_crt), NULL, 0), cn); g_free(cn); return retval; }
int h2o_socket_get_ssl_cipher_bits(h2o_socket_t *sock) { return sock->ssl != NULL ? SSL_get_cipher_bits(sock->ssl->ssl, NULL) : 0; }
/* * Wrapper around SSL_accept, returns -1 on error, 0 on success */ static int tls_accept(struct tcp_connection *c, short *poll_events) { int ret, err; SSL *ssl; X509* cert; if ( (c->proto_flags&F_TLS_DO_ACCEPT)==0 ) { LM_BUG("invalid connection state (bug in TLS code)\n"); return -1; } ssl = (SSL *) c->extra_data; #ifndef OPENSSL_NO_KRB5 if ( ssl->kssl_ctx==NULL ) ssl->kssl_ctx = kssl_ctx_new( ); #endif ret = SSL_accept(ssl); #ifndef OPENSSL_NO_KRB5 if ( ssl->kssl_ctx ) { kssl_ctx_free( ssl->kssl_ctx ); ssl->kssl_ctx = 0; } #endif if (ret > 0) { LM_INFO("New TLS connection from %s:%d accepted\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); /* TLS accept done, reset the flag */ c->proto_flags &= ~F_TLS_DO_ACCEPT; LM_DBG("new TLS connection from %s:%d using %s %s %d\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port, SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl), SSL_get_cipher_bits(ssl, 0) ); LM_DBG("local socket: %s:%d\n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port ); cert = SSL_get_peer_certificate(ssl); if (cert != 0) { tls_dump_cert_info("tls_accept: client TLS certificate", cert); if (SSL_get_verify_result(ssl) != X509_V_OK) { LM_WARN("TLS client certificate verification failed\n"); tls_dump_verification_failure(SSL_get_verify_result(ssl)); } X509_free(cert); } else { LM_INFO("Client did not present a TLS certificate\n"); } cert = SSL_get_certificate(ssl); if (cert != 0) { tls_dump_cert_info("tls_accept: local TLS server certificate", cert); } else { /* this should not happen, servers always present a cert */ LM_ERR("local TLS server domain has no certificate\n"); } return 0; } else { err = SSL_get_error(ssl, ret); switch (err) { case SSL_ERROR_ZERO_RETURN: LM_INFO("TLS connection from %s:%d accept failed cleanly\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); c->state = S_CONN_BAD; return -1; case SSL_ERROR_WANT_READ: if (poll_events) *poll_events = POLLIN; return 0; case SSL_ERROR_WANT_WRITE: if (poll_events) *poll_events = POLLOUT; return 0; default: c->state = S_CONN_BAD; if (errno == 0) { LM_ERR("New TLS connection from %s:%d failed to accept:" " rejected by client\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); } else { LM_ERR("New TLS connection from %s:%d failed to accept\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); LM_ERR("TLS error: (ret=%d, err=%d, errno=%d/%s):\n", ret, err, errno, strerror(errno)); tls_print_errstack(); } return -1; } } LM_BUG("bug\n"); return -1; }
static gboolean ssl_verify_certificate (LmSSL *ssl, const gchar *server) { gboolean retval = TRUE; LmSSLBase *base; long verify_res; unsigned int digest_len; X509 *srv_crt; gchar *cn; X509_NAME *crt_subj; base = LM_SSL_BASE(ssl); g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: Cipher: %s/%s/%i\n", __FILE__, SSL_get_cipher_version(ssl->ssl), SSL_get_cipher_name(ssl->ssl), SSL_get_cipher_bits(ssl->ssl, NULL)); verify_res = SSL_get_verify_result(ssl->ssl); srv_crt = SSL_get_peer_certificate(ssl->ssl); if (base->expected_fingerprint != NULL) { X509_digest(srv_crt, EVP_md5(), (guchar *) base->fingerprint, &digest_len); if (memcmp(base->expected_fingerprint, base->fingerprint, digest_len) != 0) { if (base->func(ssl, LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { return FALSE; } } } g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: SSL_get_verify_result() = %ld\n", __FILE__, verify_res); switch (verify_res) { case X509_V_OK: break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: /* special case for self signed certificates? */ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: case X509_V_ERR_UNABLE_TO_GET_CRL: case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: if (base->func(ssl, LM_SSL_STATUS_NO_CERT_FOUND, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } break; case X509_V_ERR_INVALID_CA: case X509_V_ERR_CERT_UNTRUSTED: case X509_V_ERR_CERT_REVOKED: if (base->func(ssl, LM_SSL_STATUS_UNTRUSTED_CERT, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_CRL_NOT_YET_VALID: if (base->func(ssl, LM_SSL_STATUS_CERT_NOT_ACTIVATED, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_CRL_HAS_EXPIRED: if (base->func(ssl, LM_SSL_STATUS_CERT_EXPIRED, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } break; default: if (base->func(ssl, LM_SSL_STATUS_GENERIC_ERROR, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } } /*if (retval == FALSE) { g_set_error (error, LM_ERROR, LM_ERROR_CONNECTION_OPEN, ssl_get_x509_err(verify_res), NULL); }*/ crt_subj = X509_get_subject_name(srv_crt); cn = (gchar *) g_malloc0(LM_SSL_CN_MAX + 1); if (X509_NAME_get_text_by_NID(crt_subj, NID_commonName, cn, LM_SSL_CN_MAX) > 0) { gchar *domain = cn; g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: server = '%s', cn = '%s'\n", __FILE__, server, cn); if ((cn[0] == '*') && (cn[1] == '.')) { domain = strstr (cn, server); } if ((domain == NULL) || (strncmp (server, domain, LM_SSL_CN_MAX) != 0)) { if (base->func (ssl, LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH, base->func_data) != LM_SSL_RESPONSE_CONTINUE) { retval = FALSE; } } } else { g_warning ("X509_NAME_get_text_by_NID() failed"); } g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s:\n\tIssuer: %s\n\tSubject: %s\n\tFor: %s\n", __FILE__, X509_NAME_oneline(X509_get_issuer_name(srv_crt), NULL, 0), X509_NAME_oneline(X509_get_subject_name(srv_crt), NULL, 0), cn); g_free(cn); return retval; }
void wr_connect(char *host, int port, char *login, char *password) { SHA_CTX c; static unsigned char hex[] = "0123456789abcdef"; unsigned char sha[SHA_DIGEST_LENGTH]; struct hostent *hp; int i, on = 1; /* disconnect active socket */ if(wr_socket >= 0) wr_close(); /* reset current working directory */ strlcpy(wr_files_cwd, "/", sizeof(wr_files_cwd)); /* copy values */ wr_port = port; if(port != 2000) snprintf(wr_host, sizeof(wr_host), "%s:%d", host, port); else strlcpy(wr_host, host, sizeof(wr_host)); strlcpy(wr_login, login, sizeof(wr_login)); strlcpy(wr_password, password, sizeof(wr_password)); /* log */ wr_printf_prefix("Connecting to %s...\n", wr_host); /* create new socket */ wr_socket = socket(AF_INET, SOCK_STREAM, 0); if(wr_socket < 0) { wr_printf_prefix("Could not create a socket: %s\n", strerror(errno)); wr_close(); return; } /* set socket options */ if(setsockopt(wr_socket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) { wr_printf_prefix("Could not set socket options: %s\n", strerror(errno)); wr_close(); return; } /* init address */ memset(&wr_addr, 0, sizeof(wr_addr)); wr_addr.sin_family = AF_INET; wr_addr.sin_port = htons(port); if(!inet_aton(host, &wr_addr.sin_addr)) { hp = gethostbyname(host); if(!hp) { wr_printf_prefix("Could not resolve hostname %s: %s\n", host, hstrerror(h_errno)); wr_close(); return; } memcpy(&wr_addr.sin_addr, hp->h_addr, sizeof(wr_addr.sin_addr)); } /* connect TCP socket */ if(connect(wr_socket, (struct sockaddr *) &wr_addr, sizeof(wr_addr)) < 0) { wr_printf_prefix("Could not connect to %s: %s\n", host, strerror(errno)); wr_close(); return; } /* create SSL context */ wr_ssl_ctx = SSL_CTX_new(TLSv1_client_method()); if(!wr_ssl_ctx) { wr_printf_prefix("Could not create SSL context: %s\n", ERR_reason_error_string(ERR_get_error())); wr_close(); return; } if(SSL_CTX_set_cipher_list(wr_ssl_ctx, "ALL") != 1) { wr_printf_prefix("Could not set SSL cipher list: %s\n", ERR_reason_error_string(ERR_get_error())); wr_close(); return; } /* create SSL socket */ wr_ssl = SSL_new(wr_ssl_ctx); if(!wr_ssl) { wr_printf_prefix("Could not create SSL socket: %s\n", ERR_reason_error_string(ERR_get_error())); wr_close(); return; } if(SSL_set_fd(wr_ssl, wr_socket) != 1) { wr_printf_prefix("Could not set SSL file descriptor: %s\n", ERR_reason_error_string(ERR_get_error())); wr_close(); return; } if(SSL_connect(wr_ssl) != 1) { wr_printf_prefix("Could not connect to %s via SSL: %s\n", host, ERR_reason_error_string(ERR_get_error())); wr_close(); return; } /* log */ wr_printf_prefix("Connected using %s/%s/%u bits, logging in...\n", SSL_get_cipher_version(wr_ssl), SSL_get_cipher_name(wr_ssl), SSL_get_cipher_bits(wr_ssl, NULL)); /* send initial login */ wr_send_command("HELLO%s", WR_MESSAGE_SEPARATOR); /* hash the password */ memset(wr_password_sha, 0, sizeof(wr_password_sha)); if(strlen(wr_password) > 0) { SHA1_Init(&c); SHA1_Update(&c, (unsigned char *) wr_password, strlen(wr_password)); SHA1_Final(sha, &c); /* map into hexademical characters */ for(i = 0; i < SHA_DIGEST_LENGTH; i++) { wr_password_sha[i+i] = hex[sha[i] >> 4]; wr_password_sha[i+i+1] = hex[sha[i] & 0x0F]; } wr_password_sha[i+i] = '\0'; }
bool reds_sasl_start_auth(RedsStream *stream, AsyncReadDone read_cb, void *opaque) { const char *mechlist = NULL; sasl_security_properties_t secprops; int err; char *localAddr, *remoteAddr; int mechlistlen; RedsSASL *sasl = &stream->priv->sasl; if (!(localAddr = reds_stream_get_local_address(stream))) { goto error; } if (!(remoteAddr = reds_stream_get_remote_address(stream))) { free(localAddr); goto error; } err = sasl_server_new("spice", NULL, /* FQDN - just delegates to gethostname */ NULL, /* User realm */ localAddr, remoteAddr, NULL, /* Callbacks, not needed */ SASL_SUCCESS_DATA, &sasl->conn); free(localAddr); free(remoteAddr); localAddr = remoteAddr = NULL; if (err != SASL_OK) { spice_warning("sasl context setup failed %d (%s)", err, sasl_errstring(err, NULL, NULL)); sasl->conn = NULL; goto error; } /* Inform SASL that we've got an external SSF layer from TLS */ if (stream->priv->ssl) { sasl_ssf_t ssf; ssf = SSL_get_cipher_bits(stream->priv->ssl, NULL); err = sasl_setprop(sasl->conn, SASL_SSF_EXTERNAL, &ssf); if (err != SASL_OK) { spice_warning("cannot set SASL external SSF %d (%s)", err, sasl_errstring(err, NULL, NULL)); goto error_dispose; } } else { sasl->wantSSF = 1; } memset(&secprops, 0, sizeof secprops); /* Inform SASL that we've got an external SSF layer from TLS */ if (stream->priv->ssl) { /* If we've got TLS (or UNIX domain sock), we don't care about SSF */ secprops.min_ssf = 0; secprops.max_ssf = 0; secprops.maxbufsize = 8192; secprops.security_flags = 0; } else { /* Plain TCP, better get an SSF layer */ secprops.min_ssf = 56; /* Good enough to require kerberos */ secprops.max_ssf = 100000; /* Arbitrary big number */ secprops.maxbufsize = 8192; /* Forbid any anonymous or trivially crackable auth */ secprops.security_flags = SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; } err = sasl_setprop(sasl->conn, SASL_SEC_PROPS, &secprops); if (err != SASL_OK) { spice_warning("cannot set SASL security props %d (%s)", err, sasl_errstring(err, NULL, NULL)); goto error_dispose; } err = sasl_listmech(sasl->conn, NULL, /* Don't need to set user */ "", /* Prefix */ ",", /* Separator */ "", /* Suffix */ &mechlist, NULL, NULL); if (err != SASL_OK || mechlist == NULL) { spice_warning("cannot list SASL mechanisms %d (%s)", err, sasl_errdetail(sasl->conn)); goto error_dispose; } spice_debug("Available mechanisms for client: '%s'", mechlist); sasl->mechlist = spice_strdup(mechlist); mechlistlen = strlen(mechlist); if (!reds_stream_write_all(stream, &mechlistlen, sizeof(uint32_t)) || !reds_stream_write_all(stream, sasl->mechlist, mechlistlen)) { spice_warning("SASL mechanisms write error"); goto error; } spice_debug("Wait for client mechname length"); reds_stream_async_read(stream, (uint8_t *)&sasl->len, sizeof(uint32_t), read_cb, opaque); return true; error_dispose: sasl_dispose(&sasl->conn); sasl->conn = NULL; error: return false; }
/* * wrapper around SSL_connect, returns 0 on success, -1 on error */ static int tls_connect(struct tcp_connection *c, short *poll_events) { int ret, err; SSL *ssl; X509* cert; if ( (c->proto_flags&F_TLS_DO_CONNECT)==0 ) { LM_BUG("invalid connection state (bug in TLS code)\n"); return -1; } ssl = (SSL *) c->extra_data; ret = SSL_connect(ssl); if (ret > 0) { LM_INFO("New TLS connection to %s:%d established\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); c->proto_flags &= ~F_TLS_DO_CONNECT; LM_DBG("new TLS connection to %s:%d using %s %s %d\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port, SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl), SSL_get_cipher_bits(ssl, 0) ); LM_DBG("sending socket: %s:%d \n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port ); cert = SSL_get_peer_certificate(ssl); if (cert != 0) { tls_dump_cert_info("tls_connect: server TLS certificate", cert); if (SSL_get_verify_result(ssl) != X509_V_OK) { LM_WARN("TLS server certificate verification failed\n"); tls_dump_verification_failure(SSL_get_verify_result(ssl)); } X509_free(cert); } else { /* this should not happen, servers always present a cert */ LM_ERR("server did not present a TLS certificate\n"); } cert = SSL_get_certificate(ssl); if (cert != 0) { tls_dump_cert_info("tls_connect: local TLS client certificate", cert); } else { LM_INFO("local TLS client domain does not have a certificate\n"); } return 0; } else { err = SSL_get_error(ssl, ret); switch (err) { case SSL_ERROR_ZERO_RETURN: LM_INFO("New TLS connection to %s:%d failed cleanly\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); c->state = S_CONN_BAD; return -1; case SSL_ERROR_WANT_READ: if (poll_events) *poll_events = POLLIN; return 0; case SSL_ERROR_WANT_WRITE: if (poll_events) *poll_events = POLLOUT; return 0; case SSL_ERROR_SYSCALL: LM_ERR("SSL_ERROR_SYSCALL err=%s(%d)\n", strerror(errno), errno); default: LM_ERR("New TLS connection to %s:%d failed\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); LM_ERR("TLS error: %d (ret=%d) err=%s(%d)\n", err,ret,strerror(errno), errno); c->state = S_CONN_BAD; tls_print_errstack(); return -1; } } LM_BUG("bug\n"); return -1; }
void session_pickup(struct session *s, struct submit_status *ss) { void *ssl; s->s_flags &= ~F_WAITIMSG; if ((ss != NULL && ss->code == 421) || (s->s_dstatus & DS_TEMPFAILURE)) { stat_increment("smtp.tempfail", 1); session_respond(s, "421 Service temporarily unavailable"); session_enter_state(s, S_QUIT); io_reload(&s->s_io); return; } switch (s->s_state) { case S_CONNECTED: session_enter_state(s, S_INIT); s->s_msg.session_id = s->s_id; s->s_msg.ss = s->s_ss; session_imsg(s, PROC_MFA, IMSG_MFA_CONNECT, 0, 0, -1, &s->s_msg, sizeof(s->s_msg)); break; case S_INIT: if (ss->code != 250) { session_destroy(s, "rejected by filter"); return; } if (s->s_l->flags & F_SMTPS) { ssl = ssl_smtp_init(s->s_l->ssl_ctx); io_set_read(&s->s_io); io_start_tls(&s->s_io, ssl); return; } session_respond(s, SMTPD_BANNER, env->sc_hostname); session_enter_state(s, S_GREETED); break; case S_AUTH_FINALIZE: if (s->s_flags & F_AUTHENTICATED) session_respond(s, "235 Authentication succeeded"); else session_respond(s, "535 Authentication failed"); session_enter_state(s, S_HELO); break; case S_RSET: session_respond(s, "250 2.0.0 Reset state"); session_enter_state(s, S_HELO); break; case S_HELO: if (ss->code != 250) { session_enter_state(s, S_GREETED); session_respond(s, "%d Helo rejected", ss->code); break; } session_respond(s, "250%c%s Hello %s [%s], pleased to meet you", (s->s_flags & F_EHLO) ? '-' : ' ', env->sc_hostname, s->s_msg.helo, ss_to_text(&s->s_ss)); if (s->s_flags & F_EHLO) { /* unconditionnal extensions go first */ session_respond(s, "250-8BITMIME"); session_respond(s, "250-ENHANCEDSTATUSCODES"); /* XXX - we also want to support reading SIZE from MAIL parameters */ session_respond(s, "250-SIZE %zu", env->sc_maxsize); if (ADVERTISE_TLS(s)) session_respond(s, "250-STARTTLS"); if (ADVERTISE_AUTH(s)) session_respond(s, "250-AUTH PLAIN LOGIN"); session_respond(s, "250 HELP"); } break; case S_MAIL_MFA: if (ss->code != 250) { session_enter_state(s, S_HELO); session_respond(s, "%d Sender rejected", ss->code); break; } session_enter_state(s, S_MAIL_QUEUE); s->s_msg.sender = ss->u.maddr; session_imsg(s, PROC_QUEUE, IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1, &s->s_msg, sizeof(s->s_msg)); break; case S_MAIL_QUEUE: session_enter_state(s, S_MAIL); session_respond(s, "%d 2.1.0 Sender ok", ss->code); break; case S_RCPT_MFA: /* recipient was not accepted */ if (ss->code != 250) { /* We do not have a valid recipient, downgrade state */ if (s->rcptcount == 0) session_enter_state(s, S_MAIL); else session_enter_state(s, S_RCPT); session_respond(s, "%d 5.0.0 Recipient rejected: %s@%s", ss->code, s->s_msg.rcpt.user, s->s_msg.rcpt.domain); break; } session_enter_state(s, S_RCPT); s->rcptcount++; s->s_msg.dest = ss->u.maddr; session_respond(s, "%d 2.0.0 Recipient ok", ss->code); break; case S_DATA_QUEUE: session_enter_state(s, S_DATACONTENT); session_respond(s, "354 Enter mail, end with \".\" on a line by" " itself"); fprintf(s->datafp, "Received: from %s (%s [%s])\n", s->s_msg.helo, s->s_hostname, ss_to_text(&s->s_ss)); fprintf(s->datafp, "\tby %s (OpenSMTPD) with %sSMTP id %08x", env->sc_hostname, s->s_flags & F_EHLO ? "E" : "", evpid_to_msgid(s->s_msg.id)); if (s->s_flags & F_SECURE) { fprintf(s->datafp, "\n\t(version=%s cipher=%s bits=%d)", SSL_get_cipher_version(s->s_io.ssl), SSL_get_cipher_name(s->s_io.ssl), SSL_get_cipher_bits(s->s_io.ssl, NULL)); } if (s->rcptcount == 1) fprintf(s->datafp, "\n\tfor <%s@%s>; ", s->s_msg.rcpt.user, s->s_msg.rcpt.domain); else fprintf(s->datafp, ";\n\t"); fprintf(s->datafp, "%s\n", time_to_text(time(NULL))); break; case S_DATACONTENT: if (ss->code != 250) s->s_dstatus |= DS_PERMFAILURE; session_read_data(s, ss->u.dataline); break; case S_DONE: session_respond(s, "250 2.0.0 %08x Message accepted for delivery", evpid_to_msgid(s->s_msg.id)); log_info("%08x: from=<%s%s%s>, size=%ld, nrcpts=%zu, proto=%s, " "relay=%s [%s]", evpid_to_msgid(s->s_msg.id), s->s_msg.sender.user, s->s_msg.sender.user[0] == '\0' ? "" : "@", s->s_msg.sender.domain, s->s_datalen, s->rcptcount, s->s_flags & F_EHLO ? "ESMTP" : "SMTP", s->s_hostname, ss_to_text(&s->s_ss)); session_enter_state(s, S_HELO); s->s_msg.id = 0; bzero(&s->s_nresp, sizeof(s->s_nresp)); break; default: fatal("session_pickup: unknown state"); } io_reload(&s->s_io); }
void http_got_header(struct connection *c, struct read_buffer *rb) { int cf; int state = c->state != S_PROC ? S_GETH : S_PROC; unsigned char *head; unsigned char *cookie, *ch; int a, h, version; unsigned char *d; struct cache_entry *e; struct http_connection_info *info; unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url); set_timeout(c); info = c->info; if (rb->close == 2) { unsigned char *h; if (!c->tries && (h = get_host_name(host))) { if (info->bl_flags & BL_NO_CHARSET) { del_blacklist_entry(h, BL_NO_CHARSET); } else { add_blacklist_entry(h, BL_NO_CHARSET); c->tries = -1; } mem_free(h); } setcstate(c, S_CANT_READ); retry_connection(c); return; } rb->close = 0; again: if ((a = get_header(rb)) == -1) { setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if (!a) { read_from_socket(c, c->sock1, rb, http_got_header); setcstate(c, state); return; } if (a != -2) { head = mem_alloc(a + 1); memcpy(head, rb->data, a); head[a] = 0; kill_buffer_data(rb, a); } else { head = stracpy("HTTP/0.9 200 OK\r\nContent-Type: text/html\r\n\r\n"); } if (get_http_code(head, &h, &version) || h == 101) { mem_free(head); setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if (check_http_server_bugs(host, c->info, head) && is_connection_restartable(c)) { mem_free(head); setcstate(c, S_RESTART); retry_connection(c); return; } ch = head; while ((cookie = parse_http_header(ch, "Set-Cookie", &ch))) { unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url); set_cookie(NULL, host, cookie); mem_free(cookie); } if (h == 100) { mem_free(head); state = S_PROC; goto again; } if (h < 200) { mem_free(head); setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if (h == 204) { mem_free(head); setcstate(c, S_HTTP_204); http_end_request(c, 0); return; } if (h == 304) { mem_free(head); setcstate(c, S_OK); http_end_request(c, 1); return; } if ((h == 500 || h == 502 || h == 503 || h == 504) && http_bugs.retry_internal_errors && is_connection_restartable(c)) { /* !!! FIXME: wait some time ... */ mem_free(head); setcstate(c, S_RESTART); retry_connection(c); return; } if (!c->cache && get_cache_entry(c->url, &c->cache)) { mem_free(head); setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } e = c->cache; e->http_code = h; if (e->head) mem_free(e->head); e->head = head; if ((d = parse_http_header(head, "Expires", NULL))) { time_t t = parse_http_date(d); if (t && e->expire_time != 1) e->expire_time = t; mem_free(d); } if ((d = parse_http_header(head, "Pragma", NULL))) { if (!casecmp(d, "no-cache", 8)) e->expire_time = 1; mem_free(d); } if ((d = parse_http_header(head, "Cache-Control", NULL))) { char *f = d; while (1) { while (*f && (*f == ' ' || *f == ',')) f++; if (!*f) break; if (!casecmp(f, "no-cache", 8) || !casecmp(f, "must-revalidate", 15)) { e->expire_time = 1; } if (!casecmp(f, "max-age=", 8)) { if (e->expire_time != 1) e->expire_time = time(NULL) + atoi(f + 8); } while (*f && *f != ',') f++; } mem_free(d); } #ifdef HAVE_SSL if (c->ssl) { int l = 0; if (e->ssl_info) mem_free(e->ssl_info); e->ssl_info = init_str(); add_num_to_str(&e->ssl_info, &l, SSL_get_cipher_bits(c->ssl, NULL)); add_to_str(&e->ssl_info, &l, "-bit "); add_to_str(&e->ssl_info, &l, SSL_get_cipher_version(c->ssl)); add_to_str(&e->ssl_info, &l, " "); add_to_str(&e->ssl_info, &l, (unsigned char *)SSL_get_cipher_name(c->ssl)); } #endif if (e->redirect) mem_free(e->redirect), e->redirect = NULL; if (h == 301 || h == 302 || h == 303 || h == 307) { if ((h == 302 || h == 307) && !e->expire_time) e->expire_time = 1; if ((d = parse_http_header(e->head, "Location", NULL))) { unsigned char *user, *ins; unsigned char *newuser, *newpassword; if (!parse_url(d, NULL, &user, NULL, NULL, NULL, &ins, NULL, NULL, NULL, NULL, NULL, NULL) && !user && ins && (newuser = get_user_name(host))) { if (*newuser) { int ins_off = ins - d; newpassword = get_pass(host); if (!newpassword) newpassword = stracpy(""); add_to_strn(&newuser, ":"); add_to_strn(&newuser, newpassword); add_to_strn(&newuser, "@"); extend_str(&d, strlen(newuser)); ins = d + ins_off; memmove(ins + strlen(newuser), ins, strlen(ins) + 1); memcpy(ins, newuser, strlen(newuser)); mem_free(newpassword); } mem_free(newuser); } if (e->redirect) mem_free(e->redirect); e->redirect = d; e->redirect_get = h == 303; } } if (!e->expire_time && strchr(c->url, POST_CHAR)) e->expire_time = 1; info->close = 0; info->length = -1; info->version = version; if ((d = parse_http_header(e->head, "Connection", NULL)) || (d = parse_http_header(e->head, "Proxy-Connection", NULL))) { if (!strcasecmp(d, "close")) info->close = 1; mem_free(d); } else if (version < 11) info->close = 1; cf = c->from; c->from = 0; if ((d = parse_http_header(e->head, "Content-Range", NULL))) { if (strlen(d) > 6) { d[5] = 0; if (!(strcasecmp(d, "bytes")) && d[6] >= '0' && d[6] <= '9') { #if defined(HAVE_STRTOLL) long long f = strtoll(d + 6, NULL, 10); #elif defined(HAVE_STRTOQ) longlong f = strtoq(d + 6, NULL, 10); #else long f = strtol(d + 6, NULL, 10); if (f == MAXLONG) f = -1; #endif if (f >= 0 && (off_t)f >= 0 && (off_t)f == f) c->from = f; } } mem_free(d); } if (cf && !c->from && !c->unrestartable) c->unrestartable = 1; if (c->from > cf || c->from < 0) { setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if ((d = parse_http_header(e->head, "Content-Length", NULL))) { unsigned char *ep; #if defined(HAVE_STRTOLL) long long l = strtoll(d, (char **)(void *)&ep, 10); #elif defined(HAVE_STRTOQ) longlong l = strtoq(d, (char **)(void *)&ep, 10); #else long l = strtol(d, (char **)(void *)&ep, 10); if (l == MAXLONG) l = -1; #endif if (!*ep && l >= 0 && (off_t)l >= 0 && (off_t)l == l) { if (!info->close || version >= 11) info->length = l; if (c->from + l >= 0) c->est_length = c->from + l; } mem_free(d); } if ((d = parse_http_header(e->head, "Accept-Ranges", NULL))) { if (!strcasecmp(d, "none") && !c->unrestartable) c->unrestartable = 1; mem_free(d); } else { if (!c->unrestartable && !c->from) c->unrestartable = 1; } if (info->bl_flags & BL_NO_RANGE && !c->unrestartable) c->unrestartable = 1; if ((d = parse_http_header(e->head, "Transfer-Encoding", NULL))) { if (!strcasecmp(d, "chunked")) { info->length = -2; info->chunk_remaining = -1; } mem_free(d); } if (!info->close && info->length == -1) info->close = 1; if ((d = parse_http_header(e->head, "Last-Modified", NULL))) { if (e->last_modified && strcasecmp(e->last_modified, d)) { delete_entry_content(e); if (c->from) { c->from = 0; mem_free(d); setcstate(c, S_MODIFIED); retry_connection(c); return; } } if (!e->last_modified) e->last_modified = d; else mem_free(d); } if (!e->last_modified && (d = parse_http_header(e->head, "Date", NULL))) e->last_modified = d; if (info->length == -1 || (version < 11 && info->close)) rb->close = 1; read_http_data(c, rb); }