*) mod_ldap: Abort on LDAP locking errors. [Eric Covener]
- *) mod_ssl: Support loading private keys from an OpenSSL engine using a
- PKCS#11 URI. [Anderson Sasaki <ansasaki redhat.com>, Joe Orton]
+ *) mod_ssl: Support loading certificates and private keys from the
+ PKCS#11 OpenSSL engine. [Anderson Sasaki <ansasaki redhat.com>,
+ Joe Orton]
*) mod_slomem_shm: Handle a generation number when the slotmem size changes,
modifying the number of proxy balancers or balancer members on restart
<directivesynopsis>
<name>SSLCertificateFile</name>
-<description>Server PEM-encoded X.509 certificate data file</description>
-<syntax>SSLCertificateFile <var>file-path</var></syntax>
+<description>Server PEM-encoded X.509 certificate data file or token identifier</description>
+<syntax>SSLCertificateFile <var>file-path</var>|<var>certid</var></syntax>
<contextlist><context>server config</context>
<context>virtual host</context></contextlist>
+<compatibility><var>certid</var> available in 2.5.1 and later.</compatibility>
<usage>
<p>
-This directive points to a file with certificate data in PEM format.
-At a minimum, the file must include an end-entity (leaf) certificate.
+This directive points to a file with certificate data in PEM format, or the certificate identifier through a configured cryptographic token.
+If using a PEM file, at minimum, the file must include an end-entity (leaf) certificate.
The directive can be used multiple times (referencing different filenames)
to support multiple algorithms for server authentication - typically
RSA, DSA, and ECC. The number of supported algorithms depends on the
key is encrypted, the pass phrase dialog is forced at startup time.
</p>
+<p>As an alternative to storing certificates and private keys in
+files, a certificate identifier can be used to identify a certificate
+stored in a token. Currently, only <a
+href="https://tools.ietf.org/html/rfc7512">PKCS#11 URIs</a> are
+recognized as certificate identifiers, and can be used in conjunction
+with the OpenSSL <code>pkcs11</code> engine configured with <directive
+module="mod_ssl">SSLCryptoDevice</directive>. If <directive
+module="mod_ssl">SSLCertificateKeyFile</directive> is omitted, the
+certificate and private key can be loaded through the single
+identifier specified with <directive
+module="mod_ssl">SSLCertificateFile</directive>.</p>
+
<note>
<title>DH parameter interoperability with primes > 1024 bit</title>
<p>
<example><title>Example</title>
<highlight language="config">
+# Example using a PEM-encoded file.
SSLCertificateFile "/usr/local/apache2/conf/ssl.crt/server.crt"
+# Example use of a certificate and private key from a PKCS#11 token:
+SSLCryptoDevice pkcs11
+...
+SSLCertificateFile "pkcs11:token=My%20Token%20Name;id=45"
</highlight>
</example>
</usage>
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
const char *err;
- if ((err = ssl_cmd_check_file(cmd, &arg))) {
+ /* Only check for non-ENGINE based certs. */
+ if (!modssl_is_engine_id(arg)
+ && (err = ssl_cmd_check_file(cmd, &arg))) {
return err;
}
const char *err;
/* Check keyfile exists for non-ENGINE keys. */
- if (!modssl_is_engine_key(arg)
+ if (!modssl_is_engine_id(arg)
&& (err = ssl_cmd_check_file(cmd, &arg))) {
return err;
}
const char *));
i++) {
EVP_PKEY *pkey;
+ const char *engine_certfile = NULL;
key_id = apr_psprintf(ptemp, "%s:%d", vhost_id, i);
ERR_clear_error();
/* first the certificate (public key) */
- if (mctx->cert_chain) {
+ if (modssl_is_engine_id(certfile)) {
+ engine_certfile = certfile;
+ }
+ else if (mctx->cert_chain) {
if ((SSL_CTX_use_certificate_file(mctx->ssl_ctx, certfile,
SSL_FILETYPE_PEM) < 1)) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02561)
ERR_clear_error();
- if (modssl_is_engine_key(keyfile)) {
+ if (modssl_is_engine_id(keyfile)) {
apr_status_t rv;
- if ((rv = modssl_load_engine_pkey(s, ptemp, keyfile, &pkey))) {
+ cert = NULL;
+
+ if ((rv = modssl_load_engine_keypair(s, ptemp, engine_certfile,
+ keyfile, &cert, &pkey))) {
return rv;
}
+
+ if (cert) {
+ if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) < 1) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO()
+ "Failed to configure engine certificate %s, check %s",
+ key_id, certfile);
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+ return APR_EGENERAL;
+ }
+
+ /* SSL_CTX now owns the cert. */
+ X509_free(cert);
+ }
if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) < 1) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10130)
}
#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
-apr_status_t modssl_load_engine_pkey(server_rec *s, apr_pool_t *p,
- const char *keyid, EVP_PKEY **ppkey)
+apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
+ const char *certid, const char *keyid,
+ X509 **pubkey, EVP_PKEY **privkey)
{
SSLModConfigRec *mc = myModConfig(s);
- EVP_PKEY *pPrivateKey = NULL;
ENGINE *e;
UI_METHOD *ui_method;
if (APLOGdebug(s)) {
ENGINE_ctrl_cmd_string(e, "VERBOSE", NULL, 0);
}
-
- pPrivateKey = ENGINE_load_private_key(e, keyid, ui_method, NULL);
- if (pPrivateKey == NULL) {
+
+ if (certid) {
+ struct {
+ const char *cert_id;
+ X509 *cert;
+ } params = { certid, NULL };
+
+ if (!ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, ¶ms, NULL, 1)) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10136)
+ "Init: Unable to get the certificate");
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+ return ssl_die(s);
+ }
+
+ *pubkey = params.cert;
+ }
+
+ *privkey = ENGINE_load_private_key(e, keyid, ui_method, NULL);
+ if (*privkey == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10133)
"Init: Unable to get the private key");
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
return ssl_die(s);
}
- *ppkey = pPrivateKey;
-
ENGINE_free(e);
return APR_SUCCESS;
/** Pass Phrase Support */
apr_status_t ssl_load_encrypted_pkey(server_rec *, apr_pool_t *, int,
const char *, apr_array_header_t **);
-/* Load private key from the configured ENGINE, returned as **pkey.
- * Errors logged on failure. */
-apr_status_t modssl_load_engine_pkey(server_rec *s, apr_pool_t *p,
- const char *keyid, EVP_PKEY **ppkey);
+
+/* Load public and/or private key from the configured ENGINE. Private
+ * 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 *certid, const char *keyid,
+ X509 **pubkey, EVP_PKEY **privkey);
/** Diffie-Hellman Parameter Support */
DH *ssl_dh_GetParamFromFile(const char *);
int modssl_request_is_tls(const request_rec *r, SSLConnRec **sslconn);
/* Returns non-zero if the cert/key filename should be handled through
- * the configure ENGINE. */
-int modssl_is_engine_key(const char *name);
+ * the configured ENGINE. */
+int modssl_is_engine_id(const char *name);
#if HAVE_VALGRIND
extern int ssl_running_on_valgrind;
#endif /* #if APR_HAS_THREADS && MODSSL_USE_OPENSSL_PRE_1_1_API */
-int modssl_is_engine_key(const char *name)
+int modssl_is_engine_id(const char *name)
{
#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
/* ### Can handle any other special ENGINE key names here? */