add callback for OpenSSL client cert verification action
Signed-off-by: Andy Green <andy@warmcat.com>
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 40b9a20..782c1ab 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -709,6 +709,9 @@
wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE);
SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
+ SSL_set_ex_data(wsi->ssl,
+ this->openssl_websocket_private_data_index, this);
+
if (SSL_connect(wsi->ssl) <= 0) {
fprintf(stderr, "SSL connect error %s\n",
ERR_error_string(ERR_get_error(), ssl_err_buf));
@@ -1390,6 +1393,39 @@
{
}
+#ifdef LWS_OPENSSL_SUPPORT
+static int
+OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+
+ SSL *ssl;
+ int n;
+// struct libwebsocket_context *this;
+
+ ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+
+ /*
+ * !!! can't get this->openssl_websocket_private_data_index
+ * can't store as a static either
+ */
+// this = SSL_get_ex_data(ssl, this->openssl_websocket_private_data_index);
+
+ n = this->protocols[0].callback(NULL, NULL,
+ LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
+ x509_ctx, ssl, preverify_ok);
+
+ /* convert return code from 0 = OK to 1 = OK */
+
+ if (!n)
+ n = 1;
+ else
+ n = 0;
+
+ return n;
+}
+#endif
+
/**
* libwebsocket_create_context() - Create the websocket handler
@@ -1553,6 +1589,9 @@
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
+ this->openssl_websocket_private_data_index =
+ SSL_get_ex_new_index(0, "libwebsockets", NULL, NULL, NULL);
+
/*
* Firefox insists on SSLv23 not SSLv3
* Konq disables SSLv2 by default now, SSLv23 works
@@ -1613,7 +1652,8 @@
/* absolutely require the client cert */
SSL_CTX_set_verify(this->ssl_ctx,
- SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
+ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ OpenSSL_verify_callback);
/*
* give user code a chance to load certs into the server
@@ -1625,7 +1665,6 @@
this->ssl_ctx, NULL, 0);
}
-
if (this->use_ssl) {
/* openssl init for server sockets */
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index d4a0b02..620c576 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -46,6 +46,7 @@
LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
+ LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
/* external poll() management support */
LWS_CALLBACK_ADD_POLL_FD,
@@ -217,6 +218,25 @@
* verify the validity of certificates returned by clients. @user
* is the server's OpenSSL SSL_CTX*
*
+ * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the
+ * libwebsockets context was created with the option
+ * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this
+ * callback is generated during OpenSSL verification of the cert
+ * sent from the client. It is sent to protocol[0] callback as
+ * no protocol has been negotiated on the connection yet.
+ * Notice that the libwebsockets context and wsi are both NULL
+ * during this callback. See
+ * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
+ * to understand more detail about the OpenSSL callback that
+ * generates this libwebsockets callback and the meanings of the
+ * arguments passed. In this callback, @user is the x509_ctx,
+ * @in is the ssl pointer and @len is preverify_ok
+ * Notice that this callback maintains libwebsocket return
+ * conventions, return 0 to mean the cert is OK or 1 to fail it.
+ * This also means that if you don't handle this callback then
+ * the default callback action of returning 0 allows the client
+ * certificates.
+ *
* The next four reasons are optional and only need taking care of if you
* will be integrating libwebsockets sockets into an external polling
* array.
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 0b4cc18..cafb479 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -181,6 +181,7 @@
int use_ssl;
SSL_CTX *ssl_ctx;
SSL_CTX *ssl_client_ctx;
+ int openssl_websocket_private_data_index;
#endif
struct libwebsocket_protocols *protocols;
int count_protocols;
diff --git a/libwebsockets-api-doc.html b/libwebsockets-api-doc.html
index ecb17ca..966df7d 100644
--- a/libwebsockets-api-doc.html
+++ b/libwebsockets-api-doc.html
@@ -583,12 +583,44 @@
</blockquote>
<h3>LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS</h3>
<blockquote>
-if configure for
+if configured for
including OpenSSL support, this callback allows your user code
to perform extra <b>SSL_CTX_load_verify_locations</b> or similar
calls to direct OpenSSL where to find certificates the client
can use to confirm the remote server identity. <tt><b>user</b></tt> is the
OpenSSL SSL_CTX*
+</blockquote>
+<h3>LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS</h3>
+<blockquote>
+if configured for
+including OpenSSL support, this callback allows your user code
+to load extra certifcates into the server which allow it to
+verify the validity of certificates returned by clients. <tt><b>user</b></tt>
+is the server's OpenSSL SSL_CTX*
+</blockquote>
+<h3>LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION</h3>
+<blockquote>
+if the
+libwebsockets context was created with the option
+LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this
+callback is generated during OpenSSL verification of the cert
+sent from the client. It is sent to protocol[0] callback as
+no protocol has been negotiated on the connection yet.
+Notice that the libwebsockets context and wsi are both NULL
+during this callback. See
+</blockquote>
+<h3>http</h3>
+<blockquote>
+//www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
+to understand more detail about the OpenSSL callback that
+generates this libwebsockets callback and the meanings of the
+arguments passed. In this callback, <tt><b>user</b></tt> is the x509_ctx,
+<tt><b>in</b></tt> is the ssl pointer and <tt><b>len</b></tt> is preverify_ok
+Notice that this callback maintains libwebsocket return
+conventions, return 0 to mean the cert is OK or 1 to fail it.
+This also means that if you don't handle this callback then
+the default callback action of returning 0 allows the client
+certificates.
<p>
The next four reasons are optional and only need taking care of if you
will be integrating libwebsockets sockets into an external polling