kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit 1375190936703cca92db19b23d49446dd2c512af
parent 75c4bb0754643edef515dd87ff503efaf5c9a531
Author: Joris Vink <joris@coders.se>
Date:   Wed,  5 Mar 2014 11:38:47 +0100

Improvements for client certificates.

Double check we actually get a certificate if we are asking for one.
Even though we set SSL_VERIFY_FAIL_IF_NO_PEER_CERT it's a sane thing to do.

Start logging the CN for the received client certificate in the access logs.

As a bonus re-arrange some accesslog stuff for sanity.

Diffstat:
includes/kore.h | 7+++++++
src/accesslog.c | 49+++++++++++++++++++++++++++++++++++++------------
src/connection.c | 20++++++++++++++++++++
3 files changed, 64 insertions(+), 12 deletions(-)

diff --git a/includes/kore.h b/includes/kore.h @@ -66,6 +66,12 @@ #define NETBUF_CALL_CB_ALWAYS 0x01 #define NETBUF_FORCE_REMOVE 0x02 +#define X509_GET_CN(c, o, l) \ + X509_NAME_get_text_by_NID(X509_get_subject_name(c), \ + NID_commonName, o, l) + +#define X509_CN_LENGTH (ub_common_name + 1) + /* XXX hackish. */ struct http_request; struct spdy_stream; @@ -135,6 +141,7 @@ struct connection { SSL *ssl; u_int8_t flags; void *hdlr_extra; + X509 *cert; u_int8_t addrtype; union { diff --git a/src/accesslog.c b/src/accesslog.c @@ -34,6 +34,7 @@ struct kore_log_packet { char host[KORE_DOMAINNAME_LEN]; char path[HTTP_URI_LEN]; char agent[HTTP_USERAGENT_LEN]; + char cn[X509_CN_LENGTH]; }; void @@ -55,13 +56,12 @@ kore_accesslog_wait(void) { ssize_t len; time_t now; - size_t slen; - int nfds; struct kore_domain *dom; struct pollfd pfd[1]; + int nfds, l; struct kore_log_packet logpacket; char addr[INET6_ADDRSTRLEN]; - char *method, buf[4096], *tbuf; + char *method, *buf, *tbuf, *cn; pfd[0].fd = accesslog_fd[0]; pfd[0].events = POLLIN; @@ -94,10 +94,22 @@ kore_accesslog_wait(void) return (KORE_RESULT_OK); } - if (logpacket.method == HTTP_METHOD_GET) + switch (logpacket.method) { + case HTTP_METHOD_GET: method = "GET"; - else + break; + case HTTP_METHOD_POST: method = "POST"; + break; + default: + method = "UNKNOWN"; + break; + } + + if (logpacket.cn[0] != '\0') + cn = logpacket.cn; + else + cn = "none"; if (inet_ntop(logpacket.addrtype, &(logpacket.addr), addr, sizeof(addr)) == NULL) @@ -105,20 +117,25 @@ kore_accesslog_wait(void) time(&now); tbuf = kore_time_to_date(now); - snprintf(buf, sizeof(buf), "[%s] %s %d %s %s (w#%d) (%dms) (%s)\n", - tbuf, addr, logpacket.status, method, - logpacket.path, logpacket.worker_id, logpacket.time_req, - logpacket.agent); - slen = strlen(buf); + l = asprintf(&buf, "[%s] %s %d %s %s (w#%d) (%dms) (%s) (%s)\n", + tbuf, addr, logpacket.status, method, logpacket.path, + logpacket.worker_id, logpacket.time_req, cn, logpacket.agent); + if (l == -1) { + kore_log(LOG_WARNING, + "kore_accesslog_wait(): asprintf() == -1"); + return (KORE_RESULT_ERROR); + } + + len = write(dom->accesslog, buf, l); + free(buf); - len = write(dom->accesslog, buf, slen); if (len == -1) { kore_log(LOG_WARNING, "kore_accesslog_wait(): write(): %s", errno_s); return (KORE_RESULT_ERROR); } - if ((size_t)len != slen) + if (len != l) kore_log(LOG_NOTICE, "accesslog: %s", buf); return (KORE_RESULT_OK); @@ -157,6 +174,14 @@ kore_accesslog(struct http_request *req) sizeof(logpacket.agent)); } + memset(logpacket.cn, '\0', sizeof(logpacket.cn)); + if (req->owner->cert != NULL) { + if (X509_GET_CN(req->owner->cert, + logpacket.cn, sizeof(logpacket.cn)) == -1) { + kore_log(LOG_WARNING, "client cert without a CN?"); + } + } + len = send(accesslog_fd[1], &logpacket, sizeof(logpacket), 0); if (len == -1) { kore_log(LOG_WARNING, "kore_accesslog(): send(): %s", errno_s); diff --git a/src/connection.c b/src/connection.c @@ -70,6 +70,7 @@ kore_connection_accept(struct listener *l, struct connection **out) c->owner = l; c->ssl = NULL; c->flags = 0; + c->cert = NULL; c->hdlr_extra = NULL; c->inflate_started = 0; c->deflate_started = 0; @@ -108,6 +109,7 @@ kore_connection_handle(struct connection *c) int r; u_int32_t len; const u_char *data; + char cn[X509_CN_LENGTH]; kore_debug("kore_connection_handle(%p)", c); @@ -139,6 +141,21 @@ kore_connection_handle(struct connection *c) } } + if (SSL_get_verify_mode(c->ssl) & SSL_VERIFY_PEER) { + c->cert = SSL_get_peer_certificate(c->ssl); + if (c->cert == NULL) { + kore_log(LOG_NOTICE, + "no client certificate presented?"); + return (KORE_RESULT_ERROR); + } + + if (X509_GET_CN(c->cert, cn, sizeof(cn)) == -1) { + kore_log(LOG_NOTICE, + "no CN found in client certificate"); + return (KORE_RESULT_ERROR); + } + } + r = SSL_get_verify_result(c->ssl); if (r != X509_V_OK) { kore_debug("SSL_get_verify_result(): %d, %s", @@ -219,6 +236,9 @@ kore_connection_remove(struct connection *c) SSL_free(c->ssl); } + if (c->cert != NULL) + X509_free(c->cert); + close(c->fd); if (c->hdlr_extra != NULL)