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