int lws_ssl_client_bio_create(struct lws *wsi) { #if defined(LWS_USE_POLARSSL) return 0; #else #if defined(LWS_USE_MBEDTLS) #else struct lws_context *context = wsi->context; const char *hostname = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST); X509_VERIFY_PARAM *param; (void)hostname; (void)param; wsi->ssl = SSL_new(wsi->vhost->ssl_client_ctx); #if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host if (!(wsi->use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) { param = SSL_get0_param(wsi->ssl); /* Enable automatic hostname checks */ X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); X509_VERIFY_PARAM_set1_host(param, hostname, 0); /* Configure a non-zero callback if desired */ SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, 0); } #endif #ifndef USE_WOLFSSL SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #endif /* * use server name indication (SNI), if supported, * when establishing connection */ #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL #ifdef CYASSL_SNI_HOST_NAME CyaSSL_UseSNI(wsi->ssl, CYASSL_SNI_HOST_NAME, hostname, strlen(hostname)); #endif #else #ifdef WOLFSSL_SNI_HOST_NAME wolfSSL_UseSNI(wsi->ssl, WOLFSSL_SNI_HOST_NAME, hostname, strlen(hostname)); #endif #endif #else #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME SSL_set_tlsext_host_name(wsi->ssl, hostname); #endif #endif #ifdef USE_WOLFSSL /* * wolfSSL/CyaSSL does certificate verification differently * from OpenSSL. * If we should ignore the certificate, we need to set * this before SSL_new and SSL_connect is called. * Otherwise the connect will simply fail with error code -155 */ #ifdef USE_OLD_CYASSL if (wsi->use_ssl == 2) CyaSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL); #else if (wsi->use_ssl == 2) wolfSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL); #endif #endif /* USE_WOLFSSL */ wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE); SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio); #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL CyaSSL_set_using_nonblock(wsi->ssl, 1); #else wolfSSL_set_using_nonblock(wsi->ssl, 1); #endif #else BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */ #endif SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, context); return 0; #endif #endif }
/* Upgrade a standard socket to use SSL/TLS. Used by both clients and servers to upgrade a socket for SSL. If a client, this may block while connecting. */ static int upgradeOss(MprSocket *sp, MprSsl *ssl, cchar *requiredPeerName) { OpenSocket *osp; OpenConfig *cfg; int rc; assert(sp); if (ssl == 0) { ssl = mprCreateSsl(sp->flags & MPR_SOCKET_SERVER); } if ((osp = (OpenSocket*) mprAllocObj(OpenSocket, manageOpenSocket)) == 0) { return MPR_ERR_MEMORY; } osp->sock = sp; sp->sslSocket = osp; sp->ssl = ssl; lock(ssl); if (configOss(ssl, sp->flags, &sp->errorMsg) < 0) { unlock(ssl); return MPR_ERR_CANT_INITIALIZE; } unlock(ssl); /* Create and configure the SSL struct */ cfg = osp->cfg = sp->ssl->config; if ((osp->handle = (SSL*) SSL_new(cfg->ctx)) == 0) { return MPR_ERR_BAD_STATE; } SSL_set_app_data(osp->handle, (void*) osp); /* Create a socket bio. We don't use the BIO except as storage for the fd */ if ((osp->bio = BIO_new_socket((int) sp->fd, BIO_NOCLOSE)) == 0) { return MPR_ERR_BAD_STATE; } SSL_set_bio(osp->handle, osp->bio, osp->bio); if (sp->flags & MPR_SOCKET_SERVER) { SSL_set_accept_state(osp->handle); } else { if (requiredPeerName) { osp->requiredPeerName = sclone(requiredPeerName); #if OPENSSL_VERSION_NUMBER >= 0x10002000L X509_VERIFY_PARAM *param = param = SSL_get0_param(osp->handle); X509_VERIFY_PARAM_set_hostflags(param, 0); X509_VERIFY_PARAM_set1_host(param, requiredPeerName, 0); #endif } /* Block while connecting */ mprSetSocketBlockingMode(sp, 1); sp->errorMsg = 0; if ((rc = SSL_connect(osp->handle)) < 1) { if (sp->errorMsg) { mprLog("info mpr ssl openssl", 4, "Connect failed: %s", sp->errorMsg); } else { mprLog("info mpr ssl openssl", 4, "Connect failed: error %s", getOssError(sp)); } return MPR_ERR_CANT_CONNECT; } if (rc > 0 && checkPeerCertName(sp) < 0) { return MPR_ERR_CANT_CONNECT; } setSecured(sp); mprSetSocketBlockingMode(sp, 0); } #if defined(ME_MPR_SSL_RENEGOTIATE) && !ME_MPR_SSL_RENEGOTIATE /* Disable renegotiation after the initial handshake if renegotiate is explicitly set to false (CVE-2009-3555). Note: this really is a bogus CVE as disabling renegotiation is not required nor does it enhance security if used with up-to-date (patched) SSL stacks. */ if (osp->handle->s3) { osp->handle->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; } #endif return 0; }
ResponseCode OpenSSLConnection::ConnectInternal() { ResponseCode networkResponse = ResponseCode::SUCCESS; X509_VERIFY_PARAM *param = nullptr; server_tcp_socket_fd_ = socket(AF_INET, SOCK_STREAM, 0); if (-1 == server_tcp_socket_fd_) { return ResponseCode::NETWORK_TCP_SETUP_ERROR; } AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Root CA : %s", root_ca_location_.c_str()); if (!SSL_CTX_load_verify_locations(p_ssl_context_, root_ca_location_.c_str(), NULL)) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Root CA Loading error"); return ResponseCode::NETWORK_SSL_ROOT_CRT_PARSE_ERROR; } if (0 < device_cert_location_.length() && 0 < device_private_key_location_.length()) { AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Device crt : %s", device_cert_location_.c_str()); if (!SSL_CTX_use_certificate_file(p_ssl_context_, device_cert_location_.c_str(), SSL_FILETYPE_PEM)) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Device Certificate Loading error"); return ResponseCode::NETWORK_SSL_DEVICE_CRT_PARSE_ERROR; } AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Device privkey : %s", device_private_key_location_.c_str()); if (1 != SSL_CTX_use_PrivateKey_file(p_ssl_context_, device_private_key_location_.c_str(), SSL_FILETYPE_PEM)) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Device Private Key Loading error"); return ResponseCode::NETWORK_SSL_KEY_PARSE_ERROR; } } p_ssl_handle_ = SSL_new(p_ssl_context_); // Requires OpenSSL v1.0.2 and above if (server_verification_flag_) { param = SSL_get0_param(p_ssl_handle_); // Enable automatic hostname checks X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); // Check if it is an IPv4 or an IPv6 address to enable ip checking // Enable host name check otherwise char dst[INET6_ADDRSTRLEN]; if (inet_pton(AF_INET, endpoint_.c_str(), (void *) dst) || inet_pton(AF_INET6, endpoint_.c_str(), (void *) dst)) { X509_VERIFY_PARAM_set1_ip_asc(param, endpoint_.c_str()); } else { X509_VERIFY_PARAM_set1_host(param, endpoint_.c_str(), 0); } } // Configure a non-zero callback if desired SSL_set_verify(p_ssl_handle_, SSL_VERIFY_PEER, nullptr); networkResponse = ConnectTCPSocket(); if (ResponseCode::SUCCESS != networkResponse) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, "TCP Connection error"); return networkResponse; } SSL_set_fd(p_ssl_handle_, server_tcp_socket_fd_); networkResponse = SetSocketToNonBlocking(); if (ResponseCode::SUCCESS != networkResponse) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Unable to set the socket to Non-Blocking"); return networkResponse; } networkResponse = AttemptConnect(); if (X509_V_OK != SSL_get_verify_result(p_ssl_handle_)) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Server Certificate Verification failed."); networkResponse = ResponseCode::NETWORK_SSL_CONNECT_ERROR; } else { // ensure you have a valid certificate returned, otherwise no certificate exchange happened if (nullptr == SSL_get_peer_certificate(p_ssl_handle_)) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " No certificate exchange happened"); networkResponse = ResponseCode::NETWORK_SSL_CONNECT_ERROR; } } if (ResponseCode::SUCCESS == networkResponse) { is_connected_ = true; } return networkResponse; }
tls_t *tls_new(xmpp_conn_t *conn) { tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls)); int mode; if (tls) { int ret; memset(tls, 0, sizeof(*tls)); tls->ctx = conn->ctx; tls->sock = conn->sock; tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); if (tls->ssl_ctx == NULL) goto err; /* Enable bug workarounds. */ SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_ALL); /* Disable insecure SSL/TLS versions. */ SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv2); /* DROWN */ SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */ SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */ SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL); SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); SSL_CTX_set_default_verify_paths(tls->ssl_ctx); tls->ssl = SSL_new(tls->ssl_ctx); if (tls->ssl == NULL) goto err_free_ctx; /* Trust server's certificate when user sets the flag explicitly. */ mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER; SSL_set_verify(tls->ssl, mode, 0); #if OPENSSL_VERSION_NUMBER >= 0x10002000L /* Hostname verification is supported in OpenSSL 1.0.2 and newer. */ X509_VERIFY_PARAM *param = SSL_get0_param(tls->ssl); /* * Allow only complete wildcards. RFC 6125 discourages wildcard usage * completely, and lists internationalized domain names as a reason * against partial wildcards. * See https://tools.ietf.org/html/rfc6125#section-7.2 for more information. */ X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); X509_VERIFY_PARAM_set1_host(param, conn->domain, 0); #endif ret = SSL_set_fd(tls->ssl, conn->sock); if (ret <= 0) goto err_free_ssl; } return tls; err_free_ssl: SSL_free(tls->ssl); err_free_ctx: SSL_CTX_free(tls->ssl_ctx); err: xmpp_free(conn->ctx, tls); _tls_log_error(conn->ctx); return NULL; }
int lws_ssl_client_bio_create(struct lws *wsi) { X509_VERIFY_PARAM *param; char hostname[128], *p; const char *alpn_comma = wsi->context->tls.alpn_default; struct alpn_ctx protos; if (lws_hdr_copy(wsi, hostname, sizeof(hostname), _WSI_TOKEN_CLIENT_HOST) <= 0) { lwsl_err("%s: Unable to get hostname\n", __func__); return -1; } /* * remove any :port part on the hostname... necessary for network * connection but typical certificates do not contain it */ p = hostname; while (*p) { if (*p == ':') { *p = '\0'; break; } p++; } wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_client_ctx); if (!wsi->tls.ssl) return -1; if (wsi->vhost->tls.ssl_info_event_mask) SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback); if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) { param = SSL_get0_param(wsi->tls.ssl); /* Enable automatic hostname checks */ // X509_VERIFY_PARAM_set_hostflags(param, // X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); X509_VERIFY_PARAM_set1_host(param, hostname, 0); } if (wsi->vhost->tls.alpn) alpn_comma = wsi->vhost->tls.alpn; if (lws_hdr_copy(wsi, hostname, sizeof(hostname), _WSI_TOKEN_CLIENT_ALPN) > 0) alpn_comma = hostname; lwsl_info("%s: %p: client conn sending ALPN list '%s'\n", __func__, wsi, alpn_comma); protos.len = lws_alpn_comma_to_openssl(alpn_comma, protos.data, sizeof(protos.data) - 1); /* with mbedtls, protos is not pointed to after exit from this call */ SSL_set_alpn_select_cb(wsi->tls.ssl, &protos); /* * use server name indication (SNI), if supported, * when establishing connection */ SSL_set_verify(wsi->tls.ssl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback); SSL_set_fd(wsi->tls.ssl, wsi->desc.sockfd); return 0; }
Result<SslFd> SslFd::init(SocketFd fd, CSlice host, CSlice cert_file, VerifyPeer verify_peer) { #if TD_WINDOWS return Status::Error("TODO"); #else static bool init_openssl = [] { #if OPENSSL_VERSION_NUMBER >= 0x10100000L return OPENSSL_init_ssl(0, nullptr) != 0; #else OpenSSL_add_all_algorithms(); SSL_load_error_strings(); return OpenSSL_add_ssl_algorithms() != 0; #endif }(); CHECK(init_openssl); openssl_clear_errors("Before SslFd::init"); CHECK(!fd.empty()); auto ssl_method = #if OPENSSL_VERSION_NUMBER >= 0x10100000L TLS_client_method(); #else SSLv23_client_method(); #endif if (ssl_method == nullptr) { return create_openssl_error(-6, "Failed to create an SSL client method"); } auto ssl_ctx = SSL_CTX_new(ssl_method); if (ssl_ctx == nullptr) { return create_openssl_error(-7, "Failed to create an SSL context"); } auto ssl_ctx_guard = ScopeExit() + [&]() { SSL_CTX_free(ssl_ctx); }; long options = 0; #ifdef SSL_OP_NO_SSLv2 options |= SSL_OP_NO_SSLv2; #endif #ifdef SSL_OP_NO_SSLv3 options |= SSL_OP_NO_SSLv3; #endif SSL_CTX_set_options(ssl_ctx, options); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE); if (cert_file.empty()) { SSL_CTX_set_default_verify_paths(ssl_ctx); } else { if (SSL_CTX_load_verify_locations(ssl_ctx, cert_file.c_str(), nullptr) == 0) { return create_openssl_error(-8, "Failed to set custom cert file"); } } if (VERIFY_PEER && verify_peer == VerifyPeer::On) { SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_callback); if (VERIFY_DEPTH != -1) { SSL_CTX_set_verify_depth(ssl_ctx, VERIFY_DEPTH); } } else { SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, nullptr); } // TODO(now): cipher list string cipher_list; if (SSL_CTX_set_cipher_list(ssl_ctx, cipher_list.empty() ? "DEFAULT" : cipher_list.c_str()) == 0) { return create_openssl_error(-9, PSLICE("Failed to set cipher list \"%s\"", cipher_list.c_str())); } auto ssl_handle = SSL_new(ssl_ctx); if (ssl_handle == nullptr) { return create_openssl_error(-13, "Failed to create an SSL handle"); } auto ssl_handle_guard = ScopeExit() + [&]() { do_ssl_shutdown(ssl_handle); SSL_free(ssl_handle); }; #if OPENSSL_VERSION_NUMBER >= 0x10002000L X509_VERIFY_PARAM *param = SSL_get0_param(ssl_handle); /* Enable automatic hostname checks */ // TODO: X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS X509_VERIFY_PARAM_set_hostflags(param, 0); X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0); #else #warning DANGEROUS! HTTPS HOST WILL NOT BE CHECKED. INSTALL OPENSSL >= 1.0.2 OR IMPLEMENT HTTPS HOST CHECK MANUALLY #endif if (!SSL_set_fd(ssl_handle, fd.get_fd().get_native_fd())) { return create_openssl_error(-14, "Failed to set fd"); } #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) auto host_str = host.str(); SSL_set_tlsext_host_name(ssl_handle, MutableCSlice(host_str).begin()); #endif SSL_set_connect_state(ssl_handle); ssl_ctx_guard.dismiss(); ssl_handle_guard.dismiss(); return SslFd(std::move(fd), ssl_handle, ssl_ctx); #endif }