summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstbuehler <stbuehler@152afb58-edef-0310-8abb-c4023f1b3aa9>2009-11-05 21:47:05 +0000
committerstbuehler <stbuehler@152afb58-edef-0310-8abb-c4023f1b3aa9>2009-11-05 21:47:05 +0000
commit8dca1b41ae335814e7c6a9ff44a27ba7c11ee50d (patch)
treec07d92eaa196dea4fb844b038f5e1a42502d96f3
parentc603cba2c23c7a7ef2afba6dabed3c049827c905 (diff)
downloadlighttpd-8dca1b41ae335814e7c6a9ff44a27ba7c11ee50d.tar.gz
export some SSL_CLIENT_* vars for client cert validation (fixes #1288, thx presbrey)
git-svn-id: svn://svn.lighttpd.net/lighttpd/trunk@2689 152afb58-edef-0310-8abb-c4023f1b3aa9
-rw-r--r--NEWS1
-rw-r--r--src/base.h1
-rw-r--r--src/configfile.c6
-rw-r--r--src/response.c75
4 files changed, 83 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index afc46534..58785fd1 100644
--- a/NEWS
+++ b/NEWS
@@ -153,6 +153,7 @@ NEWS
* Set content-length in mod_compress (fixes #2089, thx liming)
* Mark recv-queue closed if backend connection got closed in mod_proxy_core (fixes #2090, thx liming)
* mod_magnet: add traceback for printing lua errors
+ * export some SSL_CLIENT_* vars for client cert validation (fixes #1288, thx presbrey)
- 1.5.0-r19.. -
* -F option added for spawn-fcgi
diff --git a/src/base.h b/src/base.h
index 965fdc65..a61a755a 100644
--- a/src/base.h
+++ b/src/base.h
@@ -314,6 +314,7 @@ typedef struct {
unsigned short ssl_verifyclient_enforce;
unsigned short ssl_verifyclient_depth;
buffer *ssl_verifyclient_username;
+ unsigned short ssl_verifyclient_export_cert;
unsigned short use_ipv6;
unsigned short is_ssl;
diff --git a/src/configfile.c b/src/configfile.c
index 8cb5c691..2becea73 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -109,6 +109,7 @@ static int config_insert(server *srv) {
{ "ssl.verifyclient.enforce", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 61 */
{ "ssl.verifyclient.depth", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 62 */
{ "ssl.verifyclient.username", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 63 */
+ { "ssl.verifyclient.exportcert", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 64 */
{ "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
@@ -181,6 +182,7 @@ static int config_insert(server *srv) {
s->ssl_verifyclient_enforce = 1;
s->ssl_verifyclient_username = buffer_init();
s->ssl_verifyclient_depth = 9;
+ s->ssl_verifyclient_export_cert = 0;
s->max_keep_alive_requests = 16;
s->max_keep_alive_idle = 5;
s->max_read_idle = 60;
@@ -255,6 +257,7 @@ static int config_insert(server *srv) {
cv[61].destination = &(s->ssl_verifyclient_enforce);
cv[62].destination = &(s->ssl_verifyclient_depth);
cv[63].destination = s->ssl_verifyclient_username;
+ cv[64].destination = &(s->ssl_verifyclient_export_cert);
srv->config_storage[i] = s;
@@ -340,6 +343,7 @@ int config_setup_connection(server *srv, connection *con) {
PATCH(ssl_verifyclient_enforce);
PATCH(ssl_verifyclient_depth);
PATCH(ssl_verifyclient_username);
+ PATCH(ssl_verifyclient_export_cert);
return 0;
}
@@ -447,6 +451,8 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
PATCH(ssl_verifyclient_depth);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.username"))) {
PATCH(ssl_verifyclient_username);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.exportcert"))) {
+ PATCH(ssl_verifyclient_export_cert);
}
}
}
diff --git a/src/response.c b/src/response.c
index 748c2428..6dfc4e62 100644
--- a/src/response.c
+++ b/src/response.c
@@ -147,6 +147,75 @@ int http_response_write_header(server *srv, connection *con, chunkqueue *raw) {
return 0;
}
+#ifdef USE_OPENSSL
+static void https_add_ssl_entries(connection *con) {
+ X509 *xs;
+ X509_NAME *xn;
+ X509_NAME_ENTRY *xe;
+ if (
+ SSL_get_verify_result(con->sock->ssl) != X509_V_OK
+ || !(xs = SSL_get_peer_certificate(con->sock->ssl))
+ ) {
+ return;
+ }
+
+ xn = X509_get_subject_name(xs);
+ for (int i = 0, nentries = X509_NAME_entry_count(xn); i < nentries; ++i) {
+ int xobjnid;
+ const char * xobjsn;
+ data_string *envds;
+
+ if (!(xe = X509_NAME_get_entry(xn, i))) {
+ continue;
+ }
+ xobjnid = OBJ_obj2nid((ASN1_OBJECT*)X509_NAME_ENTRY_get_object(xe));
+ xobjsn = OBJ_nid2sn(xobjnid);
+ if (!xobjsn) {
+ continue;
+ }
+
+ if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
+ envds = data_string_init();
+ }
+ buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_S_DN_"));
+ buffer_append_string(envds->key, xobjsn);
+ buffer_copy_string_len(
+ envds->value,
+ (const char *)xe->value->data, xe->value->length
+ );
+ /* pick one of the exported values as "authed user", for example
+ * ssl.verifyclient.username = "SSL_CLIENT_S_DN_UID" or "SSL_CLIENT_S_DN_emailAddress"
+ */
+ if (buffer_is_equal(con->conf.ssl_verifyclient_username, envds->key)) {
+ buffer_copy_string_buffer(con->authed_user, envds->value);
+ }
+ array_insert_unique(con->environment, (data_unset *)envds);
+ }
+ if (con->conf.ssl_verifyclient_export_cert) {
+ BIO *bio;
+ if (NULL != (bio = BIO_new(BIO_s_mem()))) {
+ data_string *envds;
+ int n;
+
+ PEM_write_bio_X509(bio, xs);
+ n = BIO_pending(bio);
+
+ if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
+ envds = data_string_init();
+ }
+
+ buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_CERT"));
+ buffer_prepare_copy(envds->value, n+1);
+ BIO_read(bio, envds->value->ptr, n);
+ BIO_free(bio);
+ envds->value->ptr[n] = '\0';
+ envds->value->used = n+1;
+ array_insert_unique(con->environment, (data_unset *)envds);
+ }
+ }
+ X509_free(xs);
+}
+#endif
handler_t handle_get_backend(server *srv, connection *con) {
@@ -292,6 +361,12 @@ handler_t handle_get_backend(server *srv, connection *con) {
TRACE("URI-path : %s", SAFE_BUF_STR(con->uri.path));
}
+#ifdef USE_OPENSSL
+ if (con->conf.is_ssl && con->conf.ssl_verifyclient) {
+ https_add_ssl_entries(con);
+ }
+#endif
+
/**
*
* call plugins