1 From 2fa8fedba0968d1c6d21d2c7fa33c903f8984815 Mon Sep 17 00:00:00 2001
2 From: Jackie Huang <jackie.huang@windriver.com>
3 Date: Thu, 25 Jul 2019 15:22:49 +0800
4 Subject: [PATCH] haproxy tpm support
6 original author: Kam Nasim <kam.nasim@windriver.com>
10 Signed-off-by: Jackie Huang <jackie.huang@windriver.com>
12 include/types/global.h | 13 +++++
13 src/cfgparse.c | 28 ++++++++++
14 src/haproxy.c | 26 ++++++++-
15 src/ssl_sock.c | 147 +++++++++++++++++++++++++++++++++++++++++++------
16 4 files changed, 197 insertions(+), 17 deletions(-)
18 diff --git a/include/types/global.h b/include/types/global.h
19 index 10f3a3c..68f2138 100644
20 --- a/include/types/global.h
21 +++ b/include/types/global.h
23 #include <import/51d.h>
27 +#include <openssl/engine.h>
31 #define UNIX_MAX_PATH 108
33 @@ -79,6 +83,14 @@ enum {
34 SSL_SERVER_VERIFY_REQUIRED = 1,
37 +// WRS: Define a new TPM configuration structure
42 + ENGINE *tpm_engine_ref;
45 /* FIXME : this will have to be redefined correctly */
48 @@ -101,6 +113,7 @@ struct global {
49 char *connect_default_ciphers;
50 int listen_default_ssloptions;
51 int connect_default_ssloptions;
52 + struct tpm_conf tpm; // tpm configuration
54 unsigned int ssl_server_verify; /* default verify mode on servers side */
55 struct freq_ctr conn_per_sec;
56 diff --git a/src/cfgparse.c b/src/cfgparse.c
57 index 3489f7e..0209874 100644
60 @@ -1923,6 +1923,34 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
64 + else if (!strcmp(args[0], "tpm-object")) {
65 + if (global.tpm.tpm_object) {
66 + free(global.tpm.tpm_object);
69 + if (*(args[1]) && (access(args[1], F_OK) != -1)) {
70 + global.tpm.tpm_object = strdup(args[1]);
73 + Alert("parsing [%s:%d] : '%s' is not implemented.\n", file, linenum, args[0]);
74 + err_code |= ERR_ALERT | ERR_FATAL;
78 + else if (!strcmp(args[0], "tpm-engine")) {
79 + if (global.tpm.tpm_engine) {
80 + free(global.tpm.tpm_engine);
83 + if (*(args[1]) && (access(args[1], F_OK) != -1)) {
84 + global.tpm.tpm_engine = strdup(args[1]);
87 + Alert("parsing [%s:%d] : '%s' is not implemented.\n", file, linenum, args[0]);
88 + err_code |= ERR_ALERT | ERR_FATAL;
93 struct cfg_kw_list *kwl;
95 diff --git a/src/haproxy.c b/src/haproxy.c
96 index f8a0912..f61dacf 100644
99 @@ -1370,6 +1370,24 @@ static void deinit_stick_rules(struct list *rules)
103 +static void deinit_tpm_engine()
106 + * if the tpm engine is present then
107 + * deinit it, this is needed to
108 + * flush the TPM key handle from TPM memory
110 + if (global.tpm.tpm_engine_ref) {
111 + ENGINE_finish(global.tpm.tpm_engine_ref);
114 + if (global.tpm.tpm_key) {
115 + EVP_PKEY_free(global.tpm.tpm_key);
117 + free(global.tpm.tpm_engine); global.tpm.tpm_engine = NULL;
118 + free(global.tpm.tpm_object); global.tpm.tpm_object = NULL;
123 struct proxy *p = proxy, *p0;
124 @@ -1646,7 +1664,13 @@ void deinit(void)
130 + /* if HAProxy was in TPM mode then deinit
131 + * that configuration as well.
133 + if (global.tpm.tpm_object && global.tpm.tpm_object != '\0')
134 + deinit_tpm_engine();
136 userlist_free(userlist);
138 cfg_unregister_sections();
139 diff --git a/src/ssl_sock.c b/src/ssl_sock.c
140 index 87b2584..44d0b48 100644
144 #ifndef OPENSSL_NO_DH
145 #include <openssl/dh.h>
147 +#include <openssl/engine.h>
149 #include <import/lru.h>
150 #include <import/xxhash.h>
151 @@ -2360,6 +2361,80 @@ end:
156 + * initialize the TPM engine and load the
157 + * TPM object as private key within the Engine.
158 + * Only do this for the first bind since TPM can
159 + * only load 3-4 contexes before it runs out of memory
161 +static int ssl_sock_load_tpm_key(SSL_CTX *ctx, char **err) {
162 + if (!global.tpm.tpm_object || global.tpm.tpm_object[0] == '\0') {
163 + /* not in TPM mode */
166 + if (!global.tpm.tpm_key) {
167 + Warning ("Could not find tpm_key; initializing engine\n");
168 + /* no key present; load the dynamic TPM engine */
169 + if (global.tpm.tpm_engine && global.tpm.tpm_engine[0]) {
170 + ENGINE_load_dynamic();
171 + ENGINE *engine = ENGINE_by_id("dynamic");
173 + memprintf(err, "%s Unable to load the dynamic engine "
174 + "(needed for loading custom TPM engine)\n",
175 + err && *err ? *err : "");
179 + ENGINE_ctrl_cmd_string(engine, "SO_PATH", global.tpm.tpm_engine, 0);
180 + ENGINE_ctrl_cmd_string(engine, "LOAD", NULL, 0);
181 + /* stow away for ENGINE cleanup */
182 + global.tpm.tpm_engine_ref = engine;
184 + if (ENGINE_init(engine) != 1) {
185 + const char *error_str = ERR_error_string(ERR_get_error(), NULL);
186 + memprintf(err, "%s Unable to init the TPM engine (%s). Err: %s\n",
187 + err && *err ? *err : "",
188 + global.tpm.tpm_engine, error_str);
191 + EVP_PKEY *pkey = ENGINE_load_private_key(engine,
192 + global.tpm.tpm_object,
195 + const char *error_str = ERR_error_string(ERR_get_error(), NULL);
196 + memprintf(err, "%s Unable to load TPM object (%s). Err: %s\n",
197 + err && *err ? *err : "",
198 + global.tpm.tpm_object, error_str);
201 + global.tpm.tpm_key = pkey;
203 + else { /* no TPM engine found */
204 + memprintf(err, "%s TPM engine option not set when TPM mode expected\n",
205 + err && *err ? *err : "");
210 + if (SSL_CTX_use_PrivateKey(ctx, global.tpm.tpm_key) <= 0){
211 + const char *error_str = ERR_error_string(ERR_get_error(),
213 + memprintf(err, "%s Invalid private key provided from TPM engine(%s). Err: %s\n",
214 + err && *err ? *err : "",
215 + global.tpm.tpm_object, error_str);
222 + ENGINE_finish(global.tpm.tpm_engine_ref);
223 + global.tpm.tpm_engine_ref = NULL;
224 + EVP_PKEY_free(global.tpm.tpm_key);
225 + global.tpm.tpm_key = NULL;
229 static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf, struct proxy *curproxy, char **sni_filter, int fcount, char **err)
232 @@ -2372,26 +2447,54 @@ static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf
236 - if (SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM) <= 0) {
237 - memprintf(err, "%sunable to load SSL private key from PEM file '%s'.\n",
238 - err && *err ? *err : "", path);
241 + /* NOTE (knasim-wrs): US93721: TPM support
242 + * This SSL context applies to SSL frontends only.
243 + * If the TPM option is set then the Private key
244 + * is stored in TPM.
246 + * Launch the OpenSSL TPM engine and load the TPM
247 + * Private Key. The Public key will still be located
248 + * at the provided path and needs to be loaded as
251 + if (global.tpm.tpm_object) {
252 + ret = ssl_sock_load_tpm_key(ctx, err);
254 + /* tpm configuration failed */
260 - ret = ssl_sock_load_cert_chain_file(ctx, path, bind_conf, sni_filter, fcount);
262 - memprintf(err, "%sunable to load SSL certificate from PEM file '%s'.\n",
263 - err && *err ? *err : "", path);
264 - if (ret < 0) /* serious error, must do that ourselves */
265 + else { /* non TPM mode */
266 + if (SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM) <= 0) {
267 + memprintf(err, "%sunable to load SSL private key from PEM file '%s'.\n",
268 + err && *err ? *err : "", path);
275 - if (SSL_CTX_check_private_key(ctx) <= 0) {
276 - memprintf(err, "%sinconsistencies between private key and certificate loaded from PEM file '%s'.\n",
277 - err && *err ? *err : "", path);
279 + ret = ssl_sock_load_cert_chain_file(ctx, path, bind_conf, sni_filter, fcount);
281 + memprintf(err, "%sunable to load SSL certificate from PEM file '%s'.\n",
282 + err && *err ? *err : "", path);
283 + if (ret < 0) /* serious error, must do that ourselves */
289 + * only match the private key to the public key
290 + * for non TPM mode. This op would never work for
291 + * TPM since the private key has been wrapped, whereas
292 + * the public key is still the original one.
294 + if (!global.tpm.tpm_object) {
295 + if (SSL_CTX_check_private_key(ctx) <= 0) {
296 + memprintf(err, "%sinconsistencies between private key and certificate loaded from PEM file '%s'.\n",
297 + err && *err ? *err : "", path);
302 /* we must not free the SSL_CTX anymore below, since it's already in
303 @@ -3068,6 +3171,18 @@ int ssl_sock_prepare_srv_ctx(struct server *srv, struct proxy *curproxy)
308 + /* NOTE (knasim-wrs): US93721: TPM support
309 + * This SSL context applies to SSL backends only.
310 + * Since Titanium backends don't support SSL, there
311 + * is no need to offload these keys in TPM or reuse the
312 + * same TPM key for the frontend engine.
314 + * If SSL backends are to be supported in the future,
315 + * over TPM, then create a new TPM Engine context and
316 + * load the backend key in TPM, in a similar fashion to
317 + * the frontend key.
319 if (srv->ssl_ctx.client_crt) {
320 if (SSL_CTX_use_PrivateKey_file(srv->ssl_ctx.ctx, srv->ssl_ctx.client_crt, SSL_FILETYPE_PEM) <= 0) {
321 Alert("config : %s '%s', server '%s': unable to load SSL private key from PEM file '%s'.\n",