Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrated SSL support. Modified echo example. #106

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ LIB_WS = libws.a
INCLUDE = include
CFLAGS += -Wall -Wextra -O2
CFLAGS += -I $(INCLUDE) -std=c99 -pedantic
LDLIBS = $(LIB_WS) -pthread
#LDLIBS = $(LIB_WS) -pthread -lssl -lcrypto
LDLIBS = $(LIB_WS) -pthread -lssl -lcrypto
ARFLAGS = cru
MCSS_DIR ?= /usr/bin/
MANPAGES = doc/man/man3
Expand Down
19 changes: 19 additions & 0 deletions certs/localhost.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDDzCCAfegAwIBAgIUOBsdLqSiHICAenBcLw1Gd4GildkwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MTExNTA1MDg1OFoXDTI0MTIx
NTA1MDg1OFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAinMabl7EyoJLQkebJJaLfDv+23T1jQvHrHppHM6tGqhh
Fdx+RH568KJepc/cxiuhQEAUp3uYJqPCZm7LXTvnk4zk8zIASoIaMsyDJ4SdEsMe
h4jdALmaXJA89i6diiyhb46FDKE4pfj9xP1Zm6I3/o7b/gU30Do5g7ZVI2z6K+50
tCCv4eovZ7ES18SDj6WpcutviQKaInJfUVy0+SH68hcf0P0x599LeplTFLNJBXIJ
WEd4JvpLQ02ENrjJQa3oQrD00FthiacEjOgEqHMMoruUdT8x8C2PmBn+JpzcDwC/
99od5lOHPykokCcFo8eTrZarkSJrBuJ12qzJuDA5OQIDAQABo1kwVzAUBgNVHREE
DTALgglsb2NhbGhvc3QwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMB
MB0GA1UdDgQWBBRDZOrwgxsoDn8gmf1AZm7bEv0RDjANBgkqhkiG9w0BAQsFAAOC
AQEANMBeZjgqgFoZnAXoKJYSQgvjhATMUIOw/NnvqTlKKKBp5R7R2kOmb/XDgF7Z
0uQc7LRRy9diTVo3uUjlgFb2AfZMozqAqk0oIg2R6KdpMOWmce6j6BQEgtGEsHUx
WmvaSgrOimEMO8MG2Hf+sHWLifhFVsd5eZHEBVRkk6a8ydVTBtntNke2Mt1/99WC
qenTmGHe+WZ0YJouxeqyIpiTauKF1/YV2urQfSI3Dcu/fdUeoitiykp+7XEl8FZY
MUOQxgEMnHYOGhpSbyD6YeonUGse/OZswZNPTWRPhpRRjOE6S5oJDjyZtgI8vzIY
pm0FL5EJ4kRadxcCUx5WPN+KAA==
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions certs/localhost.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCKcxpuXsTKgktC
R5sklot8O/7bdPWNC8esemkczq0aqGEV3H5Efnrwol6lz9zGK6FAQBSne5gmo8Jm
bstdO+eTjOTzMgBKghoyzIMnhJ0Swx6HiN0AuZpckDz2Lp2KLKFvjoUMoTil+P3E
/Vmbojf+jtv+BTfQOjmDtlUjbPor7nS0IK/h6i9nsRLXxIOPpaly62+JApoicl9R
XLT5IfryFx/Q/THn30t6mVMUs0kFcglYR3gm+ktDTYQ2uMlBrehCsPTQW2GJpwSM
6ASocwyiu5R1PzHwLY+YGf4mnNwPAL/32h3mU4c/KSiQJwWjx5OtlquRImsG4nXa
rMm4MDk5AgMBAAECggEAAT3LN8BgiBbPPTDGbLdvWH2yuS3FKl63y318/gnB3lZy
aWdk1/Eg4dG44sh4eKvpOhng/YfziywmePPnHabE+qsVnfMdss1UFg7Eocjz/hgz
CMDSx3gCkPAnpcbw+W1RRL5sxbpX11AiWV7yq90yXpVSFmbeU18ER0CuJn9KhnSN
ZaK3CuyS1vwdUbk/vtE1cV/RkbNlHTLAwvSUrxUz/pKCjxSTluJf6OrvzJYmaYeV
g2Fcw5YBZwmXWic0TtZRc0jwuv1PgjqoLWkt/KcvGOJi9XlLl1BmSWWxTc9WRNN3
8SbOZfbJTODb8RgZvwbbEZJfpjy2Ls+SGe18KiK98QKBgQC/78V9eliDJgKOkZvP
dgB+DdHBQFZmWw5L5SgoD6lYuHAKalJtdxoMHJvzsVerTkBTDH4MOaZALacGbSEi
TxVn7FHwBz3I5c8IUHeLn6Z+Sdvs0oFGCtVflR104sBIX5xR7uKl5Mp7p0lJ5C3T
ojEBg1ZvTRArgZBLiRe5jKjcsQKBgQC4qRRFdUu+oy3CCzUUIfFLmNQ4DOUisYC8
zO8qp9iNaWi6a1iEvlUMRLv8GpJYbFFxCvu7IRuho1lR89N2WrdOrr9KhT604rkm
MUiZx/nPLNNOmw/LuApvKStj2jWGRbKfGjrrLDQITv8m2NO+jrHrxw5rmERiCVJr
4o/1YRmnCQKBgF7B3itDkp00z8BZDKZQqI+S/QI+ZClmPNmlSbz1dnKxo8bQlN8s
FLT0Dt4xqImPOVyG51fbwkMfBr26dMg+aOAEoLMysAMVya9eIpbQ+96PUj9J8b6F
rK/iq0dAhxNz+HXOzSB/oqOHhDwxpZo9EZqgn7SVRC1marmP9iGJ2vgRAoGAbAU0
P4FjAqyv+r/Vl+ZXIZLQKc2ZSFcvaMI08e3npqlPwyVCTbyNQbT/hnUAwMr0RT1Y
jlnKsR4+BMuuGqDsdBGTAwO479Vk22ue/Z5WipO9NFFOxyvspqQdprah8t7Yo2uT
pbhg469aYJ4cF2+fsr3puJUFA5hSZ5vL/I2FlQkCgYANv8fNaei0EYfuP92lb+re
rpFjfpjP6ZNJjeWRoUHV7hP2IuSSscE7VFjGtzcebyhqAsJnEltAqaKU/iG+Z6tw
si+GI73cief/jVU7jPNmwSkSL2djptRG87W6mSRc0u+Bbni08mx2ocdtJYwkcDcr
Oe3L9UbIguutuWZ4d0rnqg==
-----END PRIVATE KEY-----
2 changes: 2 additions & 0 deletions examples/echo/echo.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ int main(void)
*/
.host = "0.0.0.0",
.port = 8080,
//.cert = "certs/localhost.crt",
//.cert_key = "certs/localhost.key",
.thread_loop = 0,
.timeout_ms = 1000,
.evs.onopen = &onopen,
Expand Down
6 changes: 3 additions & 3 deletions examples/echo/echo.html
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ <h1 align="left">wsServer</h1>
onclick="document.getElementById('txtServer').value='ws://localhost:8080'">
<label for="port1">ws:// (8080)</label>

<input type="radio" name="port" id="port2" value="wss:// (443)"
onclick="document.getElementById('txtServer').value='wss://localhost:443'">
<label for="port2">wss:// (443)</label>
<input type="radio" name="port" id="port2" value="wss:// (8080)"
onclick="document.getElementById('txtServer').value='wss://localhost:8080'">
<label for="port2">wss:// (8080)</label>

<br /> <br />

Expand Down
14 changes: 14 additions & 0 deletions include/ws.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,16 @@ extern "C" {
* @brief Listening port
*/
uint16_t port;
#ifdef ENABLE_SSL
/**
* @brief SSL certificate path (if any) (MUST to enable "wss")
*/
const char *cert;
/**
* @brief SSL private key path (if any) (MUST to enable "wss")
*/
const char *cert_key;
#endif
/**
* @brief Whether if the ws_socket() should create a new thread
* and be non-blocking (1) or not (0).
Expand All @@ -305,6 +315,10 @@ extern "C" {
/* Internal usage. */
extern int get_handshake_accept(char *wsKey, unsigned char **dest);
extern int get_handshake_response(char *hsrequest, char **hsresponse);
#ifdef ENABLE_SSL
extern int ssl_init(const char *cert, const char *cert_key);
extern void ssl_end(void);
#endif

/* External usage. */
extern char *ws_getaddress(ws_cli_conn_t client);
Expand Down
146 changes: 145 additions & 1 deletion src/ws.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
//#define ENABLE_SSL
#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <fcntl.h>
Expand All @@ -27,6 +28,11 @@
#include <time.h>
#include <sys/time.h>

#ifdef ENABLE_SSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif

/* clang-format off */
#ifndef _WIN32
#include <arpa/inet.h>
Expand Down Expand Up @@ -59,6 +65,13 @@ typedef int socklen_t;
* @brief wsServer main routines.
*/

#ifdef ENABLE_SSL
/**
* @brief SSL context
*/
SSL_CTX *ssl_ctx;
#endif

/**
* @brief Client socks.
*/
Expand Down Expand Up @@ -88,6 +101,11 @@ struct ws_connection
int32_t current_ping_id;
pthread_mutex_t mtx_ping;

#ifdef ENABLE_SSL
/* SSL */
SSL *ssl;
#endif

/* Connection context */
void *connection_context;

Expand Down Expand Up @@ -341,7 +359,11 @@ static ssize_t send_all(
pthread_mutex_lock(&client->mtx_snd);
while (len)
{
#ifdef ENABLE_SSL
r = client->ssl ? SSL_write(client->ssl, p, len) : send(client->client_sock, p, len, flags);
#else
r = send(client->client_sock, p, len, flags);
#endif
if (r == -1)
{
pthread_mutex_unlock(&client->mtx_snd);
Expand Down Expand Up @@ -373,6 +395,15 @@ static void close_client(struct ws_connection *client, int lock)

set_client_state(client, WS_STATE_CLOSED);

#ifdef ENABLE_SSL
/* Close the client SSL instance */
if (client->ssl)
{
SSL_shutdown(client->ssl);
SSL_free(client->ssl);
}
#endif

close_socket(client->client_sock);

/* Destroy client mutexes and clear fd 'slot'. */
Expand Down Expand Up @@ -656,7 +687,11 @@ static int ws_sendframe_internal(struct ws_connection *client, const char *msg,
output = 0;
if (client && port == 0)
{
#ifdef ENABLE_SSL
output = client->ssl ? SSL_write(client->ssl, response, idx_response) : SEND(client, response, idx_response);
#else
output = SEND(client, response, idx_response);
#endif
goto skip_broadcast;
}

Expand All @@ -671,7 +706,11 @@ static int ws_sendframe_internal(struct ws_connection *client, const char *msg,
get_client_state(cli) == WS_STATE_OPEN &&
(cli->ws_srv.port == port))
{
#ifdef ENABLE_SSL
if ((send_ret = cli->ssl ? SSL_write(cli->ssl, response, idx_response) : SEND(cli, response, idx_response)) != -1)
#else
if ((send_ret = SEND(cli, response, idx_response)) != -1)
#endif
output += send_ret;
else
{
Expand Down Expand Up @@ -1027,7 +1066,11 @@ static int do_handshake(struct ws_frame_data *wfd)
ssize_t n; /* Read/Write bytes. */

/* Read the very first client message. */
#ifdef ENABLE_SSL
if ((n = (wfd->client)->ssl ? SSL_read((wfd->client)->ssl, wfd->frm, sizeof(wfd->frm) - 1) : RECV(wfd->client, wfd->frm, sizeof(wfd->frm) - 1)) < 0)
#else
if ((n = RECV(wfd->client, wfd->frm, sizeof(wfd->frm) - 1)) < 0)
#endif
return (-1);

/* Advance our pointers before the first next_byte(). */
Expand Down Expand Up @@ -1055,7 +1098,11 @@ static int do_handshake(struct ws_frame_data *wfd)
response);

/* Send handshake. */
if (SEND(wfd->client, response, strlen(response)) < 0)
#ifdef ENABLE_SSL
if (((wfd->client)->ssl ? SSL_write((wfd->client)->ssl, response, strlen(response)) : SEND(wfd->client, response, strlen(response))) < 0)
#else
if ((SEND(wfd->client, response, strlen(response))) < 0)
#endif
{
free(response);
DEBUG("As error has occurred while handshaking!\n");
Expand Down Expand Up @@ -1182,7 +1229,11 @@ static inline int next_byte(struct ws_frame_data *wfd)
/* If empty or full. */
if (wfd->cur_pos == 0 || wfd->cur_pos == wfd->amt_read)
{
#ifdef ENABLE_SSL
if ((n = (wfd->client)->ssl ? SSL_read((wfd->client)->ssl, wfd->frm, sizeof(wfd->frm)) : RECV(wfd->client, wfd->frm, sizeof(wfd->frm))) <= 0)
#else
if ((n = RECV(wfd->client, wfd->frm, sizeof(wfd->frm))) <= 0)
#endif
{
wfd->error = 1;
DEBUG("An error has occurred while trying to read next byte\n");
Expand Down Expand Up @@ -1884,6 +1935,22 @@ static void *ws_accept(void *data)
client_socks[i].client_id = get_next_cid();
set_client_address(&client_socks[i]);

#ifdef ENABLE_SSL
/* Accept the SSL instance */
client_socks[i].ssl = 0;
if (ssl_ctx)
{
SSL *cli_ssl = SSL_new(ssl_ctx);
if (SSL_set_fd(cli_ssl, new_sock))
{
if (SSL_accept(cli_ssl))
{
client_socks[i].ssl = cli_ssl;
}
}
}
#endif

if (pthread_mutex_init(&client_socks[i].mtx_state, NULL))
panic("Error on allocating close mutex");
if (pthread_cond_init(&client_socks[i].cnd_state_close, NULL))
Expand All @@ -1910,6 +1977,13 @@ static void *ws_accept(void *data)
close_socket(new_sock);
}

#ifdef ENABLE_SSL
if (ssl_ctx)
{
SSL_CTX_free(ssl_ctx);
}
#endif

free(data);
return (data);
}
Expand Down Expand Up @@ -2022,6 +2096,14 @@ int ws_socket(struct ws_server *ws_srv)
setvbuf(stdout, NULL, _IONBF, 0);
#endif

#ifdef ENABLE_SSL
/* Initialize SSL context */
if (ssl_init(ws_srv->cert, ws_srv->cert_key))
{
panic("Unable to initialize SSL context!");
}
#endif

/* Create socket and bind. */
sock = do_bind_socket(ws_srv);

Expand Down Expand Up @@ -2099,3 +2181,65 @@ int ws_file(struct ws_events *evs, const char *file)
return (0);
}
#endif

#ifdef ENABLE_SSL
/**
* @brief Initialization of the SSL functions
*
* @param cert path to the certificate (.pem).
*
* @param cert_key path to the certificate key (.pem).
*
* @return nothing
*
*/
int ssl_init(const char *cert, const char *cert_key)
{
ssl_ctx = 0;

if (!cert || !cert_key)
{
printf("SSL DISABLED\n");
return 0;
}

if (!*cert || !*cert_key)
{
return -1;
}

const SSL_METHOD *method;

method = TLS_server_method();

ssl_ctx = SSL_CTX_new(method);
if (!ssl_ctx)
{
return -1;
}

/* Configure the context of SSL session */
if (SSL_CTX_use_certificate_file(ssl_ctx, cert, SSL_FILETYPE_PEM) <= 0 ||
SSL_CTX_use_PrivateKey_file(ssl_ctx, cert_key, SSL_FILETYPE_PEM) <= 0)
{
return -1;
}

atexit(ssl_end);

printf("SSL ENABLED\n");

return 0;
}

/**
* @brief Finalize the SSL session
*
* @return nothing
*
*/
void ssl_end(void)
{
SSL_CTX_free(ssl_ctx);
}
#endif