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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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");
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user