diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 40b9a20d..782c1abf 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -709,6 +709,9 @@ libwebsocket_service_fd(struct libwebsocket_context *this, 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 @@ static void sigpipe_handler(int x) { } +#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 @@ libwebsocket_create_context(int port, const char *interface, 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 @@ libwebsocket_create_context(int port, const char *interface, /* 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 @@ libwebsocket_create_context(int port, const char *interface, 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 d4a0b02c..620c5762 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -46,6 +46,7 @@ enum libwebsocket_callback_reasons { 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 @@ struct libwebsocket_context; * 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 0b4cc18d..cafb479c 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -181,6 +181,7 @@ struct libwebsocket_context { 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 ecb17ca7..966df7d0 100644 --- a/libwebsockets-api-doc.html +++ b/libwebsockets-api-doc.html @@ -583,12 +583,44 @@ to kill the connection.
-if configure for +if configured for including OpenSSL support, this callback allows your user code to perform extra SSL_CTX_load_verify_locations or similar calls to direct OpenSSL where to find certificates the client can use to confirm the remote server identity. user is the OpenSSL SSL_CTX* ++
+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. user +is the server's OpenSSL SSL_CTX* ++
+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 ++
+//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