summaryrefslogtreecommitdiff
path: root/thirdparty/libwebsockets/tls/mbedtls/mbedtls-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/libwebsockets/tls/mbedtls/mbedtls-client.c')
-rw-r--r--thirdparty/libwebsockets/tls/mbedtls/mbedtls-client.c240
1 files changed, 240 insertions, 0 deletions
diff --git a/thirdparty/libwebsockets/tls/mbedtls/mbedtls-client.c b/thirdparty/libwebsockets/tls/mbedtls/mbedtls-client.c
new file mode 100644
index 0000000000..a7864ab790
--- /dev/null
+++ b/thirdparty/libwebsockets/tls/mbedtls/mbedtls-client.c
@@ -0,0 +1,240 @@
+/*
+ * libwebsockets - mbedtls-specific client TLS code
+ *
+ * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation:
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include "core/private.h"
+
+static int
+OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+ return 0;
+}
+
+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;
+}
+
+int ERR_get_error(void)
+{
+ return 0;
+}
+
+enum lws_ssl_capable_status
+lws_tls_client_connect(struct lws *wsi)
+{
+ int m, n = SSL_connect(wsi->tls.ssl);
+ const unsigned char *prot;
+ unsigned int len;
+
+ if (n == 1) {
+ SSL_get0_alpn_selected(wsi->tls.ssl, &prot, &len);
+ lws_role_call_alpn_negotiated(wsi, (const char *)prot);
+ lwsl_info("client connect OK\n");
+ return LWS_SSL_CAPABLE_DONE;
+ }
+
+ m = SSL_get_error(wsi->tls.ssl, n);
+
+ if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl))
+ return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
+
+ if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl))
+ return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
+
+ if (!n) /* we don't know what he wants, but he says to retry */
+ return LWS_SSL_CAPABLE_MORE_SERVICE;
+
+ return LWS_SSL_CAPABLE_ERROR;
+}
+
+int
+lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len)
+{
+ int n;
+ X509 *peer = SSL_get_peer_certificate(wsi->tls.ssl);
+ struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+ char *sb = (char *)&pt->serv_buf[0];
+
+ if (!peer) {
+ lwsl_info("peer did not provide cert\n");
+
+ return -1;
+ }
+ lwsl_info("peer provided cert\n");
+
+ n = SSL_get_verify_result(wsi->tls.ssl);
+ lws_latency(wsi->context, wsi,
+ "SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0);
+
+ lwsl_debug("get_verify says %d\n", n);
+
+ if (n == X509_V_OK)
+ return 0;
+
+ if (n == X509_V_ERR_HOSTNAME_MISMATCH &&
+ (wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
+ lwsl_info("accepting certificate for invalid hostname\n");
+ return 0;
+ }
+
+ if (n == X509_V_ERR_INVALID_CA &&
+ (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED)) {
+ lwsl_info("accepting certificate from untrusted CA\n");
+ return 0;
+ }
+
+ if ((n == X509_V_ERR_CERT_NOT_YET_VALID ||
+ n == X509_V_ERR_CERT_HAS_EXPIRED) &&
+ (wsi->tls.use_ssl & LCCSCF_ALLOW_EXPIRED)) {
+ lwsl_info("accepting expired or not yet valid certificate\n");
+
+ return 0;
+ }
+ lws_snprintf(ebuf, ebuf_len,
+ "server's cert didn't look good, X509_V_ERR = %d: %s\n",
+ n, ERR_error_string(n, sb));
+ lwsl_info("%s\n", ebuf);
+ lws_ssl_elaborate_error();
+
+ return -1;
+}
+
+int
+lws_tls_client_create_vhost_context(struct lws_vhost *vh,
+ const struct lws_context_creation_info *info,
+ const char *cipher_list,
+ const char *ca_filepath,
+ const char *cert_filepath,
+ const char *private_key_filepath)
+{
+ X509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len);
+ SSL_METHOD *method = (SSL_METHOD *)TLS_client_method();
+ unsigned long error;
+ lws_filepos_t len;
+ uint8_t *buf;
+
+ if (!method) {
+ error = ERR_get_error();
+ lwsl_err("problem creating ssl method %lu: %s\n",
+ error, ERR_error_string(error,
+ (char *)vh->context->pt[0].serv_buf));
+ return 1;
+ }
+ /* create context */
+ vh->tls.ssl_client_ctx = SSL_CTX_new(method);
+ if (!vh->tls.ssl_client_ctx) {
+ error = ERR_get_error();
+ lwsl_err("problem creating ssl context %lu: %s\n",
+ error, ERR_error_string(error,
+ (char *)vh->context->pt[0].serv_buf));
+ return 1;
+ }
+
+ if (!ca_filepath)
+ return 0;
+
+ if (alloc_file(vh->context, ca_filepath, &buf, &len)) {
+ lwsl_err("Load CA cert file %s failed\n", ca_filepath);
+ return 1;
+ }
+
+ vh->tls.x509_client_CA = d2i_X509(NULL, buf, len);
+ free(buf);
+ if (!vh->tls.x509_client_CA) {
+ lwsl_err("client CA: x509 parse failed\n");
+ return 1;
+ }
+
+ if (!vh->tls.ssl_ctx)
+ SSL_CTX_add_client_CA(vh->tls.ssl_client_ctx, vh->tls.x509_client_CA);
+ else
+ SSL_CTX_add_client_CA(vh->tls.ssl_ctx, vh->tls.x509_client_CA);
+
+ lwsl_notice("client loaded CA for verification %s\n", ca_filepath);
+
+ return 0;
+}