aboutsummaryrefslogtreecommitdiffstats
path: root/v3/contrib/libwebsock/src/openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'v3/contrib/libwebsock/src/openssl.c')
-rw-r--r--v3/contrib/libwebsock/src/openssl.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/v3/contrib/libwebsock/src/openssl.c b/v3/contrib/libwebsock/src/openssl.c
new file mode 100644
index 0000000..6f1c482
--- /dev/null
+++ b/v3/contrib/libwebsock/src/openssl.c
@@ -0,0 +1,174 @@
+/*
+ * This file is part of libwebsock
+ *
+ * Copyright (C) 2012 Payden Sutherland
+ *
+ * libwebsock is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3 of the License.
+ *
+ * libwebsock 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libwebsock; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <unistd.h>
+
+#include "websock.h"
+
+void
+libwebsock_handle_accept_ssl(evutil_socket_t listener, short event, void *arg)
+{
+ libwebsock_ssl_event_data *evdata = arg;
+ libwebsock_context *ctx = evdata->ctx;
+ SSL_CTX *ssl_ctx = evdata->ssl_ctx;
+ libwebsock_client_state *client_state;
+ struct bufferevent *bev;
+ struct sockaddr_storage ss;
+ socklen_t slen = sizeof(ss);
+ int fd = accept(listener, (struct sockaddr *) &ss, &slen);
+ if (fd < 0) {
+ fprintf(stderr, "Error accepting new connection.\n");
+ } else {
+ client_state = (libwebsock_client_state *) malloc(sizeof(libwebsock_client_state));
+ if (!client_state) {
+ fprintf(stderr, "Unable to allocate memory for new connection state structure.\n");
+ close(fd);
+ return;
+ }
+ memset(client_state, 0, sizeof(libwebsock_client_state));
+ client_state->sockfd = fd;
+ client_state->flags |= STATE_CONNECTING | STATE_IS_SSL;
+ client_state->control_callback = ctx->control_callback;
+ client_state->onopen = ctx->onopen;
+ client_state->onmessage = ctx->onmessage;
+ client_state->onclose = ctx->onclose;
+ client_state->sa = (struct sockaddr_storage *) malloc(sizeof(struct sockaddr_storage));
+ if (!client_state->sa) {
+ fprintf(stderr, "Unable to allocate memory for sockaddr_storage.\n");
+ free(client_state);
+ close(fd);
+ return;
+ }
+ memcpy(client_state->sa, &ss, sizeof(struct sockaddr_storage));
+ client_state->ssl = SSL_new(ssl_ctx);
+ SSL_set_fd(client_state->ssl, fd);
+ if (SSL_accept(client_state->ssl) <= 0) {
+ fprintf(stderr, "error during ssl handshake.\n");
+ }
+ evutil_make_socket_nonblocking(fd);
+ bev = bufferevent_openssl_socket_new(ctx->base, -1, client_state->ssl, BUFFEREVENT_SSL_OPEN, BEV_OPT_CLOSE_ON_FREE);
+ client_state->bev = bev;
+ bufferevent_setcb(bev, libwebsock_handshake, NULL, libwebsock_do_event, (void *) client_state);
+ bufferevent_setwatermark(bev, EV_READ, 0, 16384);
+ bufferevent_enable(bev, EV_READ | EV_WRITE);
+ }
+}
+
+
+void
+libwebsock_bind_ssl(libwebsock_context *ctx, char *listen_host, char *port, char *keyfile, char *certfile)
+{
+ libwebsock_bind_ssl_real(ctx, listen_host, port, keyfile, certfile, NULL);
+}
+
+
+void
+libwebsock_bind_ssl_real(libwebsock_context *ctx, char *listen_host, char *port, char *keyfile, char *certfile,
+ char *chainfile)
+{
+ struct addrinfo hints, *servinfo, *p;
+ struct event *listener_event;
+ libwebsock_ssl_event_data *evdata;
+ int sockfd, yes = 1;
+ SSL_CTX *ssl_ctx;
+
+ evdata = (libwebsock_ssl_event_data *) malloc(sizeof(libwebsock_ssl_event_data));
+ if (!evdata) {
+ fprintf(stderr, "Unable to allocate memory for ssl_event_data.\n");
+ exit(1);
+ }
+ memset(evdata, 0, sizeof(libwebsock_ssl_event_data));
+
+ if (!ctx->ssl_init) {
+ SSL_library_init();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+ ctx->ssl_init = 1;
+ }
+
+ ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+ if (!ssl_ctx) {
+ ERR_print_errors_fp(stderr);
+ exit(1);
+ }
+ if (chainfile != NULL) {
+ if (SSL_CTX_load_verify_locations(ssl_ctx, chainfile, NULL) <= 0) {
+ ERR_print_errors_fp(stderr);
+ exit(1);
+ }
+ }
+ if (SSL_CTX_use_certificate_file(ssl_ctx, certfile, SSL_FILETYPE_PEM) <= 0) {
+ ERR_print_errors_fp(stderr);
+ exit(1);
+ }
+ if (SSL_CTX_use_PrivateKey_file(ssl_ctx, keyfile, SSL_FILETYPE_PEM) <= 0) {
+ ERR_print_errors_fp(stderr);
+ exit(1);
+ }
+
+ if (!SSL_CTX_check_private_key(ssl_ctx)) {
+ fprintf(stderr, "Private key does not match the certificate public key.\n");
+ exit(1);
+ }
+ memset(&hints, 0, sizeof(struct addrinfo));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ if ((getaddrinfo(listen_host, port, &hints, &servinfo)) != 0) {
+ fprintf(stderr, "getaddrinfo failed during libwebsock_bind.\n");
+ free(ctx);
+ exit(-1);
+ }
+ for (p = servinfo; p != NULL; p = p->ai_next) {
+ if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
+ perror("socket");
+ continue;
+ }
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
+ perror("setsockopt");
+ free(ctx);
+ exit(-1);
+ }
+ if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
+ perror("bind");
+ close(sockfd);
+ continue;
+ }
+ break;
+ }
+
+ if (p == NULL) {
+ fprintf(stderr, "Failed to bind to address and port. Exiting.\n");
+ free(ctx);
+ exit(-1);
+ }
+
+ freeaddrinfo(servinfo);
+
+ if (listen(sockfd, LISTEN_BACKLOG) == -1) {
+ perror("listen");
+ exit(-1);
+ }
+ evdata->ssl_ctx = ssl_ctx;
+ evdata->ctx = ctx;
+
+ listener_event = event_new(ctx->base, sockfd, EV_READ | EV_PERSIST, libwebsock_handle_accept_ssl, (void *) evdata);
+ event_add(listener_event, NULL);
+}