MINOR: jwt: Insert public certificates into dedicated JWT tree

A JWT signed with the RSXXX or ESXXX algorithm (RSA or ECDSA) requires a
public certificate to be verified and to ensure it is valid. Those
certificates must not be read on disk at runtime so we need a caching
mechanism into which those certificates will be loaded during init.
This is done through a dedicated ebtree that is filled during
configuration parsing. The path to the public certificates will need to
be explicitely mentioned in the configuration so that certificates can
be loaded as early as possible.
This tree is different from the ckch one because ckch entries are much
bigger than the public certificates used in JWT validation process.
diff --git a/include/haproxy/jwt-t.h b/include/haproxy/jwt-t.h
index 6ac68b1..4189e65 100644
--- a/include/haproxy/jwt-t.h
+++ b/include/haproxy/jwt-t.h
@@ -61,6 +61,12 @@
 	JWT_ELT_SIG,
 	JWT_ELT_MAX
 };
+
+struct jwt_cert_tree_entry {
+	EVP_PKEY *pkey;
+	struct ebmb_node node;
+	char path[VAR_ARRAY];
+};
 #endif /* USE_OPENSSL */
 
 
diff --git a/include/haproxy/jwt.h b/include/haproxy/jwt.h
index b24cc28..6ae6e63 100644
--- a/include/haproxy/jwt.h
+++ b/include/haproxy/jwt.h
@@ -28,6 +28,7 @@
 #ifdef USE_OPENSSL
 enum jwt_alg jwt_parse_alg(const char *alg_str, unsigned int alg_len);
 int jwt_tokenize(const struct buffer *jwt, struct jwt_item *items, unsigned int *item_num);
+int jwt_tree_load_cert(char *path, int pathlen, char **err);
 #endif /* USE_OPENSSL */
 
 #endif /* _HAPROXY_JWT_H */
diff --git a/src/jwt.c b/src/jwt.c
index 9f39a89..2103083 100644
--- a/src/jwt.c
+++ b/src/jwt.c
@@ -21,6 +21,9 @@
 
 
 #ifdef USE_OPENSSL
+/* Tree into which the public certificates used to validate JWTs will be stored. */
+static struct eb_root jwt_cert_tree = EB_ROOT_UNIQUE;
+
 /*
  * The possible algorithm strings that can be found in a JWS's JOSE header are
  * defined in section 3.1 of RFC7518.
@@ -120,4 +123,47 @@
 	return (ptr != jwt_end);
 }
 
+/*
+ * Parse a public certificate and insert it into the jwt_cert_tree.
+ * Returns 0 in case of success.
+ */
+int jwt_tree_load_cert(char *path, int pathlen, char **err)
+{
+	int retval = -1;
+	struct jwt_cert_tree_entry *entry = NULL;
+	EVP_PKEY *pkey = NULL;
+	BIO *bio = NULL;
+
+	bio = BIO_new(BIO_s_file());
+	if (!bio) {
+		memprintf(err, "%sunable to allocate memory (BIO).\n", err && *err ? *err : "");
+		goto end;
+	}
+
+	if (BIO_read_filename(bio, path) == 1) {
+
+		pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
+
+		if (!pkey) {
+			memprintf(err, "%sfile not found (%s)\n", err && *err ? *err : "", path);
+			goto end;
+		}
+
+		entry = calloc(1, sizeof(*entry) + pathlen + 1);
+		if (!entry) {
+			memprintf(err, "%sunable to allocate memory (jwt_cert_tree_entry).\n", err && *err ? *err : "");
+			goto end;
+		}
+
+		memcpy(entry->path, path, pathlen + 1);
+		entry->pkey = pkey;
+
+		ebst_insert(&jwt_cert_tree, &entry->node);
+		retval = 0;
+	}
+
+end:
+	BIO_free(bio);
+	return retval;
+}
 #endif /* USE_OPENSSL */