From 86693a33abd5e8c31530adb3045c9f4664d4d6c9 Mon Sep 17 00:00:00 2001 From: Omar Polo Date: Sun, 11 Jun 2023 11:03:59 +0000 Subject: add a privsep crypto engine Incorporate the OpenSMTPD' privsep crypto engine. The idea behind it is to never load the certificate' private keys in a networked process, instead they are loaded in a separate process (the `crypto' one) which signs payloads on the behalf of the server processes. This way, we greatly reduce the risk of leaking the certificate' private key should the server process be compromised. This currently compiles only on LibreSSL (portable fix is in the way). --- utils.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'utils.c') diff --git a/utils.c b/utils.c index b8f09c7..c5f91a1 100644 --- a/utils.c +++ b/utils.c @@ -1,5 +1,7 @@ /* * Copyright (c) 2021 Omar Polo + * Copyright (c) 2008 Pierre-Yves Ritschard + * Copyright (c) 2008 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +22,7 @@ #include #include +#include #include #include #include @@ -246,6 +249,90 @@ end: return ret; } +void +ssl_error(const char *where) +{ + unsigned long code; + char errbuf[128]; + + while ((code = ERR_get_error()) != 0) { + ERR_error_string_n(code, errbuf, sizeof(errbuf)); + log_debug("debug: SSL library error: %s: %s", where, errbuf); + } +} + +char * +ssl_pubkey_hash(const char *buf, size_t len) +{ + static const char hex[] = "0123456789abcdef"; + BIO *in; + X509 *x509 = NULL; + char *hash = NULL; + size_t off; + char digest[EVP_MAX_MD_SIZE]; + int dlen, i; + + if ((in = BIO_new_mem_buf(buf, len)) == NULL) { + log_warnx("%s: BIO_new_mem_buf failed", __func__); + return NULL; + } + + if ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL)) == NULL) { + log_warnx("%s: PEM_read_bio_X509 failed", __func__); + ssl_error("PEM_read_bio_X509"); + goto fail; + } + + if ((hash = malloc(TLS_CERT_HASH_SIZE)) == NULL) { + log_warn("%s: malloc", __func__); + goto fail; + } + + if (X509_pubkey_digest(x509, EVP_sha256(), digest, &dlen) != 1) { + log_warnx("%s: X509_pubkey_digest failed", __func__); + ssl_error("X509_pubkey_digest"); + free(hash); + hash = NULL; + goto fail; + } + + if (TLS_CERT_HASH_SIZE < 2 * dlen + sizeof("SHA256:")) + fatalx("%s: hash buffer too small", __func__); + + off = strlcpy(hash, "SHA256:", TLS_CERT_HASH_SIZE); + for (i = 0; i < dlen; ++i) { + hash[off++] = hex[(digest[i] >> 4) & 0xf]; + hash[off++] = hex[digest[i] & 0xf]; + } + hash[off] = '\0'; + + fail: + BIO_free(in); + if (x509) + X509_free(x509); + return hash; +} + +EVP_PKEY * +ssl_load_pkey(const char *buf, size_t len) +{ + BIO *in; + EVP_PKEY *pkey; + + if ((in = BIO_new_mem_buf(buf, len)) == NULL) { + log_warnx("%s: BIO_new_mem_buf failed", __func__); + return NULL; + } + + if ((pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL)) == NULL) { + log_warnx("%s: PEM_read_bio_PrivateKey failed", __func__); + ssl_error("PEM_read_bio_PrivateKey"); + } + + BIO_free(in); + return pkey; +} + struct vhost * new_vhost(void) { -- cgit v1.2.3