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 | 6 ++- src/mod_openssl.c | 113 +++++++++++++++++++++++++++++++++++++++++++++--------- src/server.c | 17 +++++++- 4 files changed, 139 insertions(+), 21 deletions(-) diff --git a/src/base.h b/src/base.h index 2fe60b6..bddcd01 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 */ @@ -360,6 +375,13 @@ 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; } server_config; @@ -400,6 +422,8 @@ struct server { int con_written; int con_closed; + int tpm_is_init; // has TPM been initialized already + int max_fds; /* max possible fds */ int cur_fds; /* currently used fds */ int want_fds; /* waiting fds */ diff --git a/src/configfile.c b/src/configfile.c index c3b0f16..dca2a29 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -276,8 +276,10 @@ static int config_insert(server *srv) { { "server.syslog-facility", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 80 */ { "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.tpm-object", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 83 */ + { "server.tpm-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 84 */ - { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; /* all T_CONFIG_SCOPE_SERVER options */ @@ -318,6 +320,8 @@ static int config_insert(server *srv) { cv[80].destination = srv->srvconf.syslog_facility; http_parseopts = array_init(); cv[82].destination = http_parseopts; + cv[83].destination = srv->srvconf.tpm_object; + cv[84].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 75e0873..4cb0335 100644 --- a/src/mod_openssl.c +++ b/src/mod_openssl.c @@ -422,6 +422,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) @@ -476,15 +499,23 @@ 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 = 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__, "sssb", "SSL:", - "Private key does not match the certificate public key," - " reason:", ERR_error_string(ERR_get_error(), NULL), - s->ssl_pemfile); - return -1; + + // if TPM mode is enabled then load the TPM key otherwise load + // the regular SSL private key + if (srv->tpm_is_init) { + if (NULL == (s->ssl_pemfile_pkey = evp_pkey_load_tpm_object_file(srv))) return -1; + } + else { + if (NULL == (s->ssl_pemfile_pkey = evp_pkey_load_pem_file(srv, s->ssl_pemfile->ptr))) return -1; + + if (!X509_check_private_key(s->ssl_pemfile_x509, s->ssl_pemfile_pkey)) { + log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:", + "Private key does not match the certificate public key, reason:", + ERR_error_string(ERR_get_error(), NULL), + s->ssl_pemfile); + return -1; + } + } return 0; @@ -651,6 +682,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]; @@ -911,29 +979,36 @@ 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__, "ssb", "SSL:", ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); return -1; } - if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) { - log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:", - "Private key does not match the certificate public " - "key, reason:", - ERR_error_string(ERR_get_error(), NULL), - s->ssl_pemfile); - 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__, "sssb", "SSL:", + "Private key does not match the certificate public key, reason:", + ERR_error_string(ERR_get_error(), NULL), + s->ssl_pemfile); + 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) | SSL_MODE_ENABLE_PARTIAL_WRITE diff --git a/src/server.c b/src/server.c index f6409bb..2ace3f8 100644 --- a/src/server.c +++ b/src/server.c @@ -246,6 +246,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 @@ -347,6 +352,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 @@ -776,7 +789,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 upstrean to see if there is a potential bug */ + //return -1; } } else { -- 2.7.4