summaryrefslogtreecommitdiffstats
path: root/src/serve.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/serve.c')
-rw-r--r--src/serve.c31
1 files changed, 30 insertions, 1 deletions
diff --git a/src/serve.c b/src/serve.c
index 4b63dde..d77c2ff 100644
--- a/src/serve.c
+++ b/src/serve.c
@@ -199,7 +199,36 @@ serve_cgi(struct gmnisrv_client *client, const char *path,
setenv("TLS_CIPHER", SSL_CIPHER_get_name(cipher), 1);
setenv("TLS_VERSION", SSL_CIPHER_get_version(cipher), 1);
- // TODO: Client certificate details
+ // barebones client cert implementation
+ // adapted from openssl(1)'s implementation
+ // TODO: support REMOTE_USER, TLS_CLIENT_NOT_{BEFORE,AFTER},
+ // TLS_CLIENT_SERIAL_NUMBER
+ X509 *client_cert = SSL_get_peer_certificate(client->ssl);
+ if (client_cert != NULL) {
+ // 32 bytes because we're always using SHA256, but
+ // possibly change to EVP_MAX_MD_SIZE to support all
+ // of openssl's hash funcs
+ unsigned char digest[32];
+
+ if (X509_digest(client_cert, EVP_sha256(), digest, NULL)) {
+ setenv("AUTH_TYPE", "CERTIFICATE", 1);
+ // 32*2 because converting to hex doubles length
+ // +7 for "SHA256:" prefix
+ // +1 for null char
+ char hex_digest[32*2 + 7 + 1];
+ strncat(hex_digest, "SHA256:", 8);
+
+ char *cur_pos = hex_digest + 7;
+ for (int i = 0; i < 32; ++i) {
+ cur_pos += sprintf(cur_pos, "%02X", digest[i]);
+ }
+ setenv("TLS_CLIENT_HASH", hex_digest, 1);
+ } else {
+ const char *error = "Out of memory";
+ client_submit_response(client,
+ GEMINI_STATUS_TEMPORARY_FAILURE, error, NULL);
+ }
+ }
execlp(path, path, NULL);
server_error("execlp: %s", strerror(errno));