sbsign, sbvarsign: support engine based private keys
Add the ability to specify an engine to read the keyfile. For safety,
we don't do the full dynamic engine support, but only use engines
configured for use by the platform.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
diff --git a/src/fileio.c b/src/fileio.c
index faab3b7..032eb1e 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -39,6 +39,7 @@
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/err.h>
+#include <openssl/engine.h>
#include <ccan/talloc/talloc.h>
#include <ccan/read_write_all/read_write_all.h>
@@ -47,6 +48,55 @@
#define FLAG_NOERROR (1<<0)
+static int ui_read(UI *ui, UI_STRING *uis)
+{
+ char password[128];
+
+ if (UI_get_string_type(uis) != UIT_PROMPT)
+ return 0;
+
+ EVP_read_pw_string(password, sizeof(password), "Enter engine key pass phrase:", 0);
+ UI_set_result(ui, uis, password);
+ return 1;
+}
+
+EVP_PKEY *fileio_read_engine_key(const char *engine, const char *filename)
+{
+ UI_METHOD *ui;
+ ENGINE *e;
+ EVP_PKEY *pkey = NULL;
+
+ ENGINE_load_builtin_engines();
+ e = ENGINE_by_id(engine);
+
+ if (!e) {
+ fprintf(stderr, "Failed to load engine: %s\n", engine);
+ ERR_print_errors_fp(stderr);
+ return NULL;
+ }
+
+ ui = UI_create_method("sbsigntools");
+ if (!ui) {
+ fprintf(stderr, "Failed to create UI method\n");
+ ERR_print_errors_fp(stderr);
+ goto out_free;
+ }
+ UI_method_set_reader(ui, ui_read);
+
+ if (!ENGINE_init(e)) {
+ fprintf(stderr, "Failed to initialize engine %s\n", engine);
+ ERR_print_errors_fp(stderr);
+ goto out_free;
+ }
+
+ pkey = ENGINE_load_private_key(e, filename, ui, NULL);
+ ENGINE_finish(e);
+
+ out_free:
+ ENGINE_free(e);
+ return pkey;
+}
+
EVP_PKEY *fileio_read_pkey(const char *filename)
{
EVP_PKEY *key = NULL;
diff --git a/src/fileio.h b/src/fileio.h
index 52c3c12..b3ed22c 100644
--- a/src/fileio.h
+++ b/src/fileio.h
@@ -38,6 +38,7 @@
#include <openssl/x509.h>
EVP_PKEY *fileio_read_pkey(const char *filename);
+EVP_PKEY *fileio_read_engine_key(const char *engine, const char *filename);
X509 *fileio_read_cert(const char *filename);
int fileio_read_file(void *ctx, const char *filename,
diff --git a/src/sbsign.c b/src/sbsign.c
index 406472e..ff1fdfd 100644
--- a/src/sbsign.c
+++ b/src/sbsign.c
@@ -74,6 +74,7 @@
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
+ { "engine", required_argument, NULL, 'e'},
{ NULL, 0, NULL, 0 },
};
@@ -83,6 +84,7 @@
"<efi-boot-image>\n"
"Sign an EFI boot image for use with secure boot.\n\n"
"Options:\n"
+ "\t--engine <eng> use the specified engine to load the key\n"
"\t--key <keyfile> signing key (PEM-encoded RSA "
"private key)\n"
"\t--cert <certfile> certificate (x509 certificate)\n"
@@ -112,19 +114,21 @@
int main(int argc, char **argv)
{
- const char *keyfilename, *certfilename;
+ const char *keyfilename, *certfilename, *engine;
struct sign_context *ctx;
uint8_t *buf, *tmp;
int rc, c, sigsize;
+ EVP_PKEY *pkey;
ctx = talloc_zero(NULL, struct sign_context);
keyfilename = NULL;
certfilename = NULL;
+ engine = NULL;
for (;;) {
int idx;
- c = getopt_long(argc, argv, "o:c:k:dvVh", options, &idx);
+ c = getopt_long(argc, argv, "o:c:k:dvVhe:", options, &idx);
if (c == -1)
break;
@@ -150,6 +154,9 @@
case 'h':
usage();
return EXIT_SUCCESS;
+ case 'e':
+ engine = optarg;
+ break;
}
}
@@ -190,7 +197,10 @@
* module isn't present). In either case ignore the errors
* (malloc will cause other failures out lower down */
ERR_clear_error();
- EVP_PKEY *pkey = fileio_read_pkey(keyfilename);
+ if (engine)
+ pkey = fileio_read_engine_key(engine, keyfilename);
+ else
+ pkey = fileio_read_pkey(keyfilename);
if (!pkey)
return EXIT_FAILURE;
diff --git a/src/sbvarsign.c b/src/sbvarsign.c
index b45cccb..7dcbe51 100644
--- a/src/sbvarsign.c
+++ b/src/sbvarsign.c
@@ -398,6 +398,7 @@
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
+ { "engine", required_argument, NULL, 'e'},
{ NULL, 0, NULL, 0 },
};
@@ -409,6 +410,7 @@
"<var-name> <var-data-file>\n"
"Sign a blob of data for use in SetVariable().\n\n"
"Options:\n"
+ "\t--engine <eng> use the specified engine to load the key\n"
"\t--key <keyfile> signing key (PEM-encoded RSA "
"private key)\n"
"\t--cert <certfile> certificate (x509 certificate)\n"
@@ -437,7 +439,7 @@
int main(int argc, char **argv)
{
- const char *guid_str, *attr_str, *varname;
+ const char *guid_str, *attr_str, *varname, *engine;
const char *keyfilename, *certfilename;
struct varsign_context *ctx;
bool include_attrs;
@@ -447,13 +449,14 @@
keyfilename = NULL;
certfilename = NULL;
+ engine = NULL;
guid_str = NULL;
attr_str= NULL;
include_attrs = false;
for (;;) {
int idx;
- c = getopt_long(argc, argv, "o:g:a:k:c:ivVh", options, &idx);
+ c = getopt_long(argc, argv, "o:g:a:k:c:ivVhe:", options, &idx);
if (c == -1)
break;
@@ -485,6 +488,9 @@
case 'h':
usage();
return EXIT_SUCCESS;
+ case 'e':
+ engine = optarg;
+ break;
}
}
@@ -542,7 +548,10 @@
if (fileio_read_file(ctx, ctx->infilename, &ctx->data, &ctx->data_len))
return EXIT_FAILURE;
- ctx->key = fileio_read_pkey(keyfilename);
+ if (engine)
+ ctx->key = fileio_read_engine_key(engine, keyfilename);
+ else
+ ctx->key = fileio_read_pkey(keyfilename);
if (!ctx->key)
return EXIT_FAILURE;