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:
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)