From c58d174a1d2872272bfa9d83c642591f04effcb1 Mon Sep 17 00:00:00 2001 From: Kam Nasim Date: Wed, 29 Mar 2017 21:56:41 -0400 Subject: [PATCH] lighttpd tpm support --- src/base.h | 24 ++++++++++ src/configfile.c | 4 ++ src/mod_openssl.c | 116 +++++++++++++++++++++++++++++++++++++--------- src/server.c | 17 ++++++- 4 files changed, 139 insertions(+), 22 deletions(-) diff --git a/src/base.h b/src/base.h index f21973b..f7b5777 100644 --- a/src/base.h +++ b/src/base.h @@ -15,6 +15,21 @@ #include "sock_addr.h" #include "etag.h" +#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H +# define USE_OPENSSL +# include +# ifndef USE_OPENSSL_KERBEROS +# ifndef OPENSSL_NO_KRB5 +# define OPENSSL_NO_KRB5 +# endif +# endif +# include +# include +# if ! defined OPENSSL_NO_TLSEXT && ! defined SSL_CTRL_SET_TLSEXT_HOSTNAME +# define OPENSSL_NO_TLSEXT +# endif +#endif + struct fdevents; /* declaration */ struct stat_cache; /* declaration */ @@ -342,6 +357,14 @@ typedef struct { unsigned short high_precision_timestamps; time_t loadts; double loadavg[3]; +#ifdef USE_OPENSSL + // TPM engine and object configuration + buffer *tpm_object; + buffer *tpm_engine; + ENGINE *tpm_engine_ref; + EVP_PKEY *tpm_key; +#endif + buffer *syslog_facility; unsigned short compat_module_load; @@ -380,6 +403,7 @@ struct server { int con_written; int con_closed; + int tpm_is_init; // has TPM been initialized already int max_fds; /* max possible fds */ int max_fds_lowat;/* low watermark */ int max_fds_hiwat;/* high watermark */ diff --git a/src/configfile.c b/src/configfile.c index b870b59..5b91b35 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -282,6 +282,8 @@ static int config_insert(server *srv) { { "server.socket-perms", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 81 */ { "server.http-parseopts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 82 */ { "server.systemd-socket-activation", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 83 */ + { "server.tpm-object", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 84 */ + { "server.tpm-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 85 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -327,6 +329,8 @@ static int config_insert(server *srv) { http_parseopts = array_init(); cv[82].destination = http_parseopts; cv[83].destination = &(srv->srvconf.systemd_socket_activation); + cv[84].destination = srv->srvconf.tpm_object; + cv[85].destination = srv->srvconf.tpm_engine; srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); diff --git a/src/mod_openssl.c b/src/mod_openssl.c index f9a4fe8..e38605c 100644 --- a/src/mod_openssl.c +++ b/src/mod_openssl.c @@ -488,6 +488,29 @@ error: return NULL; } +static EVP_PKEY* +evp_pkey_load_tpm_object_file(server *srv) { + if (!srv->tpm_is_init || !srv->srvconf.tpm_engine_ref) + return NULL; + + if (srv->srvconf.tpm_key) { + // if a TPM key was previously loaded + // then return that as there is no need to + // reload this key into TPM + return srv->srvconf.tpm_key; + } + + EVP_PKEY *pkey = ENGINE_load_private_key(srv->srvconf.tpm_engine_ref, + srv->srvconf.tpm_object->ptr, + NULL, NULL); + if (!pkey) { + log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL:", + ERR_error_string(ERR_get_error(), NULL)); + return NULL; + } + srv->srvconf.tpm_key = pkey; + return pkey; +} static EVP_PKEY * evp_pkey_load_pem_file (server *srv, const char *file) @@ -542,17 +565,24 @@ network_openssl_load_pemfile (server *srv, plugin_config *s, size_t ndx) s->ssl_pemfile_x509 = x509_load_pem_file(srv, s->ssl_pemfile->ptr); if (NULL == s->ssl_pemfile_x509) return -1; - s->ssl_pemfile_pkey = !buffer_string_is_empty(s->ssl_privkey) - ? evp_pkey_load_pem_file(srv, s->ssl_privkey->ptr) - : evp_pkey_load_pem_file(srv, s->ssl_pemfile->ptr); - if (NULL == s->ssl_pemfile_pkey) return -1; - - if (!X509_check_private_key(s->ssl_pemfile_x509, s->ssl_pemfile_pkey)) { - log_error_write(srv, __FILE__, __LINE__, "sssbb", "SSL:", - "Private key does not match the certificate public key," - " reason:", ERR_error_string(ERR_get_error(), NULL), - s->ssl_pemfile, s->ssl_privkey); - return -1; + // If TPM mode is enabled thenload the TPM key, otherwise load + // the regular SSL private key. + if (srv->tpm_is_init) { + s->ssl_pemfile_pkey = evp_pkey_load_tpm_object_file(srv); + if (NULL == s->ssl_pemfile_pkey) return -1; + } else { + s->ssl_pemfile_pkey = !buffer_string_is_empty(s->ssl_privkey) + ? evp_pkey_load_pem_file(srv, s->ssl_privkey->ptr) + : evp_pkey_load_pem_file(srv, s->ssl_pemfile->ptr); + if (NULL == s->ssl_pemfile_pkey) return -1; + + if (!X509_check_private_key(s->ssl_pemfile_x509, s->ssl_pemfile_pkey)) { + log_error_write(srv, __FILE__, __LINE__, "sssbb", "SSL:", + "Private key does not match the certificate public key," + " reason:", ERR_error_string(ERR_get_error(), NULL), + s->ssl_pemfile, s->ssl_privkey); + return -1; + } } return 0; @@ -878,6 +908,43 @@ network_init_ssl (server *srv, void *p_d) force_assert(NULL != local_send_buffer); } + /* NOTE (knasim-wrs): US93721: TPM support + * if TPM mode is configured, and we have not previously + * initialized the engine then do so now + */ + if (!buffer_string_is_empty(srv->srvconf.tpm_object) && + (!srv->tpm_is_init)) { + if (!buffer_string_is_empty(srv->srvconf.tpm_engine)) { + // load the dynamic TPM engine + ENGINE_load_dynamic(); + ENGINE *engine = ENGINE_by_id("dynamic"); + if (!engine) { + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + "Unable to load the dynamic engine " + "(needed for loading custom TPM engine)"); + return -1; + } + + ENGINE_ctrl_cmd_string(engine, "SO_PATH", + srv->srvconf.tpm_engine->ptr, 0); + ENGINE_ctrl_cmd_string(engine, "LOAD", NULL, 0); + if (ENGINE_init(engine) != 1) { + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", + ERR_error_string(ERR_get_error(), NULL)); + ENGINE_finish(engine); + return -1; + } + srv->tpm_is_init = 1; + // stow away for ENGINE cleanup + srv->srvconf.tpm_engine_ref = engine; + } + else { // no TPM engine found + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + "TPM engine option not set when TPM mode expected"); + return -1; + } + } + if (!buffer_string_is_empty(s->ssl_pemfile)) { #ifdef OPENSSL_NO_TLSEXT data_config *dc = (data_config *)srv->config_context->data[i]; @@ -1147,28 +1214,35 @@ network_init_ssl (server *srv, void *p_d) } } - if (1 != SSL_CTX_use_certificate_chain_file(s->ssl_ctx, - s->ssl_pemfile->ptr)) { + if (1 != SSL_CTX_use_PrivateKey(s->ssl_ctx, s->ssl_pemfile_pkey)) { log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); return -1; } - if (1 != SSL_CTX_use_PrivateKey(s->ssl_ctx, s->ssl_pemfile_pkey)) { + if (1 != SSL_CTX_use_certificate(s->ssl_ctx, s->ssl_pemfile_x509)) { log_error_write(srv, __FILE__, __LINE__, "ssbb", "SSL:", ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile, s->ssl_privkey); return -1; } - if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) { - log_error_write(srv, __FILE__, __LINE__, "sssbb", "SSL:", - "Private key does not match the certificate public " - "key, reason:", - ERR_error_string(ERR_get_error(), NULL), - s->ssl_pemfile, s->ssl_privkey); - return -1; + /* + * Only check private key against loaded + * certificate, in non TPM mode, since + * if this is a TPM key then it is wrapped + * and will not match the public key. + */ + if (!srv->tpm_is_init) { + if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) { + log_error_write(srv, __FILE__, __LINE__, "sssbb", "SSL:", + "Private key does not match the certificate public " + "key, reason:", + ERR_error_string(ERR_get_error(), NULL), + s->ssl_pemfile, s->ssl_privkey); + return -1; + } } SSL_CTX_set_default_read_ahead(s->ssl_ctx, s->ssl_read_ahead); SSL_CTX_set_mode(s->ssl_ctx, SSL_CTX_get_mode(s->ssl_ctx) diff --git a/src/server.c b/src/server.c index b7086b0..b90ce61 100644 --- a/src/server.c +++ b/src/server.c @@ -248,6 +248,11 @@ static server *server_init(void) { CLEAN(srvconf.pid_file); CLEAN(srvconf.syslog_facility); +#ifdef USE_OPENSSL + CLEAN(srvconf.tpm_object); + CLEAN(srvconf.tpm_engine); +#endif + CLEAN(tmp_chunk_len); #undef CLEAN @@ -344,6 +349,14 @@ static void server_free(server *srv) { CLEAN(srvconf.xattr_name); CLEAN(srvconf.syslog_facility); +#ifdef USE_OPENSSL + CLEAN(srvconf.tpm_object); + CLEAN(srvconf.tpm_engine); + // don't free the tpm_key as that will be freed + // below as ssl_pemfile_pkey + ENGINE_finish(srv->srvconf.tpm_engine_ref); +#endif + CLEAN(tmp_chunk_len); #undef CLEAN @@ -784,7 +797,9 @@ static int log_error_open(server *srv) { if (-1 == (errfd = fdevent_open_devnull())) { log_error_write(srv, __FILE__, __LINE__, "ss", "opening /dev/null failed:", strerror(errno)); - return -1; + /* In version 1.4.45 it will also failed here but not check return value of openDevNull(STDERR_FILENO) + need further check with upstream to see if there is a potential bug */ + //return -1; } } else { -- 2.21.0