--- httpd-trunk/modules/ssl/ssl_private.h (revision 547710) +++ httpd-trunk/modules/ssl/ssl_private.h (working copy) @@ -384,6 +384,7 @@ apr_hash_t *tPrivateKey; #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) const char *szCryptoDevice; + ENGINE *engine; #endif struct { void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10; @@ -550,6 +551,11 @@ *ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *); void ssl_init_Child(apr_pool_t *, server_rec *); apr_status_t ssl_init_ModuleKill(void *data); +#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) +void ssl_ossle_release_engine(server_rec *s); +ENGINE *ssl_ossle_get_engine(server_rec *s, const char* enginename, const char* opensslcnf, int disablecnf); +X509* ssl_ossle_load_cert_engine_pkcs11(server_rec *s, const char *identifier); +#endif /** Apache API hooks */ int ssl_hook_Auth(request_rec *); --- httpd-trunk/modules/ssl/ssl_engine_init.c (revision 547710) +++ httpd-trunk/modules/ssl/ssl_engine_init.c (working copy) @@ -35,6 +35,10 @@ */ +#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) +static void ssl_ossle_child_init(apr_pool_t *p, server_rec *base_server); +#endif + static void ssl_add_version_components(apr_pool_t *p, server_rec *s) { @@ -51,7 +55,130 @@ modver, AP_SERVER_BASEVERSION, incver); } +/* + * centralized engine loading & configuration + */ +#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) +void ssl_ossle_release_engine(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + if (!mc->engine) + return; + /* unload any dynamic engines pulled in by CONF_modules_load_file, + * but don't unload the built in engines */ + CONF_modules_unload(0); + + /* Releases all the references retained via ssl_ossl_get_engine */ + ENGINE_finish(mc->engine); + + mc->engine = 0; +} + +ENGINE * ssl_ossle_get_engine( + server_rec *s, + const char* enginename, + const char* opensslcnf, + int disablecnf) +{ + SSLModConfigRec *mc = myModConfig(s); + ENGINE *e = 0; + int conf_modules = 0; + int funct_ref = 0; + + if (mc->engine) { + return mc->engine; + } + + /* CONF_modules_load_file allows for the declaration of engine names, and + * associated parameters, in an openssl formated configuration file. + * opensslcnf may be NULL, in which case openssl's default cofniguration + * file is used automaticaly. (Eg, "/etc/ssl/openssl.cnf"). + * + * To completely disable openssl config processing pass NULL for + * `opensslcnf' and set `disablecnf' to any non zero value. */ + + if (!disablecnf && CONF_modules_load_file(opensslcnf, 0, 0) <= 0) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Failed to load openssl config file `%s'", + opensslcnf + ); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + goto x_fail; + } + if (!disablecnf) + conf_modules = 1; + + /* side effect: aquires an additional `structure ref' */ + e = ENGINE_by_id(enginename); + if (!e) + goto x_fail; + ENGINE_free(e); /* drop the struct_ref taken out by ENGINE_by_id */ + + /* Take out a functional reference, all user configuration is handled in + * openssl.cnf and is now complete, so ENGINE_init can succede if the + * chosen engine has been configured appropriately. */ + if (!(funct_ref = ENGINE_init(e))) + goto x_fail; + + /* Remove our engine from openssl's internal list and drop the associated + * reference. This means ENGINE_by_id will no longer succede and hence + * can't cause further reference counting hell. */ + if (!ENGINE_remove(e)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Failed to apply engine configuration `%s' `%s'", + enginename, opensslcnf + ); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + goto x_fail; + } + + mc->engine = e; + + return mc->engine; + +x_fail: + if (e) { + if (funct_ref) + ENGINE_finish(e); + } + if (conf_modules) { + /* unload any dynamic engines pulled in by CONF_modules_load_file, + * but don't unload the built in engines. */ + CONF_modules_unload(0); + } + + return NULL; +} + +/* ssl_ossle_load_cert_engine_pkcs11 + * + * This is specific to the engine_pkcs11 wrapper provided by the opensc + * project. more general support *is* possible but lets get some feed back + * before writing a tone of code. + */ +X509* ssl_ossle_load_cert_engine_pkcs11(server_rec *s, const char *identifier) +{ + int cmdno; + struct { + const char *identifier; + void *cert; + } param = {identifier, 0}; + + SSLModConfigRec *mc = myModConfig(s); + if (!mc->engine) + return NULL; + + cmdno = ENGINE_ctrl(mc->engine, + ENGINE_CTRL_GET_CMD_FROM_NAME, -1, "LOAD_CERT_CTRL", 0); + /* XXX: check the value of cmdno */ + ENGINE_ctrl(mc->engine, cmdno, -1, ¶m, 0); + + return (X509*)param.cert; +} +#endif + /* * Handle the Temporary RSA Keys and DH Params */ @@ -210,40 +337,33 @@ } + /* XXX: This part of the engine_managed_keys patch is *very* much + * in need of an additional config directive. Not all engine + * implementations are sensitive to the process context issues + * described in "Applications and processes" at p17 v2.20 6.6.1 + * of the PKCS #11 standard. + * + * In the interests of distilling the patch to its essentials whilst + * clearly highlighting the issues I have simply deleted the + * initialisation steps that have been moved to ssl_init_Child. The + * negative diffs in this function are those things that should be gated + * on SSLPKCS11ProcessModel or some equivalent. BUT NOTE that + * ssl_mutex_init has *not* been removed. It now comes just after + * ssl_util_thread_setup. + * + * The calls that have been moved are (in order): + * ssl_init_Engine + * ssl_rand_seed + * ssl_pphrase_Handle + * ssl_tmp_keys_init + * ssl_init_ConfigureServer (The whole "initialize servers" loop) + */ + #if APR_HAS_THREADS ssl_util_thread_setup(p); #endif /* - * SSL external crypto device ("engine") support - */ -#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) - ssl_init_Engine(base_server, p); -#endif - - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, - "Init: Initialized %s library", SSL_LIBRARY_NAME); - - /* - * Seed the Pseudo Random Number Generator (PRNG) - * only need ptemp here; nothing inside allocated from the pool - * needs to live once we return from ssl_rand_seed(). - */ - ssl_rand_seed(base_server, ptemp, SSL_RSCTX_STARTUP, "Init: "); - - /* - * read server private keys/public certs into memory. - * decrypting any encrypted keys via configured SSLPassPhraseDialogs - * anything that needs to live longer than ptemp needs to also survive - * restarts, in which case they'll live inside s->process->pool. - */ - ssl_pphrase_Handle(base_server, ptemp); - - if (ssl_tmp_keys_init(base_server)) { - return !OK; - } - - /* * initialize the mutex handling */ if (!ssl_mutex_init(base_server, p)) { @@ -256,26 +376,6 @@ ssl_scache_init(base_server, p); /* - * initialize servers - */ - ap_log_error(APLOG_MARK, APLOG_INFO, 0, base_server, - "Init: Initializing (virtual) servers for SSL"); - - for (s = base_server; s; s = s->next) { - sc = mySrvConfig(s); - /* - * Either now skip this server when SSL is disabled for - * it or give out some information about what we're - * configuring. - */ - - /* - * Read the server certificate and key - */ - ssl_init_ConfigureServer(s, p, ptemp, sc); - } - - /* * Configuration consistency checks */ ssl_init_CheckServers(base_server, ptemp); @@ -286,6 +386,11 @@ */ ssl_add_version_components(p, base_server); + + /* WRT engine_managed_keys: I'm not certain what to do about this + * particular piece of openssl nastiness. Ignoring it seems to works in + * my case. Thoughts anyone ? + */ SSL_init_app_data2_idx(); /* for SSL_get_app_data2() at request time */ return OK; @@ -302,7 +407,7 @@ ENGINE *e; if (mc->szCryptoDevice) { - if (!(e = ENGINE_by_id(mc->szCryptoDevice))) { + if (!(e = ssl_ossle_get_engine(s, mc->szCryptoDevice, NULL, 0))) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Init: Failed to load Crypto Device API `%s'", mc->szCryptoDevice); @@ -321,8 +426,6 @@ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); ssl_die(); } - - ENGINE_free(e); } } #endif @@ -772,13 +875,25 @@ "Configuring %s server private key", type); ptr = asn1->cpData; - if (!(pkey = d2i_PrivateKey(pkey_type, NULL, &ptr, asn1->nData))) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "Unable to import %s server private key", type); - ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); - ssl_die(); + if (!mc->engine) { + if (!(pkey = d2i_PrivateKey(pkey_type, NULL, &ptr, asn1->nData))) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Unable to import %s server private key", type); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } } + else { + /* cpData is a null terminated character string */ + if(!(pkey = ENGINE_load_private_key( + mc->engine, (char*)asn1->cpData, 0 /*ui_method*/, 0 /*cbdata*/))) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Unable to import (ENGINE) %s server private key", type); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + } if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) <= 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, @@ -1202,6 +1317,10 @@ /* open the mutex lockfile */ ssl_mutex_reinit(s, p); + +#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) + ssl_ossle_child_init(p, s); +#endif /*if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)*/ } #define MODSSL_CFG_ITEM_FREE(func, item) \ @@ -1242,34 +1361,139 @@ } } -apr_status_t ssl_init_ModuleKill(void *data) +#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) +static apr_status_t ssl_ossle_child_exit(server_rec* s) { - SSLSrvConfigRec *sc; - server_rec *base_server = (server_rec *)data; + SSLSrvConfigRec *sc = mySrvConfig(s); + SSLModConfigRec *mc = myModConfig(s); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Begin child process engine cleanup: pid=`%d' engine=`%s'", + mc->pid, mc->szCryptoDevice); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, s); + + ssl_tmp_keys_free(s); + ssl_init_ctx_cleanup_proxy(sc->proxy); + ssl_init_ctx_cleanup_server(sc->server); + EVP_cleanup(); + + ssl_ossle_release_engine(s); + + CRYPTO_cleanup_all_ex_data(); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Completed child process engine cleanup: pid=`%d' engine=`%s'", + mc->pid, mc->szCryptoDevice); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, s); + + return APR_SUCCESS; +} + +static apr_status_t ssl_child_exit(void *data) +{ + return ssl_ossle_child_exit((server_rec *)data); +} + +static void ssl_ossle_child_init(apr_pool_t *p, server_rec *base_server) +{ server_rec *s; + SSLSrvConfigRec *sc = mySrvConfig(base_server); + SSLModConfigRec *mc = myModConfig(base_server); + ENGINE *e; + apr_pool_t *ptemp; - /* - * Drop the session cache and mutex - */ - ssl_scache_kill(base_server); + /* XXX: TODO: some means to apply the pkcs11 rules only to those + * engine implementations that care. */ + if (!mc->szCryptoDevice) + return; - /* - * Destroy the temporary keys and params + if (mc->engine) { + /* Complain loudly, but don't die, if the parent process has + * initialized the engine. */ + ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, + "Init(child): Crypto Device API `%s' loaded by parent " + "process. This breaks pkcs11 rules (v 2.20 6.6.1). " + "Expect problems if your engine is wrapping a pkcs11 " + "implementation.", + mc->szCryptoDevice); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, base_server); + return; + } + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, base_server, + "Begin child process engine initialization: pid=`%d' engine=`%s'", + mc->pid, mc->szCryptoDevice); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, base_server); + + + apr_pool_create(&ptemp, p); + apr_pool_tag(ptemp, "ptemp"); + + if (!(e = ssl_ossle_get_engine(base_server, mc->szCryptoDevice, + NULL, 0))) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, + "Init(child): Failed to load Crypto Device API `%s'", + mc->szCryptoDevice); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, base_server); + ssl_die(); + } + if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, + "Init(child): Failed to enable Crypto Device API `%s'", + mc->szCryptoDevice); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, base_server); + ssl_die(); + } + + ssl_rand_seed(base_server, ptemp, SSL_RSCTX_STARTUP, "Init(child): "); + + /* XXX: This assumes the backend supporting the engine can deal sensibly + * with key import on behalf of a multi-process application. Ie, that + * it *won't* block the server to perform interactive auth each time + * a new child process goes through the ssl_pphrase_Handle dance. */ - ssl_tmp_keys_free(base_server); + ssl_pphrase_Handle(base_server, ptemp); - /* - * Free the non-pool allocated structures - * in the per-server configurations - */ + ssl_tmp_keys_init(base_server); + for (s = base_server; s; s = s->next) { sc = mySrvConfig(s); + ssl_init_ConfigureServer(s, p, ptemp, sc); + } + sc = mySrvConfig(base_server); + apr_pool_destroy(ptemp); - ssl_init_ctx_cleanup_proxy(sc->proxy); + /* ssl_child_exit handler to handle pkcs11 semantics for + * C_Initialize/C_Finalize */ + apr_pool_cleanup_register(p, base_server, ssl_child_exit, ssl_child_exit); - ssl_init_ctx_cleanup_server(sc->server); - } + ap_log_error(APLOG_MARK, APLOG_INFO, 0, base_server, + "Completed child process engine initialization: pid=`%d' engine=`%s'", + mc->pid, mc->szCryptoDevice); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, base_server); +} +#endif /*if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)*/ +apr_status_t ssl_init_ModuleKill(void *data) +{ + server_rec *base_server = (server_rec *)data; + + /* XXX: engine_managed_keys patch: The deletions in this function + * correspond to the similar deletions in ssl_init_Module and are subject + * to the same comments. + * + * The calls that have moved to the corresponding child cleanup are (in order): + * ssl_tmp_keys_free + * FOR EACH server, including the base_server: + * ssl_init_ctx_cleaup_proxy + * ssl_init_ctx_cleanup_server + */ + + /* + * Drop the session cache and mutex + */ + ssl_scache_kill(base_server); + return APR_SUCCESS; } --- httpd-trunk/modules/ssl/ssl_engine_config.c (revision 547710) +++ httpd-trunk/modules/ssl/ssl_engine_config.c (working copy) @@ -75,6 +75,7 @@ mc->tPublicCert = apr_hash_make(pool); #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) mc->szCryptoDevice = NULL; + mc->engine = NULL; #endif memset(mc->pTmpKeys, 0, sizeof(mc->pTmpKeys)); @@ -432,9 +433,15 @@ if (strcEQ(arg, "builtin")) { mc->szCryptoDevice = NULL; } - else if ((e = ENGINE_by_id(arg))) { + else if ((e = ssl_ossle_get_engine(cmd->server, arg, + NULL /*openssl.cnf*/, 0 /*disablecnf*/))) { mc->szCryptoDevice = arg; - ENGINE_free(e); + /* In order to more easily accommodate pkcs11's requirement of "one + * context per process", immediately unload the engine once we know the + * config argument is good. NOTE: `ENGINE_free' or `ENGINE_finish' are + * not thorough enough. + */ + ssl_ossle_release_engine(cmd->server); } else { err = "SSLCryptoDevice: Invalid argument; must be one of: " @@ -652,9 +659,16 @@ const char *err, *desc=NULL, **files=NULL; int i; + /* checking that arg is a file, that it exists, and is non empty is totally + * incompatible with hardware hosted keys. Unfortunately, because the order + * we will encounter SSLCryptoDevice vs the various SSLCertificate commands + * is indeterminate, I can see no obvious way to may this check work - + * order dependence and apache config appears to be a general malaise. */ +#if 0 if ((err = ssl_cmd_check_file(parms, &arg))) { return err; } +#endif switch (idx) { case SSL_AIDX_CERTS: --- httpd-trunk/modules/ssl/ssl_engine_pphrase.c (revision 547710) +++ httpd-trunk/modules/ssl/ssl_engine_pphrase.c (working copy) @@ -206,19 +206,48 @@ } else { apr_cpystrn(szPath, sc->server->pks->cert_files[i], sizeof(szPath)); - if ((rv = exists_and_readable(szPath, p, NULL)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "Init: Can't open server certificate file %s", - szPath); - ssl_die(); + + if (!mc->engine) { + if ((rv = exists_and_readable(szPath, p, NULL)) + != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Init: Can't open server certificate " + "file %s", szPath); + ssl_die(); + } + if ((pX509Cert = SSL_read_X509(szPath, NULL, NULL) + ) == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Unable to read server " + "certificate from file %s", szPath); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } } - if ((pX509Cert = SSL_read_X509(szPath, NULL, NULL)) == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "Init: Unable to read server certificate from" - " file %s", szPath); - ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); - ssl_die(); + else { + /* XXX: For backwards compat, and convenience for engine + * implementors, we should probably have a configurable + * means to say: "for these named engines, use apaches + * existing pem file support to load server keys and + * certificates", this patch treats all engines the same + * TODO: + * 1. explicit support for passing UI callbacks and + * data necessary for hardware that needs password entry, + * or other interactions, in order to load keys. It's a can + * of worms so I'm leaving it out for now. + * 2. Add at least "SSLCryptoDeviceLoadCertCmd" in order to + * enable a more general purpose implementation of engine + * based certificate loading. */ + pX509Cert = ssl_ossle_load_cert_engine_pkcs11(s, szPath); + if(!pX509Cert) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Unable to server certificate `%s' using " + "engine `%s'", + szPath, mc->szCryptoDevice + ); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } } } /* @@ -302,7 +331,7 @@ * the callback function which serves the pass * phrases to OpenSSL */ - if ((rv = exists_and_readable(szPath, p, + if (!mc->engine && (rv = exists_and_readable(szPath, p, &pkey_mtime)) != APR_SUCCESS ) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "Init: Can't open server private key file " @@ -357,10 +386,17 @@ * functions will fail spuriously if the error stack * is not empty. */ ERR_clear_error(); + if (!mc->engine) { + bReadable = ((pPrivateKey = SSL_read_PrivateKey(szPath, + NULL, ssl_pphrase_Handle_CB, s)) + != NULL ? TRUE : FALSE); + } + else { + pPrivateKey = ENGINE_load_private_key( + mc->engine, szPath, 0 /*ui_method*/, 0 /*cbdata*/); + bReadable = pPrivateKey != NULL ? TRUE : FALSE; + } - bReadable = ((pPrivateKey = SSL_read_PrivateKey(szPath, NULL, - ssl_pphrase_Handle_CB, s)) != NULL ? TRUE : FALSE); - /* * when the private key file now was readable, * it's fine and we go out of the loop @@ -451,12 +487,23 @@ } if (pPrivateKey == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "Init: Unable to read server private key from " - "file %s [Hint: Perhaps it is in a separate file? " - " See SSLCertificateKeyFile]", szPath); - ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); - ssl_die(); + if (!mc->engine) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Unable to read server private key from " + "file %s [Hint: Perhaps it is in a separate " + "file? See SSLCertificateKeyFile]", szPath); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + else { + /* log the error with clear indication that engine format + * keys are in play. */ + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Unable to load server private key " + "using the identifier `%s' and engine `%s'", + szPath, mc->szCryptoDevice); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + } } /* @@ -513,15 +560,33 @@ * RSA structure which do not survive DSO reloads!) */ cp = asn1_table_vhost_key(mc, p, cpVHostID, an); - length = i2d_PrivateKey(pPrivateKey, NULL); - ucp = ssl_asn1_table_set(mc->tPrivateKey, cp, length); - (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */ + if (!mc->engine) { + length = i2d_PrivateKey(pPrivateKey, NULL); + ucp = ssl_asn1_table_set(mc->tPrivateKey, cp, length); + /* 2nd arg increments */ + (void)i2d_PrivateKey(pPrivateKey, &ucp); - if (nPassPhraseDialogCur != 0) { - /* remember mtime of encrypted keys */ - asn1 = ssl_asn1_table_get(mc->tPrivateKey, cp); - asn1->source_mtime = pkey_mtime; + if (nPassPhraseDialogCur != 0) { + /* remember mtime of encrypted keys */ + asn1 = ssl_asn1_table_get(mc->tPrivateKey, cp); + asn1->source_mtime = pkey_mtime; + } } + else { /* mc->engine != 0 */ + /* the asn1 trick does not play well with hardware hosted + * keys. */ + length = strlen(szPath) + 1; + /* cpData is the key_id */ + ucp = ssl_asn1_table_set(mc->tPrivateKey, cp, length); + memcpy(ucp, szPath, length); + /* un-necessary, given we will reload, but retained for + * consistency. */ + if (nPassPhraseDialogCur != 0) { + /* remember mtime of encrypted keys */ + asn1 = ssl_asn1_table_get(mc->tPrivateKey, cp); + asn1->source_mtime = pkey_mtime; + } + } /* * Free the private key structure