</section>
<directivesynopsis>
-<name>SessionCryptoPassphrase</name>
-<description>The key used to encrypt the session</description>
-<syntax>SessionCryptoPassphrase <var>secret</var></syntax>
+<name>SessionCryptoDriver</name>
+<description>The crypto driver to be used to encrypt the session</description>
+<syntax>SessionCryptoDriver <var>name</var> <var>[param[=value]]</var></syntax>
<default>none</default>
<contextlist><context>server config</context>
-<context>virtual host</context>
-<context>directory</context>
-<context>.htaccess</context>
</contextlist>
<compatibility>Available in Apache 2.3.0 and later</compatibility>
<usage>
- <p>The <directive>SessionCryptoPassphrase</directive> directive specifies the key
- to be used to enable symmetrical encryption on the contents of the session before
- writing the session, or decrypting the contents of the session after reading the session.</p>
+ <p>The <directive>SessionCryptoDriver</directive> directive specifies the name of
+ the crypto driver to be used for encryption. If not specified, the driver defaults
+ to the recommended driver compiled into APR-util.</p>
- <p>Keys are more secure when they are long, and consist of truly random characters.
- Changing the key on a server has the effect of invalidating all existing sessions.</p>
+ <p>The <var>NSS</var> crypto driver requires some parameters for configuration,
+ which are specified as parameters with optional values after the driver name.</p>
- <p>If the <directive module="mod_session_crypto">SessionCryptoCertificateFile</directive>
- directive is set and asymmetrical encryption is enabled instead, the
- <directive module="mod_session_crypto">SessionCryptoPassphrase</directive> directive
- will be interpreted as the passphrase of the key, if the key is encrypted.</p>
+ <example><title>NSS without a certificate database</title>
+ SessionCryptoDriver nss
+ </example>
-</usage>
-</directivesynopsis>
+ <example><title>NSS with certificate database</title>
+ SessionCryptoDriver nss dir=certs
+ </example>
-<directivesynopsis>
-<name>SessionCryptoCertificateFile</name>
-<description>The certificate used to encrypt and decrypt the session</description>
-<syntax>SessionCryptoCertificateFile <var>file</var></syntax>
-<default>none</default>
-<contextlist><context>server config</context>
-<context>virtual host</context>
-<context>directory</context>
-<context>.htaccess</context>
-</contextlist>
-<compatibility>Available in Apache 2.3.0 and later</compatibility>
+ <example><title>NSS with certificate database and parameters</title>
+ SessionCryptoDriver nss dir=certs key3=key3.db cert7=cert7.db secmod=secmod
+ </example>
-<usage>
- <p>The <directive>SessionCryptoCertificateFile</directive> directive specifies the name
- of a certificate to be used to asymmetrically encrypt the contents of the session before
- writing the session, or decrypting the content of the session after reading the session.</p>
+ <p>The <var>NSS</var> crypto driver might have already been configured by another
+ part of the server, for example from <module name="mod_nns">mod_nss</module> or
+ <module name="mod_ldap">mod_ldap</module>. If found to have already been configured,
+ a warning will be logged, and the existing configuration will have taken affect.
+ To avoid this warning, use the noinit parameter as follows.</p>
- <p>Changing the certificate on a server has the effect of invalidating all existing
- sessions.</p>
+ <example><title>NSS with certificate database</title>
+ SessionCryptoDriver nss noinit
+ </example>
- <p>If the key associated with this certificate is protected with a passphrase, the
- <directive module="mod_session_crypto">SessionCryptoPassphrase</directive> directive
- will be interpreted as the passphrase to use to decrypt the key.</p>
+ <p>To prevent confusion, ensure that all modules requiring NSS are configured with
+ identical parameters.</p>
- <note type="warning"><title>Experimental</title>
- <p>This directive is dependent on experimental support for asymmetrical encryption
- support currently available in prerelease versions of OpenSSL, and will only be
- available on platforms that support it.</p>
- </note>
-
</usage>
</directivesynopsis>
<directivesynopsis>
-<name>SessionCryptoCertificateKeyFile</name>
-<description>The certificate key used to encrypt and decrypt the session</description>
-<syntax>SessionCryptoCertificateKeyFile <var>file</var></syntax>
+<name>SessionCryptoPassphrase</name>
+<description>The key used to encrypt the session</description>
+<syntax>SessionCryptoPassphrase <var>secret</var></syntax>
<default>none</default>
<contextlist><context>server config</context>
<context>virtual host</context>
<compatibility>Available in Apache 2.3.0 and later</compatibility>
<usage>
- <p>The <directive>SessionCryptoCertificateKeyFile</directive> directive specifies the name
- of a certificate key to be used alongside a certificate to encrypt the contents of the
- session before writing the session, or decrypting the content of the session after reading
- the session.</p>
-
- <p>Changing the certificate or key on a server has the effect of invalidating all existing
- sessions.</p>
+ <p>The <directive>SessionCryptoPassphrase</directive> directive specifies the key
+ to be used to enable symmetrical encryption on the contents of the session before
+ writing the session, or decrypting the contents of the session after reading the
+ session.</p>
- <p>If this key is protected with a passphrase, the
- <directive module="mod_session_crypto">SessionCryptoPassphrase</directive> directive
- will be interpreted as the passphrase to use to decrypt the key.</p>
+ <p>Keys are more secure when they are long, and consist of truly random characters.
+ Changing the key on a server has the effect of invalidating all existing sessions.</p>
- <note type="warning"><title>Experimental</title>
- <p>This directive is dependent on experimental support for asymmetrical encryption
- support currently available in prerelease versions of OpenSSL, and will only be
- available on platforms that support it.</p>
- </note>
+ <p>The cipher can be set to <var>3des192</var> or <var>aes256</var> using the
+ <var>cipher</var> parameter as per the example below. If not set, the cipher defaults
+ to <var>aes256</var>.</p>
-</usage>
-</directivesynopsis>
+ <example><title>Cipher</title>
+ SessionCryptoPassphrase secret cipher=aes256
+ </example>
-<directivesynopsis>
-<name>SessionCryptoCipher</name>
-<description>The name of the cipher to use during encryption / decryption</description>
-<syntax>SessionCryptoCipher <var>cipher</var></syntax>
-<default>AES256</default>
-<contextlist><context>server config</context>
-<context>virtual host</context>
-<context>directory</context>
-<context>.htaccess</context>
-</contextlist>
-<compatibility>Available in Apache 2.3.0 and later</compatibility>
+ <p>The <var>openssl</var> crypto driver supports an optional parameter to specify
+ the engine to be used for encryption.</p>
-<usage>
- <p>The <directive>SessionCryptoCipher</directive> directive specifies the name
- of the cipher to use during encryption. The ciphers available will depend on the
- underlying encryption toolkit on the server platform.</p>
-</usage>
-</directivesynopsis>
+ <example><title>OpenSSL with engine support</title>
+ SessionCryptoPassphrase secret engine=name
+ </example>
-<directivesynopsis>
-<name>SessionCryptoDigest</name>
-<description>The name of the digest to use during encryption / decryption</description>
-<syntax>SessionCryptoDigest <var>cipher</var></syntax>
-<default>SHA</default>
-<contextlist><context>server config</context>
-<context>virtual host</context>
-<context>directory</context>
-<context>.htaccess</context>
-</contextlist>
-<compatibility>Available in Apache 2.3.0 and later</compatibility>
-
-<usage>
- <p>The <directive>SessionCryptoDigest</directive> directive specifies the name
- of the digest to use during encryption. The list of digests available will depend
- on the underlying encryption toolkit on the server platform.</p>
-</usage>
-</directivesynopsis>
-
-<directivesynopsis>
-<name>SessionCryptoEngine</name>
-<description>The name of the engine to use during encryption / decryption</description>
-<syntax>SessionCryptoEngine <var>engine</var></syntax>
-<default>none</default>
-<contextlist><context>server config</context>
-<context>virtual host</context>
-<context>directory</context>
-<context>.htaccess</context>
-</contextlist>
-<compatibility>Available in Apache 2.3.0 and later</compatibility>
-
-<usage>
- <p>The <directive>SessionCryptoEngine</directive> directive specifies the name
- of the engine to use during encryption, depending on the capabilities of the
- underlying encryption toolkit on the server platform.</p>
</usage>
</directivesynopsis>
#include "mod_session.h"
#include "apu_version.h"
#include "apr_base64.h" /* for apr_base64_decode et al */
-#include "apr_ssl.h" /* for apr_*_encrypt et al */
#include "apr_lib.h"
#include "apr_strings.h"
#include "http_log.h"
+#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 4)
+
+#include "apr_crypto.h" /* for apr_*_crypt et al */
+
#define LOG_PREFIX "mod_session_crypto: "
-#define DEFAULT_CIPHER "AES256"
-#define DEFAULT_DIGEST "SHA"
module AP_MODULE_DECLARE_DATA session_crypto_module;
*/
typedef struct {
const char *passphrase;
+ apr_array_header_t *params;
int passphrase_set;
- const char *certfile;
- int certfile_set;
- const char *keyfile;
- int keyfile_set;
- const char *cipher;
+ apr_crypto_block_key_type_e cipher;
int cipher_set;
- const char *digest;
- int digest_set;
- const char *engine;
- int engine_set;
-} session_crypto_dir_conf;
+}session_crypto_dir_conf;
+
+/**
+ * Structure to carry the server wide session config.
+ */
+typedef struct {
+ const char *library;
+ apr_array_header_t *params;
+ const apr_crypto_driver_t *driver;
+ int library_set;
+ int noinit;
+ int noinit_set;
+}session_crypto_conf;
AP_DECLARE(int) ap_session_crypto_encode(request_rec * r, session_rec * z);
AP_DECLARE(int) ap_session_crypto_decode(request_rec * r, session_rec * z);
AP_DECLARE(int) ap_session_crypto_init(apr_pool_t *p, apr_pool_t *plog,
- apr_pool_t *ptemp, server_rec *s);
+ apr_pool_t *ptemp, server_rec *s);
/**
* Initialise the encryption as per the current config.
*
* Returns APR_SUCCESS if successful.
*/
-#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
-static apr_status_t crypt_init(request_rec * r, apr_evp_factory_t ** f, apr_evp_crypt_key_e * key, session_crypto_dir_conf * conf)
+static apr_status_t crypt_init(request_rec * r, apr_crypto_t **f, apr_crypto_key_t **key, apr_uuid_t *salt, apr_size_t *ivSize, session_crypto_conf * conf, session_crypto_dir_conf * dconf)
{
apr_status_t res;
- if (!conf->certfile_set && !conf->passphrase_set) {
+ if (!conf->driver) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, LOG_PREFIX
+ "encryption driver not configured, "
+ "no SessionCryptoLibrary set");
+ return APR_EGENERAL;
+ }
+
+ if (!dconf->passphrase_set) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, LOG_PREFIX
- "encryption not configured, "
- "no passphrase or certfile/keyfile set");
+ "encryption not configured, "
+ "no passphrase set");
return APR_EGENERAL;
}
/* set up */
- if (conf->certfile_set) {
- *key = APR_EVP_KEY_PUBLIC;
- res = apr_evp_factory_create(f, conf->keyfile, conf->certfile, NULL,
- conf->passphrase, conf->engine, conf->digest,
- APR_EVP_FACTORY_ASYM, r->pool);
- if (APR_ENOTIMPL == res) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "generic public/private key encryption is not supported by "
- "this version of APR. session encryption not possible");
- }
- }
- else {
- *key = APR_EVP_KEY_SYM;
- res = apr_evp_factory_create(f, NULL, NULL, conf->cipher,
- conf->passphrase, conf->engine, conf->digest,
- APR_EVP_FACTORY_SYM, r->pool);
- if (APR_ENOTIMPL == res) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "generic symmetrical encryption is not supported by this "
- "version of APR. session encryption not possible");
- }
- }
- if (APR_STATUS_IS_ENOCIPHER(res)) {
+ res = apr_crypto_factory(conf->driver, r->pool, dconf->params, f);
+ if (APR_ENOTIMPL == res) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "the cipher '%s' was not found", conf->cipher);
+ "generic symmetrical encryption is not supported by this "
+ "version of APR. session encryption not possible");
}
- if (APR_STATUS_IS_ENODIGEST(res)) {
+
+ if (APR_SUCCESS == res) {
+ res = apr_crypto_passphrase(conf->driver, r->pool, *f, dconf->passphrase,
+ strlen(dconf->passphrase),
+ (unsigned char *) salt, salt ? sizeof(apr_uuid_t) : 0, dconf->cipher,
+ MODE_CBC, 1, 4096, key, ivSize);
+ }
+
+ if (APR_STATUS_IS_ENOKEY(res)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "the digest '%s' was not found", conf->digest);
+ "the passphrase '%s' was empty", dconf->passphrase);
}
- if (APR_STATUS_IS_ENOCERT(res)) {
+ if (APR_STATUS_IS_EPADDING(res)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "the public and private key could not be extracted from "
- "the certificates");
+ "padding is not supported for cipher");
}
- if (APR_STATUS_IS_ENOENGINE(res)) {
+ if (APR_STATUS_IS_EKEYTYPE(res)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "the engine '%s' was not found", conf->engine);
+ "the key type is not known");
}
if (APR_SUCCESS != res) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "encryption could not be configured. Please check the "
- "certificates and/or passphrase as appropriate");
- apr_evp_factory_cleanup(*f);
+ "encryption could not be configured. Please check the "
+ "certificates and/or passphrase as appropriate");
return APR_EGENERAL;
}
return APR_SUCCESS;
}
-#endif
/**
* Encrypt the string given as per the current config.
*
* Returns APR_SUCCESS if successful.
*/
-static apr_status_t encrypt_string(request_rec * r, session_crypto_dir_conf *conf,
- const char *in, char **out)
+static apr_status_t encrypt_string(request_rec * r, session_crypto_conf *conf,
+ session_crypto_dir_conf *dconf,
+ const char *in, char **out)
{
-#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
apr_status_t res;
- apr_evp_factory_t *f = NULL;
- apr_evp_crypt_t *e = NULL;
- apr_evp_crypt_key_e key;
+ apr_crypto_t *f = NULL;
+ apr_crypto_key_t *key = NULL;
+ apr_size_t ivSize = 0;
+ apr_crypto_block_t *block = NULL;
unsigned char *encrypt = NULL;
+ unsigned char *combined = NULL;
apr_size_t encryptlen, tlen;
char *base64;
+ apr_size_t blockSize = 0;
+ const unsigned char *iv = NULL;
+ apr_uuid_t salt;
/* by default, return an empty string */
*out = "";
return APR_SUCCESS;
}
- res = crypt_init(r, &f, &key, conf);
+ /* use a uuid as a salt value, and prepend it to our result */
+ apr_uuid_get(&salt);
+ res = crypt_init(r, &f, &key, &salt, &ivSize, conf, dconf);
if (res != APR_SUCCESS) {
return res;
}
- res = apr_evp_crypt_init(f, &e, APR_EVP_ENCRYPT, key, r->pool);
+ res = apr_crypto_block_encrypt_init(conf->driver, r->pool, f, key, &iv, &block,
+ &blockSize);
if (APR_SUCCESS != res) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "encryption could be configured but not initialised");
- apr_evp_factory_cleanup(f);
+ "apr_crypto_block_encrypt_init failed");
return res;
}
/* encrypt the given string */
- res = apr_evp_crypt(e, &encrypt, &encryptlen, (unsigned char *) in, strlen(in));
+ res = apr_crypto_block_encrypt(conf->driver, block, &encrypt,
+ &encryptlen, (unsigned char *)in, strlen(in));
if (APR_SUCCESS != res) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "attempt to encrypt failed");
- apr_evp_factory_cleanup(f);
- apr_evp_crypt_cleanup(e);
+ "apr_crypto_block_encrypt failed");
return res;
}
- res = apr_evp_crypt_finish(e, encrypt + encryptlen, &tlen);
+ res = apr_crypto_block_encrypt_finish(conf->driver, block, encrypt + encryptlen,
+ &tlen);
if (APR_SUCCESS != res) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "attempt to finish the encryption failed");
- apr_evp_factory_cleanup(f);
- apr_evp_crypt_cleanup(e);
+ "apr_crypto_block_encrypt_finish failed");
return res;
}
encryptlen += tlen;
+ /* prepend the salt and the iv to the result */
+ combined = apr_palloc(r->pool, ivSize + encryptlen + sizeof(apr_uuid_t));
+ memcpy(combined, &salt, sizeof(apr_uuid_t));
+ memcpy(combined + sizeof(apr_uuid_t), iv, ivSize);
+ memcpy(combined + sizeof(apr_uuid_t) + ivSize, encrypt, encryptlen);
+
/* base64 encode the result */
- base64 = apr_pcalloc(r->pool, apr_base64_encode_len(encryptlen + 1) * sizeof(char));
- apr_base64_encode(base64, (const char *) encrypt, encryptlen);
+ base64 = apr_palloc(r->pool, apr_base64_encode_len(ivSize + encryptlen + sizeof(apr_uuid_t) + 1) * sizeof(char));
+ apr_base64_encode(base64, (const char *) combined, ivSize + encryptlen + sizeof(apr_uuid_t));
*out = base64;
- /* clean up afterwards */
- apr_evp_factory_cleanup(f);
- apr_evp_crypt_cleanup(e);
-
return res;
-#else
- ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_ENOTIMPL, r, LOG_PREFIX
- "crypto is not supported by APR on this platform");
- return APR_ENOTIMPL;
-#endif
}
/**
*
* Returns APR_SUCCESS if successful.
*/
-static apr_status_t decrypt_string(request_rec * r, session_crypto_dir_conf *conf,
- const char *in, char **out)
+static apr_status_t decrypt_string(request_rec * r, session_crypto_conf *conf,
+ session_crypto_dir_conf *dconf,
+ const char *in, char **out)
{
-#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
apr_status_t res;
- apr_evp_factory_t *f = NULL;
- apr_evp_crypt_t *e = NULL;
- apr_evp_crypt_key_e key;
+ apr_crypto_t *f = NULL;
+ apr_crypto_key_t *key = NULL;
+ apr_size_t ivSize = 0;
+ apr_crypto_block_t *block = NULL;
unsigned char *decrypted = NULL;
apr_size_t decryptedlen, tlen;
apr_size_t decodedlen;
char *decoded;
+ apr_size_t blockSize = 0;
- res = crypt_init(r, &f, &key, conf);
+ /* strip base64 from the string */
+ decoded = apr_palloc(r->pool, apr_base64_decode_len(in));
+ decodedlen = apr_base64_decode(decoded, in);
+ decoded[decodedlen] = '\0';
+
+ res = crypt_init(r, &f, &key, (apr_uuid_t *)decoded, &ivSize, conf, dconf);
if (res != APR_SUCCESS) {
return res;
}
- res = apr_evp_crypt_init(f, &e, APR_EVP_DECRYPT, key, r->pool);
+ /* bypass the salt at the start of the decoded block */
+ decoded += sizeof(apr_uuid_t);
+ decodedlen -= sizeof(apr_uuid_t);
+
+ res = apr_crypto_block_decrypt_init(conf->driver, r->pool, f, key, (unsigned char *)decoded, &block,
+ &blockSize);
if (APR_SUCCESS != res) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "decryption could be configured but not initialised");
- apr_evp_factory_cleanup(f);
+ "apr_crypto_block_decrypt_init failed");
return res;
}
- /* strip base64 from the string */
- decoded = apr_palloc(r->pool, apr_base64_decode_len(in));
- decodedlen = apr_base64_decode(decoded, in);
- decoded[decodedlen] = '\0';
+ /* bypass the iv at the start of the decoded block */
+ decoded += ivSize;
+ decodedlen -= ivSize;
/* decrypt the given string */
- res = apr_evp_crypt(e, &decrypted, &decryptedlen, (unsigned char *) decoded, decodedlen);
+ res = apr_crypto_block_decrypt(conf->driver, block, &decrypted,
+ &decryptedlen, (unsigned char *)decoded, decodedlen);
if (res) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "decrypt: attempt to decrypt failed");
- apr_evp_factory_cleanup(f);
- apr_evp_crypt_cleanup(e);
+ "apr_crypto_block_decrypt failed");
return res;
}
*out = (char *) decrypted;
- res = apr_evp_crypt_finish(e, decrypted + decryptedlen, &tlen);
+ res = apr_crypto_block_decrypt_finish(conf->driver, block, decrypted + decryptedlen,
+ &tlen);
if (APR_SUCCESS != res) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "attempt to finish the decryption failed");
- apr_evp_factory_cleanup(f);
- apr_evp_crypt_cleanup(e);
+ "apr_crypto_block_decrypt_finish failed");
return res;
}
decryptedlen += tlen;
return APR_SUCCESS;
-#else
- ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_ENOTIMPL, r, LOG_PREFIX
- "crypto is not supported by APR on this platform");
- return APR_ENOTIMPL;
-#endif
}
-
/**
* Crypto encoding for the session.
*
char *encoded = NULL;
apr_status_t res;
- session_crypto_dir_conf *conf = ap_get_module_config(r->per_dir_config,
- &session_crypto_module);
+ session_crypto_conf *conf = ap_get_module_config(r->server->module_config,
+ &session_crypto_module);
+ session_crypto_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
+ &session_crypto_module);
- if (conf->passphrase_set || conf->certfile_set) {
- res = encrypt_string(r, conf, z->encoded, &encoded);
+ if (dconf->passphrase_set) {
+ res = encrypt_string(r, conf, dconf, z->encoded, &encoded);
if (res != OK) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, LOG_PREFIX
- "encrypt session failed");
+ "encrypt session failed");
return res;
}
z->encoded = encoded;
char *encoded = NULL;
apr_status_t res;
- session_crypto_dir_conf *conf = ap_get_module_config(r->per_dir_config,
- &session_crypto_module);
+ session_crypto_conf *conf = ap_get_module_config(r->server->module_config,
+ &session_crypto_module);
+ session_crypto_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
+ &session_crypto_module);
- if ((conf->passphrase_set || conf->certfile_set) && z->encoded) {
- res = decrypt_string(r, conf, z->encoded, &encoded);
+ if ((dconf->passphrase_set) && z->encoded) {
+ res = decrypt_string(r, conf, dconf, z->encoded, &encoded);
if (res != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, LOG_PREFIX
- "decrypt session failed, wrong passphrase?");
+ "decrypt session failed, wrong passphrase?");
return res;
}
z->encoded = encoded;
* Initialise the SSL in the post_config hook.
*/
AP_DECLARE(int) ap_session_crypto_init(apr_pool_t *p, apr_pool_t *plog,
- apr_pool_t *ptemp, server_rec *s)
+ apr_pool_t *ptemp, server_rec *s)
{
- apr_ssl_init();
+ void *data;
+ const char *userdata_key = "session_crypto_init";
+
+ session_crypto_conf *conf = ap_get_module_config(s->module_config,
+ &session_crypto_module);
+
+ /* session_crypto_init() will be called twice. Don't bother
+ * going through all of the initialization on the first call
+ * because it will just be thrown away.*/
+ apr_pool_userdata_get(&data, userdata_key, s->process->pool);
+ if (!data) {
+ apr_pool_userdata_set((const void *)1, userdata_key,
+ apr_pool_cleanup_null, s->process->pool);
+ return OK;
+ }
+
+ if (conf->library) {
+
+ const apu_err_t *err = NULL;
+ apr_status_t rv;
+
+ rv = apr_crypto_init(p, NULL);
+ if (APR_SUCCESS != rv) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, LOG_PREFIX
+ "APR crypto could not be initialised");
+ return rv;
+ }
+
+ rv = apr_crypto_get_driver(p, conf->library, &conf->driver, conf->params, &err);
+ if (APR_EREINIT == rv) {
+ if (!conf->noinit) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, LOG_PREFIX
+ "warning: crypto for '%s' was already initialised, "
+ "using existing configuration", conf->library);
+ }
+ rv = APR_SUCCESS;
+ }
+ else {
+ if (conf->noinit) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, LOG_PREFIX
+ "warning: crypto for '%s' was not previously initialised "
+ "when it was expected to be, initialised instead by "
+ "mod_session_crypto", conf->library);
+ }
+ }
+ if (APR_SUCCESS != rv && err) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, LOG_PREFIX
+ "%s", err->msg);
+ return rv;
+ }
+ if (APR_ENOTIMPL == rv) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, LOG_PREFIX
+ "The crypto library '%s' could not be found",
+ conf->library);
+ return rv;
+ }
+ if (APR_SUCCESS != rv || !conf->driver) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, LOG_PREFIX
+ "The crypto library '%s' could not be loaded",
+ conf->library);
+ return rv;
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_INFO, rv, s, LOG_PREFIX
+ "The crypto library '%s' was loaded successfully",
+ conf->library);
+
+ }
+
return OK;
}
+static void *create_session_crypto_config(apr_pool_t * p, server_rec *s)
+{
+ session_crypto_conf *new =
+ (session_crypto_conf *) apr_pcalloc(p, sizeof(session_crypto_conf));
+
+ return (void *) new;
+}
+
+static void *merge_session_crypto_config(apr_pool_t * p, void *basev, void *addv)
+{
+ session_crypto_conf *new = (session_crypto_conf *) apr_pcalloc(p, sizeof(session_crypto_conf));
+ session_crypto_conf *add = (session_crypto_conf *) addv;
+ session_crypto_conf *base = (session_crypto_conf *) basev;
+
+ new->library = (add->library_set == 0) ? base->library : add->library;
+ new->params = (add->library_set == 0) ? base->params : add->params;
+ new->driver = (add->library_set == 0) ? base->driver : add->driver;
+ new->library_set = add->library_set || base->library_set;
+ new->noinit = (add->noinit_set == 0) ? base->noinit : add->noinit;
+ new->noinit_set = add->noinit_set || base->noinit_set;
+ return new;
+}
static void *create_session_crypto_dir_config(apr_pool_t * p, char *dummy)
{
(session_crypto_dir_conf *) apr_pcalloc(p, sizeof(session_crypto_dir_conf));
/* default cipher AES256-SHA */
- new->cipher = DEFAULT_CIPHER;
- new->digest = DEFAULT_DIGEST;
+ new->cipher = KEY_AES_256;
return (void *) new;
}
session_crypto_dir_conf *base = (session_crypto_dir_conf *) basev;
new->passphrase = (add->passphrase_set == 0) ? base->passphrase : add->passphrase;
+ new->params = (add->passphrase_set == 0) ? base->params : add->params;
new->passphrase_set = add->passphrase_set || base->passphrase_set;
- new->certfile = (add->certfile_set == 0) ? base->certfile : add->certfile;
- new->certfile_set = add->certfile_set || base->certfile_set;
- new->keyfile = (add->keyfile_set == 0) ? base->keyfile : add->keyfile;
- new->keyfile_set = add->keyfile_set || base->keyfile_set;
new->cipher = (add->cipher_set == 0) ? base->cipher : add->cipher;
new->cipher_set = add->cipher_set || base->cipher_set;
- new->digest = (add->digest_set == 0) ? base->digest : add->digest;
- new->digest_set = add->digest_set || base->digest_set;
- new->engine = (add->engine_set == 0) ? base->engine : add->engine;
- new->engine_set = add->engine_set || base->engine_set;
return new;
}
-static const char *check_file(cmd_parms * cmd, const char **file)
+static const char *set_crypto_driver(cmd_parms * cmd, void *config, const char *arg)
{
- apr_finfo_t finfo;
- const char *filepath = ap_server_root_relative(cmd->pool, *file);
-
- if (!filepath) {
- return apr_pstrcat(cmd->pool, cmd->directive->directive,
- ": Invalid file path ", *file, NULL);
- }
- if (apr_stat(&finfo, filepath,
- APR_FINFO_TYPE | APR_FINFO_SIZE, cmd->pool) != 0 ||
- finfo.filetype != APR_REG || finfo.size <= 0) {
- return apr_pstrcat(cmd->pool, cmd->directive->directive,
- ": File empty or missing ", *file, NULL);
+ char *word, *val;
+ int library_set = 0;
+ session_crypto_conf *conf =
+ (session_crypto_conf *)ap_get_module_config(cmd->server->module_config,
+ &session_crypto_module);
+ apr_crypto_param_t *param;
+ conf->params = apr_array_make(cmd->pool, 10, sizeof(apr_crypto_param_t));
+
+ while (*arg) {
+ word = ap_getword_conf(cmd->pool, &arg);
+ val = strchr(word, '=');
+ if (!val) {
+ if (!strcasecmp(word, "noinit")) {
+ conf->noinit = 1;
+ conf->noinit_set = 1;
+ }
+ else if (!library_set) {
+ conf->library = word;
+ conf->library_set = 1;
+ library_set = 1;
+ }
+ else {
+ return "Invalid SessionCryptoLibrary parameter. Parameter must "
+ "be in the form 'key=value'.";
+ }
+ }
+ else {
+ *val++ = '\0';
+ if (!strcasecmp(word, "dir")) {
+ param = apr_array_push(conf->params);
+ param->type = APR_CRYPTO_CA_TYPE_DIR;
+ param->path = val;
+ }
+ else if (!strcasecmp(word, "key3")) {
+ param = apr_array_push(conf->params);
+ param->type = APR_CRYPTO_CERT_TYPE_KEY3_DB;
+ param->path = val;
+ }
+ else if (!strcasecmp(word, "cert7")) {
+ param = apr_array_push(conf->params);
+ param->type = APR_CRYPTO_CA_TYPE_CERT7_DB;
+ param->path = val;
+ }
+ else if (!strcasecmp(word, "secmod")) {
+ param = apr_array_push(conf->params);
+ param->type = APR_CRYPTO_CA_TYPE_SECMOD;
+ param->path = val;
+ }
+ }
}
- *file = filepath;
-
- return NULL;
-}
-static const char *set_crypto_passphrase(cmd_parms * cmd, void *config, const char *passphrase)
-{
- session_crypto_dir_conf *conf = (session_crypto_dir_conf *) config;
- conf->passphrase = passphrase;
- conf->passphrase_set = 1;
return NULL;
}
-static const char *set_crypto_certificate_file(cmd_parms * cmd, void *config, const char *file)
+static const char *set_crypto_passphrase(cmd_parms * cmd, void *config, const char *arg)
{
- const char *res = check_file(cmd, &file);
- if (!res) {
- session_crypto_dir_conf *conf = (session_crypto_dir_conf *) config;
- conf->certfile = file;
- conf->certfile_set = 1;
+ char *word, *val;
+ int passphrase_set = 0;
+ session_crypto_dir_conf *dconf = (session_crypto_dir_conf *) config;
+ session_crypto_conf *conf =
+ (session_crypto_conf *)ap_get_module_config(cmd->server->module_config,
+ &session_crypto_module);
+ apr_crypto_param_t *param;
+ dconf->params = apr_array_make(cmd->pool, 10, sizeof(apr_crypto_param_t));
+
+ while (*arg) {
+ word = ap_getword_conf(cmd->pool, &arg);
+ val = strchr(word, '=');
+ if (!val) {
+ if (!passphrase_set) {
+ dconf->passphrase = word;
+ dconf->passphrase_set = 1;
+ passphrase_set = 1;
+ }
+ else {
+ return "Invalid SessionCryptoPassphrase parameter. Parameter must "
+ "be in the form 'key=value'.";
+ }
+ }
+ else {
+ *val++ = '\0';
+ if (!strcasecmp(word, "engine")) {
+ param = apr_array_push(dconf->params);
+ param->type = APR_CRYPTO_ENGINE;
+ param->path = val;
+ }
+ else if (!strcasecmp(word, "cipher")) {
+ if (!strcasecmp(val, "3des192")) {
+ dconf->cipher = KEY_3DES_192;
+ dconf->cipher_set = 1;
+ }
+ else if (!strcasecmp(val, "aes256")) {
+ dconf->cipher = KEY_AES_256;
+ dconf->cipher_set = 1;
+ }
+ else {
+ return "Invalid SessionCryptoPassphrase parameter. Cipher must "
+ "be '3des192' or 'aes256'.";
+ }
+ }
+ else {
+ return "Invalid SessionCryptoPassphrase parameter. Parameters must "
+ "be 'engine' or 'cipher'.";
+ }
+ }
}
- return res;
-}
-static const char *set_crypto_certificate_keyfile(cmd_parms * cmd, void *config, const char *file)
-{
- const char *res = check_file(cmd, &file);
- if (!res) {
- session_crypto_dir_conf *conf = (session_crypto_dir_conf *) config;
- conf->keyfile = file;
- conf->keyfile_set = 1;
+ /* if no library has been configured, set the recommended library
+ * as a sensible default.
+ */
+#ifdef APU_CRYPTO_RECOMMENDED_DRIVER
+ if (!conf->library) {
+ conf->library = APU_CRYPTO_RECOMMENDED_DRIVER;
}
- return res;
-}
-
-static const char *set_crypto_cipher(cmd_parms * cmd, void *config, const char *cipher)
-{
- session_crypto_dir_conf *conf = (session_crypto_dir_conf *) config;
- conf->cipher = cipher;
- conf->cipher_set = 1;
- return NULL;
-}
+#endif
-static const char *set_crypto_digest(cmd_parms * cmd, void *config, const char *digest)
-{
- session_crypto_dir_conf *conf = (session_crypto_dir_conf *) config;
- conf->digest = digest;
- conf->digest_set = 1;
return NULL;
}
-static const char *set_crypto_engine(cmd_parms * cmd, void *config, const char *engine)
-{
- session_crypto_dir_conf *conf = (session_crypto_dir_conf *) config;
- conf->engine = engine;
- conf->engine_set = 1;
- return NULL;
-}
-
-
static const command_rec session_crypto_cmds[] =
{
- AP_INIT_TAKE1("SessionCryptoPassphrase", set_crypto_passphrase, NULL, RSRC_CONF|OR_AUTHCFG,
- "The passphrase used to encrypt cookies"),
- AP_INIT_TAKE1("SessionCryptoCertificateFile", set_crypto_certificate_file, NULL, RSRC_CONF|OR_AUTHCFG,
- "The name of a certificate whose public key will be used to encrypt cookies"),
- AP_INIT_TAKE1("SessionCryptoCertificateKeyFile", set_crypto_certificate_keyfile, NULL, RSRC_CONF|OR_AUTHCFG,
- "The name of a private key which will be used to decrypt cookies"),
- AP_INIT_TAKE1("SessionCryptoCipher", set_crypto_cipher, NULL, RSRC_CONF|OR_AUTHCFG,
- "The cipher used to encrypt cookies. Defaults to " DEFAULT_CIPHER),
- AP_INIT_TAKE1("SessionCryptoDigest", set_crypto_digest, NULL, RSRC_CONF|OR_AUTHCFG,
- "The digest used to encrypt cookies. Defaults to " DEFAULT_DIGEST),
- AP_INIT_TAKE1("SessionCryptoEngine", set_crypto_engine, NULL, RSRC_CONF|OR_AUTHCFG,
- "The optional engine used to encrypt cookies, if supported by the underlying crypto "
- "toolkit"),
- {NULL}
+ AP_INIT_RAW_ARGS("SessionCryptoPassphrase", set_crypto_passphrase, NULL, RSRC_CONF|OR_AUTHCFG,
+ "The passphrase used to encrypt the session"),
+ AP_INIT_RAW_ARGS("SessionCryptoDriver", set_crypto_driver, NULL, RSRC_CONF,
+ "The underlying crypto library driver to use"),
+ { NULL}
};
static void register_hooks(apr_pool_t * p)
create_session_crypto_dir_config, /* dir config creater */
merge_session_crypto_dir_config, /* dir merger --- default is to
* override */
- NULL, /* server config */
- NULL, /* merge server config */
+ create_session_crypto_config, /* server config */
+ merge_session_crypto_config, /* merge server config */
session_crypto_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};
+
+#else
+#error session_crypto_module requires APR v1.4.0 or later
+#endif