1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

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
This commit is contained in:
Joe Orton
2018-07-06 12:01:29 +00:00
parent 1779ce853d
commit 45e3cf9511
3 changed files with 232 additions and 9 deletions

View File

@@ -1293,8 +1293,9 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
cert = NULL; cert = NULL;
if ((rv = modssl_load_engine_keypair(s, ptemp, engine_certfile, if ((rv = modssl_load_engine_keypair(s, ptemp, vhost_id,
keyfile, &cert, &pkey))) { engine_certfile, keyfile,
&cert, &pkey))) {
return rv; return rv;
} }

View File

@@ -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) #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, apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
const char *vhostid,
const char *certid, const char *keyid, const char *certid, const char *keyid,
X509 **pubkey, EVP_PKEY **privkey) X509 **pubkey, EVP_PKEY **privkey)
{ {
SSLModConfigRec *mc = myModConfig(s); SSLModConfigRec *mc = myModConfig(s);
ENGINE *e; 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) { if (!mc->szCryptoDevice) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131) 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); return ssl_die(s);
} }
/*
* Using the builtin OpenSSL UI only, for now...
*/
ui_method = UI_OpenSSL();
if (!(e = ENGINE_by_id(mc->szCryptoDevice))) { if (!(e = ENGINE_by_id(mc->szCryptoDevice))) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10132) ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10132)
"Init: Failed to load Crypto Device API `%s'", "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; *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) { if (*privkey == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10133) ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10133)
"Init: Unable to get the private key"); "Init: Unable to get the private key");

View File

@@ -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 * key returned as *pkey. certid can be NULL, in which case *pubkey
* is not altered. Errors logged on failure. */ * is not altered. Errors logged on failure. */
apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p, apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
const char *vhostid,
const char *certid, const char *keyid, const char *certid, const char *keyid,
X509 **pubkey, EVP_PKEY **privkey); X509 **pubkey, EVP_PKEY **privkey);