From 88ca3621017aea6655e83d3cbe19f76ae87a17f9 Mon Sep 17 00:00:00 2001 From: Christian Hohnstaedt Date: Wed, 26 Jul 2023 18:35:53 +0200 Subject: [PATCH] Close #62 #149: pass a private key passphrase to an enroll request Implement the Openssl syntax according to: https://www.openssl.org/docs/man3.0/man1/openssl-passphrase-options.html Enable this feature (and keyboard login) for ENGINE keys. Removing the passphrase from a software key is sometimes possible, but removing it from from an ENGINE key is usually impossible. The OS will drop the allocated memory for the UI_METHOD. This is a short running app after all. Signed-off-by: Christian Hohnstaedt --- src/engine.c | 2 +- src/sscep.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src/engine.c b/src/engine.c index 5b00686..7768a4e 100644 --- a/src/engine.c +++ b/src/engine.c @@ -179,7 +179,7 @@ ENGINE *scep_engine_load_dynamic(void) { //idea from: http://blog.burghardt.pl/2010/03/ncipher-hsm-with-openssl/ void sscep_engine_read_key(EVP_PKEY **key, char *id, ENGINE *e) { - *key = ENGINE_load_private_key(e, id, NULL, NULL); + *key = ENGINE_load_private_key(e, id, UI_get_default_method(), NULL); //ERR_print_errors_fp(stderr); if(*key == 0) { diff --git a/src/sscep.c b/src/sscep.c index 15456a6..b1f0d25 100644 --- a/src/sscep.c +++ b/src/sscep.c @@ -8,6 +8,11 @@ #include "sscep.h" +#include +#include +#include +#include + char *pname; int timeout; @@ -68,6 +73,7 @@ int v_flag; int w_flag; char *w_char; int W_flag; +char *P_char; const EVP_MD *fp_alg; const EVP_MD *sig_alg; @@ -223,6 +229,74 @@ handle_serial (char * serial) return serial; } /* handle_serial */ +static int sscep_read_cmd(UI *ui, UI_STRING *uis) +{ + int fd = -1, docl = -1; + const char *result = P_char; + char buf[128], *p; + + switch (UI_get_string_type(uis)) { + case UIT_BOOLEAN: + case UIT_PROMPT: + case UIT_VERIFY: + break; + case UIT_NONE: + case UIT_INFO: + case UIT_ERROR: + return 1; + } + if (!strncmp(result, "pass:", 5)) { + result += 5; + } else if (!strncmp(result, "env:", 4)) { + result = getenv(result +4); + if (!result) { + fprintf(stderr, "Environment variable '%s' was empty\n", P_char+4); + return 0; + } + } else if (!strncmp(result, "fd:", 3)) { + if (result[3] < '0' || result[3] > '9') { + fprintf(stderr, "password fd must be between 0 and 9\n"); + return 0; + } + fd = result[3] - '0'; + } else if (!strcmp(result, "stdin")) { + fd = 0; + } else if (!strncmp(result, "file:", 5)) { + docl = fd = open(result +5, O_RDONLY); + if (fd == -1) { + perror(result +5); + return 0; + } + } + if (fd >= 0) { + ssize_t r = read(fd, buf, sizeof buf-1); + if (r < 0) { + perror(result +5); + if (docl >= 0) + close(docl); + return 0; + } + buf[r] = 0; + p = memchr(buf, '\n', r); + if (p) + *p = 0; + result = buf; + if (docl >= 0) + close(docl); + } + return UI_set_result(ui, uis, result) >= 0 ? 1 : 0; +} + +static void setup_UI() +{ + if (!P_char) + return; + UI_METHOD *ui = UI_create_method("sscep UI"); + UI_method_set_reader(ui, sscep_read_cmd); + + UI_set_default_method(ui); +} + int main(int argc, char **argv) { //ENGINE *e = NULL; @@ -307,7 +381,7 @@ main(int argc, char **argv) { } /* Skip first parameter and parse the rest of the command */ optind++; - while ((c = getopt(argc, argv, "c:C:de:E:f:g:hF:i:k:K:l:L:n:O:p:r:Rs:S:t:T:u:vw:W:m:HM:")) != -1) + while ((c = getopt(argc, argv, "c:C:de:E:f:g:hF:i:k:K:l:L:n:O:p:P:r:Rs:S:t:T:u:vw:W:m:HM:")) != -1) switch(c) { case 'c': c_flag = 1; @@ -445,6 +519,9 @@ main(int argc, char **argv) { case 'W': W_flag = atoi(optarg); break; + case 'P': + P_char = optarg; + break; default: printf("argv: %s\n", argv[optind]); usage(); @@ -466,6 +543,7 @@ main(int argc, char **argv) { fprintf(stdout, "%s: starting sscep, version %s\n", pname, VERSION); + setup_UI(); /* * Create a new SCEP transaction and self-signed * certificate based on cert request @@ -1350,6 +1428,7 @@ usage() { " -r Certificate request file\n" " -K Signature private key file, use with -O\n" " -O Signature certificate (used instead of self-signed)\n" + " -P Provide password for batch mode\n" " -l Write enrolled certificate in file\n" " -e Use different CA cert for encryption\n" " -L Write selfsigned certificate in file\n" @@ -1361,14 +1440,22 @@ usage() { " -k Signature private key file\n" " -l Signature local certificate file\n" " -O Issuer Certificate of the certificate to query (requires -s)\n" + " -P Provide password for batch mode\n" " -s Certificate serial number (decimal)\n" " -w Write certificate in file\n" "\nOPTIONS for OPERATION getcrl are\n" " -k Signature private key file\n" " -l Signature local certificate file\n" " -O Certificate to get the CRL for (reads issuer and serial)\n" + " -P Provide password for batch mode\n" " -s Certificate serial number (decimal)\n" - " -w Write CRL in file\n\n", pname); + " -w Write CRL in file\n" + "\n\n" + "The parameter 'pwdesc' for the -P option is handled according to\n" + "https://www.openssl.org/docs/man3.0/man1/openssl-passphrase-options.html\n" + " - 'pass:' to provide it on the commandline (dangerous) or\n" + " - 'stdin' or 'fd:' or 'file:' to provide it via file or descriptor\n" + " - 'env:' take the password from the environment variable VAR.\n\n", pname); exit(0); }