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.
This commit is contained in:
Joris Vink 2014-03-05 11:38:47 +01:00
parent 75c4bb0754
commit 1375190936
3 changed files with 64 additions and 12 deletions

View File

@ -66,6 +66,12 @@
#define NETBUF_CALL_CB_ALWAYS 0x01 #define NETBUF_CALL_CB_ALWAYS 0x01
#define NETBUF_FORCE_REMOVE 0x02 #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. */ /* XXX hackish. */
struct http_request; struct http_request;
struct spdy_stream; struct spdy_stream;
@ -135,6 +141,7 @@ struct connection {
SSL *ssl; SSL *ssl;
u_int8_t flags; u_int8_t flags;
void *hdlr_extra; void *hdlr_extra;
X509 *cert;
u_int8_t addrtype; u_int8_t addrtype;
union { union {

View File

@ -34,6 +34,7 @@ struct kore_log_packet {
char host[KORE_DOMAINNAME_LEN]; char host[KORE_DOMAINNAME_LEN];
char path[HTTP_URI_LEN]; char path[HTTP_URI_LEN];
char agent[HTTP_USERAGENT_LEN]; char agent[HTTP_USERAGENT_LEN];
char cn[X509_CN_LENGTH];
}; };
void void
@ -55,13 +56,12 @@ kore_accesslog_wait(void)
{ {
ssize_t len; ssize_t len;
time_t now; time_t now;
size_t slen;
int nfds;
struct kore_domain *dom; struct kore_domain *dom;
struct pollfd pfd[1]; struct pollfd pfd[1];
int nfds, l;
struct kore_log_packet logpacket; struct kore_log_packet logpacket;
char addr[INET6_ADDRSTRLEN]; char addr[INET6_ADDRSTRLEN];
char *method, buf[4096], *tbuf; char *method, *buf, *tbuf, *cn;
pfd[0].fd = accesslog_fd[0]; pfd[0].fd = accesslog_fd[0];
pfd[0].events = POLLIN; pfd[0].events = POLLIN;
@ -94,10 +94,22 @@ kore_accesslog_wait(void)
return (KORE_RESULT_OK); return (KORE_RESULT_OK);
} }
if (logpacket.method == HTTP_METHOD_GET) switch (logpacket.method) {
case HTTP_METHOD_GET:
method = "GET"; method = "GET";
else break;
case HTTP_METHOD_POST:
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), if (inet_ntop(logpacket.addrtype, &(logpacket.addr),
addr, sizeof(addr)) == NULL) addr, sizeof(addr)) == NULL)
@ -105,20 +117,25 @@ kore_accesslog_wait(void)
time(&now); time(&now);
tbuf = kore_time_to_date(now); tbuf = kore_time_to_date(now);
snprintf(buf, sizeof(buf), "[%s] %s %d %s %s (w#%d) (%dms) (%s)\n", l = asprintf(&buf, "[%s] %s %d %s %s (w#%d) (%dms) (%s) (%s)\n",
tbuf, addr, logpacket.status, method, tbuf, addr, logpacket.status, method, logpacket.path,
logpacket.path, logpacket.worker_id, logpacket.time_req, logpacket.worker_id, logpacket.time_req, cn, logpacket.agent);
logpacket.agent); if (l == -1) {
slen = strlen(buf); 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) { if (len == -1) {
kore_log(LOG_WARNING, kore_log(LOG_WARNING,
"kore_accesslog_wait(): write(): %s", errno_s); "kore_accesslog_wait(): write(): %s", errno_s);
return (KORE_RESULT_ERROR); return (KORE_RESULT_ERROR);
} }
if ((size_t)len != slen) if (len != l)
kore_log(LOG_NOTICE, "accesslog: %s", buf); kore_log(LOG_NOTICE, "accesslog: %s", buf);
return (KORE_RESULT_OK); return (KORE_RESULT_OK);
@ -157,6 +174,14 @@ kore_accesslog(struct http_request *req)
sizeof(logpacket.agent)); 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); len = send(accesslog_fd[1], &logpacket, sizeof(logpacket), 0);
if (len == -1) { if (len == -1) {
kore_log(LOG_WARNING, "kore_accesslog(): send(): %s", errno_s); kore_log(LOG_WARNING, "kore_accesslog(): send(): %s", errno_s);

View File

@ -70,6 +70,7 @@ kore_connection_accept(struct listener *l, struct connection **out)
c->owner = l; c->owner = l;
c->ssl = NULL; c->ssl = NULL;
c->flags = 0; c->flags = 0;
c->cert = NULL;
c->hdlr_extra = NULL; c->hdlr_extra = NULL;
c->inflate_started = 0; c->inflate_started = 0;
c->deflate_started = 0; c->deflate_started = 0;
@ -108,6 +109,7 @@ kore_connection_handle(struct connection *c)
int r; int r;
u_int32_t len; u_int32_t len;
const u_char *data; const u_char *data;
char cn[X509_CN_LENGTH];
kore_debug("kore_connection_handle(%p)", c); 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); r = SSL_get_verify_result(c->ssl);
if (r != X509_V_OK) { if (r != X509_V_OK) {
kore_debug("SSL_get_verify_result(): %d, %s", kore_debug("SSL_get_verify_result(): %d, %s",
@ -219,6 +236,9 @@ kore_connection_remove(struct connection *c)
SSL_free(c->ssl); SSL_free(c->ssl);
} }
if (c->cert != NULL)
X509_free(c->cert);
close(c->fd); close(c->fd);
if (c->hdlr_extra != NULL) if (c->hdlr_extra != NULL)