ASF Bugzilla – Attachment 20364 Details for
Bug 42687
Fully delegate certificate & key semantics to the SSLCryptoDevice
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Minimal support for (openssl) engine managed keys
engine_managed_keys_1-http_trunk_r547710.svn.diff.patch (text/plain), 17.19 KB, created by
Robin Bryce
on 2007-06-18 03:48:02 UTC
(
hide
)
Description:
Minimal support for (openssl) engine managed keys
Filename:
MIME Type:
Creator:
Robin Bryce
Created:
2007-06-18 03:48:02 UTC
Size:
17.19 KB
patch
obsolete
>Index: httpd-trunk/modules/ssl/ssl_private.h >=================================================================== >--- 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 *); >Index: httpd-trunk/modules/ssl/ssl_engine_init.c >=================================================================== >--- httpd-trunk/modules/ssl/ssl_engine_init.c (revision 547710) >+++ httpd-trunk/modules/ssl/ssl_engine_init.c (working copy) >@@ -51,7 +51,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 > */ >@@ -302,7 +425,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 +444,6 @@ > ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); > ssl_die(); > } >- >- ENGINE_free(e); > } > } > #endif >@@ -772,13 +893,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, >@@ -1270,6 +1403,11 @@ > ssl_init_ctx_cleanup_server(sc->server); > } > >+ /* >+ * Release the engine if there is one. >+ */ >+ ssl_ossle_release_engine(base_server); >+ > return APR_SUCCESS; > } > >Index: httpd-trunk/modules/ssl/ssl_engine_config.c >=================================================================== >--- 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: >Index: httpd-trunk/modules/ssl/ssl_engine_pphrase.c >=================================================================== >--- 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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 42687
: 20364