summaryrefslogtreecommitdiffstats
path: root/modules/ssl
diff options
context:
space:
mode:
authorJoe Orton <jorton@apache.org>2018-07-06 14:01:29 +0200
committerJoe Orton <jorton@apache.org>2018-07-06 14:01:29 +0200
commit45e3cf951120b9db11280c7bbba50a839e237007 (patch)
treeed5796297b0b4935e81734f8b785a65d05f8a91f /modules/ssl
parentXML update. (diff)
downloadapache2-45e3cf951120b9db11280c7bbba50a839e237007.tar.xz
apache2-45e3cf951120b9db11280c7bbba50a839e237007.zip
Hook up PKCS#11 PIN entry through configured passphrase entry method.
* modules/ssl/ssl_engine_pphrase.c: Add wrappers for OpenSSL UI * API around passphrase entry. (modssl_load_engine_keypair): Take vhost ID and use above rather than default OpenSSL UI. * modules/ssl/ssl_engine_init.c (ssl_init_server_certs): Pass vhost ID. Submitted by: Anderson Sasaki<ansaski redhat.com>, jorton git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1835240 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/ssl')
-rw-r--r--modules/ssl/ssl_engine_init.c5
-rw-r--r--modules/ssl/ssl_engine_pphrase.c235
-rw-r--r--modules/ssl/ssl_private.h1
3 files changed, 232 insertions, 9 deletions
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index c8a3365e0c..be4184ff86 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -1293,8 +1293,9 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
cert = NULL;
- if ((rv = modssl_load_engine_keypair(s, ptemp, engine_certfile,
- keyfile, &cert, &pkey))) {
+ if ((rv = modssl_load_engine_keypair(s, ptemp, vhost_id,
+ engine_certfile, keyfile,
+ &cert, &pkey))) {
return rv;
}
diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c
index 85982c80c1..7688b2425c 100644
--- a/modules/ssl/ssl_engine_pphrase.c
+++ b/modules/ssl/ssl_engine_pphrase.c
@@ -588,13 +588,239 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
}
#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
+
+/* OpenSSL UI implementation for passphrase entry; largely duplicated
+ * from ssl_pphrase_Handle_CB but adjusted for UI API. TODO: Might be
+ * worth trying to shift pphrase handling over to the UI API
+ * completely. */
+static int passphrase_ui_open(UI *ui)
+{
+ pphrase_cb_arg_t *ppcb = UI_get0_user_data(ui);
+ SSLSrvConfigRec *sc = mySrvConfig(ppcb->s);
+
+ ppcb->nPassPhraseDialog++;
+ ppcb->nPassPhraseDialogCur++;
+
+ /*
+ * Builtin or Pipe dialog
+ */
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN
+ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
+ if (!readtty) {
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s,
+ APLOGNO()
+ "Init: Creating pass phrase dialog pipe child "
+ "'%s'", sc->server->pphrase_dialog_path);
+ if (ssl_pipe_child_create(ppcb->p,
+ sc->server->pphrase_dialog_path)
+ != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ppcb->s,
+ APLOGNO()
+ "Init: Failed to create pass phrase pipe '%s'",
+ sc->server->pphrase_dialog_path);
+ return 0;
+ }
+ }
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s, APLOGNO()
+ "Init: Requesting pass phrase via piped dialog");
+ }
+ else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
+#ifdef WIN32
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ppcb->s, APLOGNO()
+ "Init: Failed to create pass phrase pipe '%s'",
+ sc->server->pphrase_dialog_path);
+ return 0;
+#else
+ /*
+ * stderr has already been redirected to the error_log.
+ * rather than attempting to temporarily rehook it to the terminal,
+ * we print the prompt to stdout before EVP_read_pw_string turns
+ * off tty echo
+ */
+ apr_file_open_stdout(&writetty, ppcb->p);
+
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s, APLOGNO()
+ "Init: Requesting pass phrase via builtin terminal "
+ "dialog");
+#endif
+ }
+
+ /*
+ * The first time display a header to inform the user about what
+ * program he actually speaks to, which module is responsible for
+ * this terminal dialog and why to the hell he has to enter
+ * something...
+ */
+ if (ppcb->nPassPhraseDialog == 1) {
+ apr_file_printf(writetty, "%s mod_ssl (Pass Phrase Dialog)\n",
+ AP_SERVER_BASEVERSION);
+ apr_file_printf(writetty,
+ "A pass phrase is required to access the private key.\n");
+ }
+ if (ppcb->bPassPhraseDialogOnce) {
+ ppcb->bPassPhraseDialogOnce = FALSE;
+ apr_file_printf(writetty, "\n");
+ apr_file_printf(writetty, "Private key %s (%s)\n",
+ ppcb->key_id, ppcb->pkey_file);
+ }
+ }
+
+ return 1;
+}
+
+static int passphrase_ui_read(UI *ui, UI_STRING *uis)
+{
+ pphrase_cb_arg_t *ppcb = UI_get0_user_data(ui);
+ SSLSrvConfigRec *sc = mySrvConfig(ppcb->s);
+ const char *prompt;
+ int i;
+ int bufsize;
+ int len;
+ char *buf;
+
+ prompt = UI_get0_output_string(uis);
+ if (prompt == NULL) {
+ prompt = "Enter pass phrase:";
+ }
+
+ /*
+ * Get the maximum expected size and allocate the buffer
+ */
+ bufsize = UI_get_result_maxsize(uis);
+ buf = apr_pcalloc(ppcb->p, bufsize);
+
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN
+ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
+ /*
+ * Get the pass phrase through a callback.
+ * Empty input is not accepted.
+ */
+ for (;;) {
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
+ i = pipe_get_passwd_cb(buf, bufsize, "", FALSE);
+ }
+ else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
+ i = EVP_read_pw_string(buf, bufsize, "", FALSE);
+ }
+ if (i != 0) {
+ OPENSSL_cleanse(buf, bufsize);
+ return 0;
+ }
+ len = strlen(buf);
+ if (len < 1){
+ apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase"
+ "empty (needs to be at least 1 character).\n");
+ apr_file_puts(prompt, writetty);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ /*
+ * Filter program
+ */
+ else if (sc->server->pphrase_dialog_type == SSL_PPTYPE_FILTER) {
+ const char *cmd = sc->server->pphrase_dialog_path;
+ const char **argv = apr_palloc(ppcb->p, sizeof(char *) * 3);
+ char *result;
+
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s, APLOGNO()
+ "Init: Requesting pass phrase from dialog filter "
+ "program (%s)", cmd);
+
+ argv[0] = cmd;
+ argv[1] = ppcb->key_id;
+ argv[2] = NULL;
+
+ result = ssl_util_readfilter(ppcb->s, ppcb->p, cmd, argv);
+ apr_cpystrn(buf, result, bufsize);
+ len = strlen(buf);
+ }
+
+ /*
+ * Ok, we now have the pass phrase, so give it back
+ */
+ ppcb->cpPassPhraseCur = apr_pstrdup(ppcb->p, buf);
+ UI_set_result(ui, uis, buf);
+
+ /* Clear sensitive data. */
+ OPENSSL_cleanse(buf, bufsize);
+ return 1;
+}
+
+static int passphrase_ui_write(UI *ui, UI_STRING *uis)
+{
+ pphrase_cb_arg_t *ppcb = UI_get0_user_data(ui);
+ SSLSrvConfigRec *sc;
+ const char *prompt;
+
+ sc = mySrvConfig(ppcb->s);
+
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN
+ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
+ prompt = UI_get0_output_string(uis);
+ apr_file_puts(prompt, writetty);
+ }
+
+ return 1;
+}
+
+static int passphrase_ui_close(UI *ui)
+{
+ /*
+ * Close the pipes if they were opened
+ */
+ if (readtty) {
+ apr_file_close(readtty);
+ apr_file_close(writetty);
+ readtty = writetty = NULL;
+ }
+ return 1;
+}
+
+static apr_status_t pp_ui_method_cleanup(void *uip)
+{
+ UI_METHOD *uim = uip;
+
+ UI_destroy_method(uim);
+
+ return APR_SUCCESS;
+}
+
+static UI_METHOD *get_passphrase_ui(apr_pool_t *p)
+{
+ UI_METHOD *ui_method = UI_create_method("Passphrase UI");
+
+ UI_method_set_opener(ui_method, passphrase_ui_open);
+ UI_method_set_reader(ui_method, passphrase_ui_read);
+ UI_method_set_writer(ui_method, passphrase_ui_write);
+ UI_method_set_closer(ui_method, passphrase_ui_close);
+
+ apr_pool_cleanup_register(p, ui_method, pp_ui_method_cleanup,
+ pp_ui_method_cleanup);
+
+ return ui_method;
+}
+
+
apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
+ const char *vhostid,
const char *certid, const char *keyid,
X509 **pubkey, EVP_PKEY **privkey)
{
SSLModConfigRec *mc = myModConfig(s);
ENGINE *e;
- UI_METHOD *ui_method;
+ UI_METHOD *ui_method = get_passphrase_ui(p);
+ pphrase_cb_arg_t ppcb;
+
+ memset(&ppcb, 0, sizeof ppcb);
+ ppcb.s = s;
+ ppcb.p = p;
+ ppcb.bPassPhraseDialogOnce = TRUE;
+ ppcb.key_id = vhostid;
+ ppcb.pkey_file = keyid;
if (!mc->szCryptoDevice) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131)
@@ -603,11 +829,6 @@ apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
return ssl_die(s);
}
- /*
- * Using the builtin OpenSSL UI only, for now...
- */
- ui_method = UI_OpenSSL();
-
if (!(e = ENGINE_by_id(mc->szCryptoDevice))) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10132)
"Init: Failed to load Crypto Device API `%s'",
@@ -636,7 +857,7 @@ apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
*pubkey = params.cert;
}
- *privkey = ENGINE_load_private_key(e, keyid, ui_method, NULL);
+ *privkey = ENGINE_load_private_key(e, keyid, ui_method, &ppcb);
if (*privkey == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10133)
"Init: Unable to get the private key");
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index 1f629a46e3..8524c515ba 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -994,6 +994,7 @@ apr_status_t ssl_load_encrypted_pkey(server_rec *, apr_pool_t *, int,
* key returned as *pkey. certid can be NULL, in which case *pubkey
* is not altered. Errors logged on failure. */
apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
+ const char *vhostid,
const char *certid, const char *keyid,
X509 **pubkey, EVP_PKEY **privkey);