|
Packit |
90a5c9 |
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
Packit |
90a5c9 |
* contributor license agreements. See the NOTICE file distributed with
|
|
Packit |
90a5c9 |
* this work for additional information regarding copyright ownership.
|
|
Packit |
90a5c9 |
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
Packit |
90a5c9 |
* (the "License"); you may not use this file except in compliance with
|
|
Packit |
90a5c9 |
* the License. You may obtain a copy of the License at
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
90a5c9 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
90a5c9 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
90a5c9 |
* See the License for the specific language governing permissions and
|
|
Packit |
90a5c9 |
* limitations under the License.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "mod_session.h"
|
|
Packit |
90a5c9 |
#include "apu_version.h"
|
|
Packit |
90a5c9 |
#include "apr_base64.h" /* for apr_base64_decode et al */
|
|
Packit |
90a5c9 |
#include "apr_lib.h"
|
|
Packit |
90a5c9 |
#include "apr_md5.h"
|
|
Packit |
90a5c9 |
#include "apr_strings.h"
|
|
Packit |
90a5c9 |
#include "http_log.h"
|
|
Packit |
90a5c9 |
#include "http_core.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#if APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION < 4
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#error session_crypto_module requires APU v1.4.0 or later
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#elif APU_HAVE_CRYPTO == 0
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#error Crypto support must be enabled in APR
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#else
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "apr_crypto.h" /* for apr_*_crypt et al */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define CRYPTO_KEY "session_crypto_context"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
module AP_MODULE_DECLARE_DATA session_crypto_module;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Structure to carry the per-dir session config.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
apr_array_header_t *passphrases;
|
|
Packit |
90a5c9 |
int passphrases_set;
|
|
Packit |
90a5c9 |
const char *cipher;
|
|
Packit |
90a5c9 |
int cipher_set;
|
|
Packit |
90a5c9 |
} session_crypto_dir_conf;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Structure to carry the server wide session config.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
const char *library;
|
|
Packit |
90a5c9 |
const char *params;
|
|
Packit |
90a5c9 |
int library_set;
|
|
Packit |
90a5c9 |
} session_crypto_conf;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Wrappers around apr_siphash24() and apr_crypto_equals(),
|
|
Packit |
90a5c9 |
* available in APU-1.6/APR-2.0 only.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 6)
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "apr_siphash.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define AP_SIPHASH_DSIZE APR_SIPHASH_DSIZE
|
|
Packit |
90a5c9 |
#define AP_SIPHASH_KSIZE APR_SIPHASH_KSIZE
|
|
Packit |
90a5c9 |
#define ap_siphash24_auth apr_siphash24_auth
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define ap_crypto_equals apr_crypto_equals
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#else
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define AP_SIPHASH_DSIZE 8
|
|
Packit |
90a5c9 |
#define AP_SIPHASH_KSIZE 16
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define U8TO64_LE(p) \
|
|
Packit |
90a5c9 |
(((apr_uint64_t)((p)[0]) ) | \
|
|
Packit |
90a5c9 |
((apr_uint64_t)((p)[1]) << 8) | \
|
|
Packit |
90a5c9 |
((apr_uint64_t)((p)[2]) << 16) | \
|
|
Packit |
90a5c9 |
((apr_uint64_t)((p)[3]) << 24) | \
|
|
Packit |
90a5c9 |
((apr_uint64_t)((p)[4]) << 32) | \
|
|
Packit |
90a5c9 |
((apr_uint64_t)((p)[5]) << 40) | \
|
|
Packit |
90a5c9 |
((apr_uint64_t)((p)[6]) << 48) | \
|
|
Packit |
90a5c9 |
((apr_uint64_t)((p)[7]) << 56))
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define U64TO8_LE(p, v) \
|
|
Packit |
90a5c9 |
do { \
|
|
Packit |
90a5c9 |
(p)[0] = (unsigned char)((v) ); \
|
|
Packit |
90a5c9 |
(p)[1] = (unsigned char)((v) >> 8); \
|
|
Packit |
90a5c9 |
(p)[2] = (unsigned char)((v) >> 16); \
|
|
Packit |
90a5c9 |
(p)[3] = (unsigned char)((v) >> 24); \
|
|
Packit |
90a5c9 |
(p)[4] = (unsigned char)((v) >> 32); \
|
|
Packit |
90a5c9 |
(p)[5] = (unsigned char)((v) >> 40); \
|
|
Packit |
90a5c9 |
(p)[6] = (unsigned char)((v) >> 48); \
|
|
Packit |
90a5c9 |
(p)[7] = (unsigned char)((v) >> 56); \
|
|
Packit |
90a5c9 |
} while (0)
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define SIPROUND() \
|
|
Packit |
90a5c9 |
do { \
|
|
Packit |
90a5c9 |
v0 += v1; v1=ROTL64(v1,13); v1 ^= v0; v0=ROTL64(v0,32); \
|
|
Packit |
90a5c9 |
v2 += v3; v3=ROTL64(v3,16); v3 ^= v2; \
|
|
Packit |
90a5c9 |
v0 += v3; v3=ROTL64(v3,21); v3 ^= v0; \
|
|
Packit |
90a5c9 |
v2 += v1; v1=ROTL64(v1,17); v1 ^= v2; v2=ROTL64(v2,32); \
|
|
Packit |
90a5c9 |
} while(0)
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_uint64_t ap_siphash24(const void *src, apr_size_t len,
|
|
Packit |
90a5c9 |
const unsigned char key[AP_SIPHASH_KSIZE])
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const unsigned char *ptr, *end;
|
|
Packit |
90a5c9 |
apr_uint64_t v0, v1, v2, v3, m;
|
|
Packit |
90a5c9 |
apr_uint64_t k0, k1;
|
|
Packit |
90a5c9 |
unsigned int rem;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
k0 = U8TO64_LE(key + 0);
|
|
Packit |
90a5c9 |
k1 = U8TO64_LE(key + 8);
|
|
Packit |
90a5c9 |
v3 = k1 ^ (apr_uint64_t)0x7465646279746573ULL;
|
|
Packit |
90a5c9 |
v2 = k0 ^ (apr_uint64_t)0x6c7967656e657261ULL;
|
|
Packit |
90a5c9 |
v1 = k1 ^ (apr_uint64_t)0x646f72616e646f6dULL;
|
|
Packit |
90a5c9 |
v0 = k0 ^ (apr_uint64_t)0x736f6d6570736575ULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rem = (unsigned int)(len & 0x7);
|
|
Packit |
90a5c9 |
for (ptr = src, end = ptr + len - rem; ptr < end; ptr += 8) {
|
|
Packit |
90a5c9 |
m = U8TO64_LE(ptr);
|
|
Packit |
90a5c9 |
v3 ^= m;
|
|
Packit |
90a5c9 |
SIPROUND();
|
|
Packit |
90a5c9 |
SIPROUND();
|
|
Packit |
90a5c9 |
v0 ^= m;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
m = (apr_uint64_t)(len & 0xff) << 56;
|
|
Packit |
90a5c9 |
switch (rem) {
|
|
Packit |
90a5c9 |
case 7: m |= (apr_uint64_t)ptr[6] << 48;
|
|
Packit |
90a5c9 |
case 6: m |= (apr_uint64_t)ptr[5] << 40;
|
|
Packit |
90a5c9 |
case 5: m |= (apr_uint64_t)ptr[4] << 32;
|
|
Packit |
90a5c9 |
case 4: m |= (apr_uint64_t)ptr[3] << 24;
|
|
Packit |
90a5c9 |
case 3: m |= (apr_uint64_t)ptr[2] << 16;
|
|
Packit |
90a5c9 |
case 2: m |= (apr_uint64_t)ptr[1] << 8;
|
|
Packit |
90a5c9 |
case 1: m |= (apr_uint64_t)ptr[0];
|
|
Packit |
90a5c9 |
case 0: break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
v3 ^= m;
|
|
Packit |
90a5c9 |
SIPROUND();
|
|
Packit |
90a5c9 |
SIPROUND();
|
|
Packit |
90a5c9 |
v0 ^= m;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
v2 ^= 0xff;
|
|
Packit |
90a5c9 |
SIPROUND();
|
|
Packit |
90a5c9 |
SIPROUND();
|
|
Packit |
90a5c9 |
SIPROUND();
|
|
Packit |
90a5c9 |
SIPROUND();
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return v0 ^ v1 ^ v2 ^ v3;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void ap_siphash24_auth(unsigned char out[AP_SIPHASH_DSIZE],
|
|
Packit |
90a5c9 |
const void *src, apr_size_t len,
|
|
Packit |
90a5c9 |
const unsigned char key[AP_SIPHASH_KSIZE])
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_uint64_t h;
|
|
Packit |
90a5c9 |
h = ap_siphash24(src, len, key);
|
|
Packit |
90a5c9 |
U64TO8_LE(out, h);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int ap_crypto_equals(const void *buf1, const void *buf2,
|
|
Packit |
90a5c9 |
apr_size_t size)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const unsigned char *p1 = buf1;
|
|
Packit |
90a5c9 |
const unsigned char *p2 = buf2;
|
|
Packit |
90a5c9 |
unsigned char diff = 0;
|
|
Packit |
90a5c9 |
apr_size_t i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (i = 0; i < size; ++i) {
|
|
Packit |
90a5c9 |
diff |= p1[i] ^ p2[i];
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return 1 & ((diff - 1) >> 8);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void compute_auth(const void *src, apr_size_t len,
|
|
Packit |
90a5c9 |
const char *passphrase, apr_size_t passlen,
|
|
Packit |
90a5c9 |
unsigned char auth[AP_SIPHASH_DSIZE])
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
unsigned char key[APR_MD5_DIGESTSIZE];
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* XXX: if we had a way to get the raw bytes from an apr_crypto_key_t
|
|
Packit |
90a5c9 |
* we could use them directly (not available in APR-1.5.x).
|
|
Packit |
90a5c9 |
* MD5 is 128bit too, so use it to get a suitable siphash key
|
|
Packit |
90a5c9 |
* from the passphrase.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_md5(key, passphrase, passlen);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_siphash24_auth(auth, src, len, key);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Initialise the encryption as per the current config.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Returns APR_SUCCESS if successful.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t crypt_init(request_rec *r,
|
|
Packit |
90a5c9 |
const apr_crypto_t *f, apr_crypto_block_key_type_e **cipher,
|
|
Packit |
90a5c9 |
session_crypto_dir_conf * dconf)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t res;
|
|
Packit |
90a5c9 |
apr_hash_t *ciphers;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
res = apr_crypto_get_block_key_types(&ciphers, f);
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != res) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01823)
|
|
Packit |
90a5c9 |
"no ciphers returned by APR. "
|
|
Packit |
90a5c9 |
"session encryption not possible");
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
*cipher = apr_hash_get(ciphers, dconf->cipher, APR_HASH_KEY_STRING);
|
|
Packit |
90a5c9 |
if (!(*cipher)) {
|
|
Packit |
90a5c9 |
apr_hash_index_t *hi;
|
|
Packit |
90a5c9 |
const void *key;
|
|
Packit |
90a5c9 |
apr_ssize_t klen;
|
|
Packit |
90a5c9 |
int sum = 0;
|
|
Packit |
90a5c9 |
int offset = 0;
|
|
Packit |
90a5c9 |
char *options = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (hi = apr_hash_first(r->pool, ciphers); hi; hi = apr_hash_next(hi)) {
|
|
Packit |
90a5c9 |
apr_hash_this(hi, NULL, &klen, NULL);
|
|
Packit |
90a5c9 |
sum += klen + 2;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
for (hi = apr_hash_first(r->pool, ciphers); hi; hi = apr_hash_next(hi)) {
|
|
Packit |
90a5c9 |
apr_hash_this(hi, &key, &klen, NULL);
|
|
Packit |
90a5c9 |
if (!options) {
|
|
Packit |
90a5c9 |
options = apr_palloc(r->pool, sum + 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
options[offset++] = ',';
|
|
Packit |
90a5c9 |
options[offset++] = ' ';
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
strncpy(options + offset, key, klen);
|
|
Packit |
90a5c9 |
offset += klen;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
options[offset] = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01824)
|
|
Packit |
90a5c9 |
"cipher '%s' not recognised by crypto driver. "
|
|
Packit |
90a5c9 |
"session encryption not possible, options: %s", dconf->cipher, options);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Encrypt the string given as per the current config.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Returns APR_SUCCESS if successful.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t encrypt_string(request_rec * r, const apr_crypto_t *f,
|
|
Packit |
90a5c9 |
session_crypto_dir_conf *dconf, const char *in, char **out)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t res;
|
|
Packit |
90a5c9 |
apr_crypto_key_t *key = NULL;
|
|
Packit |
90a5c9 |
apr_size_t ivSize = 0;
|
|
Packit |
90a5c9 |
apr_crypto_block_t *block = NULL;
|
|
Packit |
90a5c9 |
unsigned char *encrypt = NULL;
|
|
Packit |
90a5c9 |
unsigned char *combined = NULL;
|
|
Packit |
90a5c9 |
apr_size_t encryptlen, tlen, combinedlen;
|
|
Packit |
90a5c9 |
char *base64;
|
|
Packit |
90a5c9 |
apr_size_t blockSize = 0;
|
|
Packit |
90a5c9 |
const unsigned char *iv = NULL;
|
|
Packit |
90a5c9 |
apr_uuid_t salt;
|
|
Packit |
90a5c9 |
apr_crypto_block_key_type_e *cipher;
|
|
Packit |
90a5c9 |
const char *passphrase;
|
|
Packit |
90a5c9 |
apr_size_t passlen;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* use a uuid as a salt value, and prepend it to our result */
|
|
Packit |
90a5c9 |
apr_uuid_get(&salt);
|
|
Packit |
90a5c9 |
res = crypt_init(r, f, &cipher, dconf);
|
|
Packit |
90a5c9 |
if (res != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* encrypt using the first passphrase in the list */
|
|
Packit |
90a5c9 |
passphrase = APR_ARRAY_IDX(dconf->passphrases, 0, const char *);
|
|
Packit |
90a5c9 |
passlen = strlen(passphrase);
|
|
Packit |
90a5c9 |
res = apr_crypto_passphrase(&key, &ivSize, passphrase, passlen,
|
|
Packit |
90a5c9 |
(unsigned char *) (&salt), sizeof(apr_uuid_t),
|
|
Packit |
90a5c9 |
*cipher, APR_MODE_CBC, 1, 4096, f, r->pool);
|
|
Packit |
90a5c9 |
if (APR_STATUS_IS_ENOKEY(res)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01825)
|
|
Packit |
90a5c9 |
"the passphrase '%s' was empty", passphrase);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (APR_STATUS_IS_EPADDING(res)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01826)
|
|
Packit |
90a5c9 |
"padding is not supported for cipher");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (APR_STATUS_IS_EKEYTYPE(res)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01827)
|
|
Packit |
90a5c9 |
"the key type is not known");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != res) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01828)
|
|
Packit |
90a5c9 |
"encryption could not be configured.");
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
res = apr_crypto_block_encrypt_init(&block, &iv, key, &blockSize, r->pool);
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != res) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01829)
|
|
Packit |
90a5c9 |
"apr_crypto_block_encrypt_init failed");
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* encrypt the given string */
|
|
Packit |
90a5c9 |
res = apr_crypto_block_encrypt(&encrypt, &encryptlen,
|
|
Packit |
90a5c9 |
(const unsigned char *)in, strlen(in),
|
|
Packit |
90a5c9 |
block);
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != res) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01830)
|
|
Packit |
90a5c9 |
"apr_crypto_block_encrypt failed");
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
res = apr_crypto_block_encrypt_finish(encrypt + encryptlen, &tlen, block);
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != res) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01831)
|
|
Packit |
90a5c9 |
"apr_crypto_block_encrypt_finish failed");
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
encryptlen += tlen;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* prepend the salt and the iv to the result (keep room for the MAC) */
|
|
Packit |
90a5c9 |
combinedlen = AP_SIPHASH_DSIZE + sizeof(apr_uuid_t) + ivSize + encryptlen;
|
|
Packit |
90a5c9 |
combined = apr_palloc(r->pool, combinedlen);
|
|
Packit |
90a5c9 |
memcpy(combined + AP_SIPHASH_DSIZE, &salt, sizeof(apr_uuid_t));
|
|
Packit |
90a5c9 |
memcpy(combined + AP_SIPHASH_DSIZE + sizeof(apr_uuid_t), iv, ivSize);
|
|
Packit |
90a5c9 |
memcpy(combined + AP_SIPHASH_DSIZE + sizeof(apr_uuid_t) + ivSize,
|
|
Packit |
90a5c9 |
encrypt, encryptlen);
|
|
Packit |
90a5c9 |
/* authenticate the whole salt+IV+ciphertext with a leading MAC */
|
|
Packit |
90a5c9 |
compute_auth(combined + AP_SIPHASH_DSIZE, combinedlen - AP_SIPHASH_DSIZE,
|
|
Packit |
90a5c9 |
passphrase, passlen, combined);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* base64 encode the result (APR handles the trailing '\0') */
|
|
Packit |
90a5c9 |
base64 = apr_palloc(r->pool, apr_base64_encode_len(combinedlen));
|
|
Packit |
90a5c9 |
apr_base64_encode(base64, (const char *) combined, combinedlen);
|
|
Packit |
90a5c9 |
*out = base64;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Decrypt the string given as per the current config.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Returns APR_SUCCESS if successful.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t decrypt_string(request_rec * r, const apr_crypto_t *f,
|
|
Packit |
90a5c9 |
session_crypto_dir_conf *dconf, const char *in, char **out)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t res;
|
|
Packit |
90a5c9 |
apr_crypto_key_t *key = NULL;
|
|
Packit |
90a5c9 |
apr_size_t ivSize = 0;
|
|
Packit |
90a5c9 |
apr_crypto_block_t *block = NULL;
|
|
Packit |
90a5c9 |
unsigned char *decrypted = NULL;
|
|
Packit |
90a5c9 |
apr_size_t decryptedlen, tlen;
|
|
Packit |
90a5c9 |
apr_size_t decodedlen;
|
|
Packit |
90a5c9 |
char *decoded;
|
|
Packit |
90a5c9 |
apr_size_t blockSize = 0;
|
|
Packit |
90a5c9 |
apr_crypto_block_key_type_e *cipher;
|
|
Packit |
90a5c9 |
unsigned char auth[AP_SIPHASH_DSIZE];
|
|
Packit |
90a5c9 |
int i = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* strip base64 from the string */
|
|
Packit |
90a5c9 |
decoded = apr_palloc(r->pool, apr_base64_decode_len(in));
|
|
Packit |
90a5c9 |
decodedlen = apr_base64_decode(decoded, in);
|
|
Packit |
90a5c9 |
decoded[decodedlen] = '\0';
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* sanity check - decoded too short? */
|
|
Packit |
90a5c9 |
if (decodedlen < (AP_SIPHASH_DSIZE + sizeof(apr_uuid_t))) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(10005)
|
|
Packit |
90a5c9 |
"too short to decrypt, aborting");
|
|
Packit |
90a5c9 |
return APR_ECRYPT;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
res = crypt_init(r, f, &cipher, dconf);
|
|
Packit |
90a5c9 |
if (res != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* try each passphrase in turn */
|
|
Packit |
90a5c9 |
for (; i < dconf->passphrases->nelts; i++) {
|
|
Packit |
90a5c9 |
const char *passphrase = APR_ARRAY_IDX(dconf->passphrases, i, char *);
|
|
Packit |
90a5c9 |
apr_size_t passlen = strlen(passphrase);
|
|
Packit |
90a5c9 |
apr_size_t len = decodedlen - AP_SIPHASH_DSIZE;
|
|
Packit |
90a5c9 |
unsigned char *slider = (unsigned char *)decoded + AP_SIPHASH_DSIZE;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Verify authentication of the whole salt+IV+ciphertext by computing
|
|
Packit |
90a5c9 |
* the MAC and comparing it (timing safe) with the one in the payload.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
compute_auth(slider, len, passphrase, passlen, auth);
|
|
Packit |
90a5c9 |
if (!ap_crypto_equals(auth, decoded, AP_SIPHASH_DSIZE)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(10006)
|
|
Packit |
90a5c9 |
"auth does not match, skipping");
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* encrypt using the first passphrase in the list */
|
|
Packit |
90a5c9 |
res = apr_crypto_passphrase(&key, &ivSize, passphrase, passlen,
|
|
Packit |
90a5c9 |
slider, sizeof(apr_uuid_t),
|
|
Packit |
90a5c9 |
*cipher, APR_MODE_CBC, 1, 4096,
|
|
Packit |
90a5c9 |
f, r->pool);
|
|
Packit |
90a5c9 |
if (APR_STATUS_IS_ENOKEY(res)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01832)
|
|
Packit |
90a5c9 |
"the passphrase '%s' was empty", passphrase);
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (APR_STATUS_IS_EPADDING(res)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01833)
|
|
Packit |
90a5c9 |
"padding is not supported for cipher");
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (APR_STATUS_IS_EKEYTYPE(res)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01834)
|
|
Packit |
90a5c9 |
"the key type is not known");
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (APR_SUCCESS != res) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01835)
|
|
Packit |
90a5c9 |
"encryption could not be configured.");
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* sanity check - decoded too short? */
|
|
Packit |
90a5c9 |
if (len < (sizeof(apr_uuid_t) + ivSize)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(01836)
|
|
Packit |
90a5c9 |
"too short to decrypt, skipping");
|
|
Packit |
90a5c9 |
res = APR_ECRYPT;
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* bypass the salt at the start of the decoded block */
|
|
Packit |
90a5c9 |
slider += sizeof(apr_uuid_t);
|
|
Packit |
90a5c9 |
len -= sizeof(apr_uuid_t);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
res = apr_crypto_block_decrypt_init(&block, &blockSize, slider, key,
|
|
Packit |
90a5c9 |
r->pool);
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != res) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01837)
|
|
Packit |
90a5c9 |
"apr_crypto_block_decrypt_init failed");
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* bypass the iv at the start of the decoded block */
|
|
Packit |
90a5c9 |
slider += ivSize;
|
|
Packit |
90a5c9 |
len -= ivSize;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* decrypt the given string */
|
|
Packit |
90a5c9 |
res = apr_crypto_block_decrypt(&decrypted, &decryptedlen,
|
|
Packit |
90a5c9 |
slider, len, block);
|
|
Packit |
90a5c9 |
if (res) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01838)
|
|
Packit |
90a5c9 |
"apr_crypto_block_decrypt failed");
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
*out = (char *) decrypted;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
res = apr_crypto_block_decrypt_finish(decrypted + decryptedlen, &tlen, block);
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != res) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01839)
|
|
Packit |
90a5c9 |
"apr_crypto_block_decrypt_finish failed");
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
decryptedlen += tlen;
|
|
Packit |
90a5c9 |
decrypted[decryptedlen] = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != res) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_INFO, res, r, APLOGNO(01840)
|
|
Packit |
90a5c9 |
"decryption failed");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Crypto encoding for the session.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param r The request pointer.
|
|
Packit |
90a5c9 |
* @param z A pointer to where the session will be written.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t session_crypto_encode(request_rec * r, session_rec * z)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
char *encoded = NULL;
|
|
Packit |
90a5c9 |
apr_status_t res;
|
|
Packit |
90a5c9 |
const apr_crypto_t *f = NULL;
|
|
Packit |
90a5c9 |
session_crypto_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
|
|
Packit |
90a5c9 |
&session_crypto_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (dconf->passphrases_set && z->encoded && *z->encoded) {
|
|
Packit |
90a5c9 |
apr_pool_userdata_get((void **)&f, CRYPTO_KEY, r->server->process->pconf);
|
|
Packit |
90a5c9 |
res = encrypt_string(r, f, dconf, z->encoded, &encoded);
|
|
Packit |
90a5c9 |
if (res != OK) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01841)
|
|
Packit |
90a5c9 |
"encrypt session failed");
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
z->encoded = encoded;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Crypto decoding for the session.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param r The request pointer.
|
|
Packit |
90a5c9 |
* @param z A pointer to where the session will be written.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t session_crypto_decode(request_rec * r,
|
|
Packit |
90a5c9 |
session_rec * z)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
char *encoded = NULL;
|
|
Packit |
90a5c9 |
apr_status_t res;
|
|
Packit |
90a5c9 |
const apr_crypto_t *f = NULL;
|
|
Packit |
90a5c9 |
session_crypto_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
|
|
Packit |
90a5c9 |
&session_crypto_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((dconf->passphrases_set) && z->encoded && *z->encoded) {
|
|
Packit |
90a5c9 |
apr_pool_userdata_get((void **)&f, CRYPTO_KEY,
|
|
Packit |
90a5c9 |
r->server->process->pconf);
|
|
Packit |
90a5c9 |
res = decrypt_string(r, f, dconf, z->encoded, &encoded);
|
|
Packit |
90a5c9 |
if (res != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01842)
|
|
Packit |
90a5c9 |
"decrypt session failed, wrong passphrase?");
|
|
Packit |
90a5c9 |
return res;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
z->encoded = encoded;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Initialise the SSL in the post_config hook.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static int session_crypto_init(apr_pool_t *p, apr_pool_t *plog,
|
|
Packit |
90a5c9 |
apr_pool_t *ptemp, server_rec *s)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const apr_crypto_driver_t *driver = NULL;
|
|
Packit |
90a5c9 |
apr_crypto_t *f = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
session_crypto_conf *conf = ap_get_module_config(s->module_config,
|
|
Packit |
90a5c9 |
&session_crypto_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* session_crypto_init() will be called twice. Don't bother
|
|
Packit |
90a5c9 |
* going through all of the initialization on the first call
|
|
Packit |
90a5c9 |
* because it will just be thrown away.*/
|
|
Packit |
90a5c9 |
if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) {
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (conf->library) {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
const apu_err_t *err = NULL;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = apr_crypto_init(p);
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != rv) {
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(01843)
|
|
Packit |
90a5c9 |
"APR crypto could not be initialised");
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = apr_crypto_get_driver(&driver, conf->library, conf->params, &err, p);
|
|
Packit |
90a5c9 |
if (APR_EREINIT == rv) {
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, APLOGNO(01844)
|
|
Packit |
90a5c9 |
"warning: crypto for '%s' was already initialised, "
|
|
Packit |
90a5c9 |
"using existing configuration", conf->library);
|
|
Packit |
90a5c9 |
rv = APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != rv && err) {
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(01845)
|
|
Packit |
90a5c9 |
"The crypto library '%s' could not be loaded: %s (%s: %d)", conf->library, err->msg, err->reason, err->rc);
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (APR_ENOTIMPL == rv) {
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(01846)
|
|
Packit |
90a5c9 |
"The crypto library '%s' could not be found",
|
|
Packit |
90a5c9 |
conf->library);
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != rv || !driver) {
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(01847)
|
|
Packit |
90a5c9 |
"The crypto library '%s' could not be loaded",
|
|
Packit |
90a5c9 |
conf->library);
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = apr_crypto_make(&f, driver, conf->params, p);
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != rv) {
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(01848)
|
|
Packit |
90a5c9 |
"The crypto library '%s' could not be initialised",
|
|
Packit |
90a5c9 |
conf->library);
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_INFO, rv, s, APLOGNO(01849)
|
|
Packit |
90a5c9 |
"The crypto library '%s' was loaded successfully",
|
|
Packit |
90a5c9 |
conf->library);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_pool_userdata_set((const void *)f, CRYPTO_KEY,
|
|
Packit |
90a5c9 |
apr_pool_cleanup_null, s->process->pconf);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *create_session_crypto_config(apr_pool_t * p, server_rec *s)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_crypto_conf *new =
|
|
Packit |
90a5c9 |
(session_crypto_conf *) apr_pcalloc(p, sizeof(session_crypto_conf));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* if no library has been configured, set the recommended library
|
|
Packit |
90a5c9 |
* as a sensible default.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
#ifdef APU_CRYPTO_RECOMMENDED_DRIVER
|
|
Packit |
90a5c9 |
new->library = APU_CRYPTO_RECOMMENDED_DRIVER;
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return (void *) new;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *create_session_crypto_dir_config(apr_pool_t * p, char *dummy)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_crypto_dir_conf *new =
|
|
Packit |
90a5c9 |
(session_crypto_dir_conf *) apr_pcalloc(p, sizeof(session_crypto_dir_conf));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
new->passphrases = apr_array_make(p, 10, sizeof(char *));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* default cipher AES256-SHA */
|
|
Packit |
90a5c9 |
new->cipher = "aes256";
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return (void *) new;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *merge_session_crypto_dir_config(apr_pool_t * p, void *basev, void *addv)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_crypto_dir_conf *new = (session_crypto_dir_conf *) apr_pcalloc(p, sizeof(session_crypto_dir_conf));
|
|
Packit |
90a5c9 |
session_crypto_dir_conf *add = (session_crypto_dir_conf *) addv;
|
|
Packit |
90a5c9 |
session_crypto_dir_conf *base = (session_crypto_dir_conf *) basev;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
new->passphrases = (add->passphrases_set == 0) ? base->passphrases : add->passphrases;
|
|
Packit |
90a5c9 |
new->passphrases_set = add->passphrases_set || base->passphrases_set;
|
|
Packit |
90a5c9 |
new->cipher = (add->cipher_set == 0) ? base->cipher : add->cipher;
|
|
Packit |
90a5c9 |
new->cipher_set = add->cipher_set || base->cipher_set;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return new;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_crypto_driver(cmd_parms * cmd, void *config, const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_crypto_conf *conf =
|
|
Packit |
90a5c9 |
(session_crypto_conf *)ap_get_module_config(cmd->server->module_config,
|
|
Packit |
90a5c9 |
&session_crypto_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (err != NULL) {
|
|
Packit |
90a5c9 |
return err;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conf->library = ap_getword_conf(cmd->pool, &arg;;
|
|
Packit |
90a5c9 |
conf->params = arg;
|
|
Packit |
90a5c9 |
conf->library_set = 1;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_crypto_passphrase(cmd_parms * cmd, void *config, const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int arglen = strlen(arg);
|
|
Packit |
90a5c9 |
char **argv;
|
|
Packit |
90a5c9 |
char *result;
|
|
Packit |
90a5c9 |
const char **passphrase;
|
|
Packit |
90a5c9 |
session_crypto_dir_conf *dconf = (session_crypto_dir_conf *) config;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
passphrase = apr_array_push(dconf->passphrases);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((arglen > 5) && strncmp(arg, "exec:", 5) == 0) {
|
|
Packit |
90a5c9 |
if (apr_tokenize_to_argv(arg+5, &argv, cmd->temp_pool) != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return apr_pstrcat(cmd->pool,
|
|
Packit |
90a5c9 |
"Unable to parse exec arguments from ",
|
|
Packit |
90a5c9 |
arg+5, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
argv[0] = ap_server_root_relative(cmd->temp_pool, argv[0]);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!argv[0]) {
|
|
Packit |
90a5c9 |
return apr_pstrcat(cmd->pool,
|
|
Packit |
90a5c9 |
"Invalid SessionCryptoPassphrase exec location:",
|
|
Packit |
90a5c9 |
arg+5, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
result = ap_get_exec_line(cmd->pool,
|
|
Packit |
90a5c9 |
(const char*)argv[0], (const char * const *)argv);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if(!result) {
|
|
Packit |
90a5c9 |
return apr_pstrcat(cmd->pool,
|
|
Packit |
90a5c9 |
"Unable to get bind password from exec of ",
|
|
Packit |
90a5c9 |
arg+5, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
*passphrase = result;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
*passphrase = arg;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
dconf->passphrases_set = 1;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_crypto_passphrase_file(cmd_parms *cmd, void *config,
|
|
Packit |
90a5c9 |
const char *filename)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char buffer[MAX_STRING_LEN];
|
|
Packit |
90a5c9 |
char *arg;
|
|
Packit |
90a5c9 |
const char *args;
|
|
Packit |
90a5c9 |
ap_configfile_t *file;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
filename = ap_server_root_relative(cmd->temp_pool, filename);
|
|
Packit |
90a5c9 |
rv = ap_pcfg_openfile(&file, cmd->temp_pool, filename);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return apr_psprintf(cmd->pool, "%s: Could not open file %s: %pm",
|
|
Packit |
90a5c9 |
cmd->cmd->name, filename, &rv;;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (!(ap_cfg_getline(buffer, sizeof(buffer), file))) {
|
|
Packit |
90a5c9 |
args = buffer;
|
|
Packit |
90a5c9 |
while (*(arg = ap_getword_conf(cmd->pool, &args)) != '\0') {
|
|
Packit |
90a5c9 |
if (*arg == '#') {
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
set_crypto_passphrase(cmd, config, arg);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_cfg_closefile(file);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_crypto_cipher(cmd_parms * cmd, void *config, const char *cipher)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_crypto_dir_conf *dconf = (session_crypto_dir_conf *) config;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
dconf->cipher = cipher;
|
|
Packit |
90a5c9 |
dconf->cipher_set = 1;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const command_rec session_crypto_cmds[] =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
AP_INIT_ITERATE("SessionCryptoPassphrase", set_crypto_passphrase, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"The passphrase(s) used to encrypt the session. First will be used for encryption, all phrases will be accepted for decryption"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("SessionCryptoPassphraseFile", set_crypto_passphrase_file, NULL, RSRC_CONF|ACCESS_CONF,
|
|
Packit |
90a5c9 |
"File containing passphrase(s) used to encrypt the session, one per line. First will be used for encryption, all phrases will be accepted for decryption"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("SessionCryptoCipher", set_crypto_cipher, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"The underlying crypto cipher to use"),
|
|
Packit |
90a5c9 |
AP_INIT_RAW_ARGS("SessionCryptoDriver", set_crypto_driver, NULL, RSRC_CONF,
|
|
Packit |
90a5c9 |
"The underlying crypto library driver to use"),
|
|
Packit |
90a5c9 |
{ NULL }
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void register_hooks(apr_pool_t * p)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
ap_hook_session_encode(session_crypto_encode, NULL, NULL, APR_HOOK_LAST);
|
|
Packit |
90a5c9 |
ap_hook_session_decode(session_crypto_decode, NULL, NULL, APR_HOOK_FIRST);
|
|
Packit |
90a5c9 |
ap_hook_post_config(session_crypto_init, NULL, NULL, APR_HOOK_LAST);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
AP_DECLARE_MODULE(session_crypto) =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
STANDARD20_MODULE_STUFF,
|
|
Packit |
90a5c9 |
create_session_crypto_dir_config, /* dir config creater */
|
|
Packit |
90a5c9 |
merge_session_crypto_dir_config, /* dir merger --- default is to override */
|
|
Packit |
90a5c9 |
create_session_crypto_config, /* server config */
|
|
Packit |
90a5c9 |
NULL, /* merge server config */
|
|
Packit |
90a5c9 |
session_crypto_cmds, /* command apr_table_t */
|
|
Packit |
90a5c9 |
register_hooks /* register hooks */
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#endif
|