mod_session_crypto.c revision bd0a4e219c3875862a01f7941d2eba6fa933d305
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mod_session.h"
#include "apu_version.h"
#include "apr_base64.h" /* for apr_base64_decode et al */
#include "apr_lib.h"
#include "apr_strings.h"
#include "http_log.h"
#elif APU_HAVE_CRYPTO == 0
#else
#include "apr_crypto.h" /* for apr_*_crypt et al */
#define LOG_PREFIX "mod_session_crypto: "
#define DRIVER_KEY "session_crypto_driver"
#define INIT_KEY "session_crypto_init"
/**
* Structure to carry the per-dir session config.
*/
typedef struct {
const char *passphrase;
int passphrase_set;
int cipher_set;
/**
* Structure to carry the server wide session config.
*/
typedef struct {
const char *library;
int library_set;
int noinit;
int noinit_set;
/**
* Initialise the encryption as per the current config.
*
* Returns APR_SUCCESS if successful.
*/
static apr_status_t crypt_init(request_rec * r, const apr_crypto_driver_t *driver, apr_crypto_t **f, apr_crypto_key_t **key, apr_uuid_t *salt, apr_size_t *ivSize, session_crypto_dir_conf * dconf)
{
if (!driver) {
"encryption driver not configured, "
"no SessionCryptoDriver set");
return APR_EGENERAL;
}
if (!dconf->passphrase_set) {
"encryption not configured, "
"no passphrase set");
return APR_EGENERAL;
}
/* set up */
if (APR_ENOTIMPL == res) {
"generic symmetrical encryption is not supported by this "
"version of APR. session encryption not possible");
}
if (APR_SUCCESS == res) {
}
if (APR_STATUS_IS_ENOKEY(res)) {
}
if (APR_STATUS_IS_EPADDING(res)) {
"padding is not supported for cipher");
}
if (APR_STATUS_IS_EKEYTYPE(res)) {
"the key type is not known");
}
if (APR_SUCCESS != res) {
"encryption could not be configured. Please check the "
return APR_EGENERAL;
}
return APR_SUCCESS;
}
/**
* Encrypt the string given as per the current config.
*
* Returns APR_SUCCESS if successful.
*/
{
apr_crypto_t *f = NULL;
apr_size_t ivSize = 0;
char *base64;
apr_size_t blockSize = 0;
/* by default, return an empty string */
*out = "";
/* don't attempt to encrypt an empty string, trying to do so causes a segfault */
return APR_SUCCESS;
}
/* use a uuid as a salt value, and prepend it to our result */
apr_uuid_get(&salt);
if (res != APR_SUCCESS) {
return res;
}
&blockSize);
if (APR_SUCCESS != res) {
"apr_crypto_block_encrypt_init failed");
return res;
}
/* encrypt the given string */
if (APR_SUCCESS != res) {
"apr_crypto_block_encrypt failed");
return res;
}
&tlen);
if (APR_SUCCESS != res) {
"apr_crypto_block_encrypt_finish failed");
return res;
}
encryptlen += tlen;
/* prepend the salt and the iv to the result */
/* base64 encode the result */
base64 = apr_palloc(r->pool, apr_base64_encode_len(ivSize + encryptlen + sizeof(apr_uuid_t) + 1) * sizeof(char));
return res;
}
/**
* Decrypt the string given as per the current config.
*
* Returns APR_SUCCESS if successful.
*/
{
apr_crypto_t *f = NULL;
apr_size_t ivSize = 0;
char *decoded;
apr_size_t blockSize = 0;
/* strip base64 from the string */
if (res != APR_SUCCESS) {
return res;
}
/* sanity check - decoded too short? */
"too short to decrypt, skipping");
return APR_ECRYPT;
}
/* bypass the salt at the start of the decoded block */
decoded += sizeof(apr_uuid_t);
decodedlen -= sizeof(apr_uuid_t);
&blockSize);
if (APR_SUCCESS != res) {
"apr_crypto_block_decrypt_init failed");
return res;
}
/* bypass the iv at the start of the decoded block */
decodedlen -= ivSize;
/* decrypt the given string */
if (res) {
"apr_crypto_block_decrypt failed");
return res;
}
&tlen);
if (APR_SUCCESS != res) {
"apr_crypto_block_decrypt_finish failed");
return res;
}
decryptedlen += tlen;
decrypted[decryptedlen] = 0;
return APR_SUCCESS;
}
/**
* Crypto encoding for the session.
*
* @param r The request pointer.
* @param z A pointer to where the session will be written.
*/
{
"encrypt session failed");
return res;
}
}
return OK;
}
/**
* Crypto decoding for the session.
*
* @param r The request pointer.
* @param z A pointer to where the session will be written.
*/
{
if (res != APR_SUCCESS) {
"decrypt session failed, wrong passphrase?");
return res;
}
}
return OK;
}
/**
* Initialise the SSL in the post_config hook.
*/
{
void *data;
/* 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.*/
if (!data) {
return OK;
}
if (APR_SUCCESS != rv) {
"APR crypto could not be initialised");
return rv;
}
if (APR_EREINIT == rv) {
"warning: crypto for '%s' was already initialised, "
}
rv = APR_SUCCESS;
}
else {
"warning: crypto for '%s' was not previously initialised "
"when it was expected to be, initialised instead by "
}
}
return rv;
}
if (APR_ENOTIMPL == rv) {
"The crypto library '%s' could not be found",
return rv;
}
"The crypto library '%s' could not be loaded",
return rv;
}
"The crypto library '%s' was loaded successfully",
}
return OK;
}
{
/* if no library has been configured, set the recommended library
* as a sensible default.
*/
#endif
return (void *) new;
}
{
/* default cipher AES256-SHA */
return (void *) new;
}
{
session_crypto_dir_conf *new = (session_crypto_dir_conf *) apr_pcalloc(p, sizeof(session_crypto_dir_conf));
return new;
}
{
int library_set = 0;
return err;
}
while (*arg) {
if (!val) {
}
else if (!library_set) {
library_set = 1;
}
else {
return "Invalid SessionCryptoDriver parameter. Parameter must "
"be in the form 'key=value'.";
}
}
else {
*val++ = '\0';
}
}
}
}
}
}
return NULL;
}
{
int passphrase_set = 0;
while (*arg) {
if (!val) {
if (!passphrase_set) {
passphrase_set = 1;
}
else {
return "Invalid SessionCryptoPassphrase parameter. Parameter must "
"be in the form 'key=value'.";
}
}
else {
*val++ = '\0';
}
}
}
else {
return "Invalid SessionCryptoPassphrase parameter. Cipher must "
"be '3des192' or 'aes256'.";
}
}
else {
return "Invalid SessionCryptoPassphrase parameter. Parameters must "
"be 'engine' or 'cipher'.";
}
}
}
return NULL;
}
static const command_rec session_crypto_cmds[] =
{
"The passphrase used to encrypt the session"),
"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 */
create_session_crypto_config, /* server config */
NULL, /* merge server config */
session_crypto_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};
#endif