commit 68d0523817537f46783aaf1bc61a10da2fc9af74
parent cba9628f16ad49bc7b8bb2f4077f16978b1cb9fb
Author: Joris Vink <joris@coders.se>
Date: Sun, 21 Apr 2013 20:21:46 +0200
Add initial SSL stuff + bare bones NPN advertisement. So far chrome connects and
shows our connection as SPDY/3, good start.
Diffstat:
4 files changed, 114 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,6 +1,6 @@
# Kore Makefile
-CC=clang
+CC=gcc
BIN=kore
S_SRC= src/kore.c src/utils.c
@@ -9,7 +9,7 @@ S_OBJS= $(S_SRC:.c=.o)
CFLAGS+=-Wall -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+=-Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual
CFLAGS+=-Wsign-compare -Iincludes -g
-LDFLAGS=
+LDFLAGS=-lcrypto -lssl
light: $(S_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) $(S_OBJS) -o $(BIN)
diff --git a/includes/kore.h b/includes/kore.h
@@ -21,9 +21,12 @@
#define KORE_RESULT_OK 1
#define errno_s strerror(errno)
+#define ssl_errno_s ERR_error_string(ERR_get_error(), NULL)
#define kore_log(fmt, ...) \
kore_log_internal(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
+#define KORE_SSL_PROTO_STRING "\x06spdy/3\x08http/1.1"
+
struct netbuf {
u_int8_t *data;
u_int32_t offset;
@@ -39,10 +42,16 @@ struct listener {
struct sockaddr_in sin;
};
+#define CONN_STATE_UNKNOWN 0
+#define CONN_STATE_SSL_SHAKE 1
+#define CONN_STATE_ESTABLISHED 2
+
struct connection {
int fd;
+ int state;
struct sockaddr_in sin;
void *owner;
+ SSL *ssl;
TAILQ_HEAD(, netbuf) send_queue;
TAILQ_HEAD(, netbuf) recv_queue;
diff --git a/src/kore.c b/src/kore.c
@@ -23,6 +23,9 @@
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
@@ -35,12 +38,16 @@
#define EPOLL_EVENTS 500
static int efd = -1;
+static SSL_CTX *ssl_ctx = NULL;
+static int kore_server_sslstart(void);
static int kore_server_bind(struct listener *, const char *, int);
static int kore_server_accept(struct listener *);
static int kore_connection_handle(struct connection *, int);
static int kore_socket_nonblock(int);
static void kore_event(int, int, void *);
+static int kore_ssl_npn_cb(SSL *, const unsigned char **,
+ unsigned int *, void *);
int
main(int argc, char *argv[])
@@ -55,6 +62,8 @@ main(int argc, char *argv[])
if (!kore_server_bind(&server, argv[1], atoi(argv[2])))
fatal("cannot bind to %s:%s", argv[1], argv[2]);
+ if (!kore_server_sslstart())
+ fatal("cannot initiate SSL");
if ((efd = epoll_create(1000)) == -1)
fatal("epoll_create(): %s", errno_s);
@@ -82,7 +91,8 @@ main(int argc, char *argv[])
kore_server_accept(&server);
} else {
c = (struct connection *)events[i].data.ptr;
- if (!kore_connection_handle(c, events[i].events))
+ if (!kore_connection_handle(c,
+ events[i].events))
/* Disconnect. */;
}
}
@@ -93,6 +103,37 @@ main(int argc, char *argv[])
}
static int
+kore_server_sslstart(void)
+{
+ SSL_library_init();
+ SSL_load_error_strings();
+ ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+ if (ssl_ctx == NULL) {
+ kore_log("SSL_ctx_new(): %s", ssl_errno_s);
+ return (KORE_RESULT_ERROR);
+ }
+
+ if (!SSL_CTX_use_certificate_file(ssl_ctx, "cert/server.crt",
+ SSL_FILETYPE_PEM)) {
+ kore_log("SSL_CTX_use_certificate_file(): %s", ssl_errno_s);
+ return (KORE_RESULT_ERROR);
+ }
+
+ if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, "cert/server.key",
+ SSL_FILETYPE_PEM)) {
+ kore_log("SSL_CTX_use_PrivateKey_file(): %s", ssl_errno_s);
+ return (KORE_RESULT_ERROR);
+ }
+
+ SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
+ SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, kore_ssl_npn_cb, NULL);
+
+ return (KORE_RESULT_OK);
+}
+
+static int
kore_server_bind(struct listener *l, const char *ip, int port)
{
if ((l->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
@@ -146,6 +187,8 @@ kore_server_accept(struct listener *l)
}
c->owner = l;
+ c->ssl = NULL;
+ c->state = CONN_STATE_SSL_SHAKE;
TAILQ_INIT(&(c->send_queue));
TAILQ_INIT(&(c->recv_queue));
kore_event(c->fd, EPOLLIN | EPOLLET, c);
@@ -157,6 +200,49 @@ kore_server_accept(struct listener *l)
static int
kore_connection_handle(struct connection *c, int flags)
{
+ int r;
+
+ switch (c->state) {
+ case CONN_STATE_SSL_SHAKE:
+ if (c->ssl == NULL) {
+ c->ssl = SSL_new(ssl_ctx);
+ if (c->ssl == NULL) {
+ kore_log("SSL_new(): %s", ssl_errno_s);
+ return (KORE_RESULT_ERROR);
+ }
+
+ SSL_set_fd(c->ssl, c->fd);
+ }
+
+ r = SSL_accept(c->ssl);
+ if (r <= 0) {
+ r = SSL_get_error(c->ssl, r);
+ switch (r) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ return (KORE_RESULT_OK);
+ default:
+ kore_log("SSL_accept(): %s", ssl_errno_s);
+ return (KORE_RESULT_ERROR);
+ }
+ }
+
+ r = SSL_get_verify_result(c->ssl);
+ if (r != X509_V_OK) {
+ kore_log("SSL_get_verify_result(): %s", ssl_errno_s);
+ return (KORE_RESULT_ERROR);
+ }
+
+ c->state = CONN_STATE_ESTABLISHED;
+ break;
+ case CONN_STATE_ESTABLISHED:
+ kore_log("got bytes on established");
+ break;
+ default:
+ kore_log("unknown state on %d (%d)", c->fd, c->state);
+ break;
+ }
+
return (KORE_RESULT_OK);
}
@@ -189,3 +275,15 @@ kore_event(int fd, int flags, void *udata)
if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &evt) == -1)
fatal("epoll_ctl(): %s", errno_s);
}
+
+static int
+kore_ssl_npn_cb(SSL *ssl, const unsigned char **data,
+ unsigned int *len, void *arg)
+{
+ kore_log("npn callback: sending protocols");
+
+ *data = (const unsigned char *)KORE_SSL_PROTO_STRING;
+ *len = strlen(KORE_SSL_PROTO_STRING);
+
+ return (SSL_TLSEXT_ERR_OK);
+}
diff --git a/src/utils.c b/src/utils.c
@@ -22,8 +22,12 @@
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
#include <errno.h>
#include <fcntl.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>