[PATCH] uhttpd: implement TLS client certificate authentication
Luka Logar
luka.logar at cifra.si
Fri Feb 19 15:01:51 EST 2021
Enable client certificate authentication by specifying a -b path_to_ca_cert_file on the command line.
When this parameter is set, TLS server requests a client certificate (signed by the specified CA). If
client certificate authentication is successful, client cert data is stored in HTTPS_CLIENT_CERT,
HTTPS_CLIENT_CERT_SHA256 and HTTPS_CLIENT_CERT_SN environment variables. Currently not supported by
mbedtls backend.
Signed-off-by: Luka Logar <luka.logar at cifra.si>
---
main.c | 10 ++++++++--
proc.c | 9 +++++++++
tls.c | 7 ++++++-
tls.h | 2 +-
4 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/main.c b/main.c
index 73e3d42..fb6a84e 100644
--- a/main.c
+++ b/main.c
@@ -141,6 +141,7 @@ static int usage(const char *name)
" -K file ASN.1 server private key file\n"
" -P ciphers Colon separated list of allowed TLS ciphers\n"
" -q Redirect all HTTP requests to HTTPS\n"
+ " -b client_ca Enable TLS client auth using client_ca for certificate selection\n"
#endif
" -h directory Specify the document root, default is '.'\n"
" -E string Use given virtual URL as 404 error handler\n"
@@ -252,6 +253,7 @@ int main(int argc, char **argv)
#ifdef HAVE_TLS
int n_tls = 0;
const char *tls_key = NULL, *tls_crt = NULL, *tls_ciphers = NULL;
+ const char *tls_client_ca = NULL;
#endif
#ifdef HAVE_LUA
const char *lua_prefix = NULL, *lua_handler = NULL;
@@ -263,7 +265,7 @@ int main(int argc, char **argv)
init_defaults_pre();
signal(SIGPIPE, SIG_IGN);
- while ((ch = getopt(argc, argv, "A:aC:c:Dd:E:e:fh:H:I:i:K:k:L:l:m:N:n:P:p:qRr:Ss:T:t:U:u:Xx:y:")) != -1) {
+ while ((ch = getopt(argc, argv, "A:ab:C:c:Dd:E:e:fh:H:I:i:K:k:L:l:m:N:n:P:p:qRr:Ss:T:t:U:u:Xx:y:")) != -1) {
switch(ch) {
#ifdef HAVE_TLS
case 'C':
@@ -282,6 +284,10 @@ int main(int argc, char **argv)
conf.tls_redirect = 1;
break;
+ case 'b':
+ tls_client_ca = optarg;
+ break;
+
case 's':
n_tls++;
/* fall through */
@@ -535,7 +541,7 @@ int main(int argc, char **argv)
return 1;
}
- if (uh_tls_init(tls_key, tls_crt, tls_ciphers))
+ if (uh_tls_init(tls_key, tls_crt, tls_ciphers, tls_client_ca))
return 1;
}
#endif
diff --git a/proc.c b/proc.c
index 2b69703..798f385 100644
--- a/proc.c
+++ b/proc.c
@@ -90,6 +90,9 @@ enum extra_vars {
VAR_PATH_INFO,
VAR_USER,
VAR_HTTPS,
+ VAR_HTTPS_CLIENT_CERT,
+ VAR_HTTPS_CLIENT_CERT_SHA256,
+ VAR_HTTPS_CLIENT_CERT_SN,
VAR_REDIRECT,
VAR_SERVER_NAME,
VAR_SERVER_ADDR,
@@ -118,6 +121,9 @@ static struct env_var extra_vars[] = {
[VAR_PATH_INFO] = { "PATH_INFO" },
[VAR_USER] = { "REMOTE_USER" },
[VAR_HTTPS] = { "HTTPS" },
+ [VAR_HTTPS_CLIENT_CERT] = { "HTTPS_CLIENT_CERT" },
+ [VAR_HTTPS_CLIENT_CERT_SHA256] = { "HTTPS_CLIENT_CERT_SHA256" },
+ [VAR_HTTPS_CLIENT_CERT_SN] = { "HTTPS_CLIENT_CERT_SN" },
[VAR_REDIRECT] = { "REDIRECT_STATUS", redirect_status },
[VAR_SERVER_NAME] = { "SERVER_NAME", local_addr },
[VAR_SERVER_ADDR] = { "SERVER_ADDR", local_addr },
@@ -154,6 +160,9 @@ struct env_var *uh_get_process_vars(struct client *cl, struct path_info *pi)
extra_vars[VAR_PATH_INFO].value = pi->info;
extra_vars[VAR_USER].value = req->realm ? req->realm->user : NULL;
extra_vars[VAR_HTTPS].value = cl->tls ? "on" : NULL;
+ extra_vars[VAR_HTTPS_CLIENT_CERT].value = cl->ssl.peer_cert;
+ extra_vars[VAR_HTTPS_CLIENT_CERT_SHA256].value = cl->ssl.peer_cert ? cl->ssl.peer_cert_sha256 : NULL;
+ extra_vars[VAR_HTTPS_CLIENT_CERT_SN].value = cl->ssl.peer_cert_sn;
snprintf(redirect_status, sizeof(redirect_status),
"%d", req->redirect_status);
diff --git a/tls.c b/tls.c
index 1da0881..bb616eb 100644
--- a/tls.c
+++ b/tls.c
@@ -31,7 +31,7 @@ static struct ustream_ssl_ops *ops;
static void *dlh;
static void *ctx;
-int uh_tls_init(const char *key, const char *crt, const char *ciphers)
+int uh_tls_init(const char *key, const char *crt, const char *ciphers, const char *client_ca)
{
static bool _init = false;
@@ -68,6 +68,11 @@ int uh_tls_init(const char *key, const char *crt, const char *ciphers)
return -EINVAL;
}
+ if (client_ca && (ops->context_set_require_validation(ctx, 1) || ops->context_add_ca_crt_file(ctx, client_ca))) {
+ fprintf(stderr, "Can not enable TLS client authentication\n");
+ return -EINVAL;
+ }
+
return 0;
}
diff --git a/tls.h b/tls.h
index f457cb7..2b0b26a 100644
--- a/tls.h
+++ b/tls.h
@@ -22,7 +22,7 @@
#ifdef HAVE_TLS
-int uh_tls_init(const char *key, const char *crt, const char *ciphers);
+int uh_tls_init(const char *key, const char *crt, const char *ciphers, const char *client_ca);
void uh_tls_client_attach(struct client *cl);
void uh_tls_client_detach(struct client *cl);
--
2.25.1
More information about the openwrt-devel
mailing list