You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
264 lines
6.0 KiB
264 lines
6.0 KiB
/**
|
|
* this filter generates a sha1 from the current microtime and request
|
|
* useses this to fill the linux random source.
|
|
*
|
|
* inspired by timed_entropyd.
|
|
*
|
|
* ATTENTION: This module is not portable right now as i don't know
|
|
* howto fill the random source for other systems. It is linux only.
|
|
*
|
|
* Most time was spend in figuring out how to write apache modules.
|
|
*
|
|
* \author Georg Hopp <georg@steffers.org>
|
|
*/
|
|
#define _POSIX_C_SOURCE 199309L
|
|
|
|
#include <apache2/httpd.h>
|
|
#include <apache2/http_core.h>
|
|
#include <apr-1/apu.h>
|
|
#include <apr-1/apr_general.h>
|
|
#include <apr-1/apr_sha1.h>
|
|
|
|
#include <time.h>
|
|
#include <math.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <linux/random.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#define min(x, y) ((x)<(y)?(x):(y))
|
|
|
|
|
|
module AP_MODULE_DECLARE_DATA entropy_module;
|
|
|
|
char * getData(const char *, size_t);
|
|
|
|
/**
|
|
* This is taken from timer_entropyd and modified so
|
|
* that the constant 1/log(2.0) is not calculated but
|
|
* set directly.
|
|
*
|
|
* As far as i can say this correlates to the shannon
|
|
* entropy algorithm with equal probabilities
|
|
* for entropy where the entropy units are bits.
|
|
*
|
|
* But actually i am no mathemacian and my analysis capabilities
|
|
* are limited. Additionally i have not analysed the linux random
|
|
* character device code, so i trusted the code in timer_entropyd.
|
|
*/
|
|
static
|
|
int
|
|
get_entropy(const unsigned char * data, size_t ndata)
|
|
{
|
|
size_t byte_count[256];
|
|
size_t iterator;
|
|
static double log2inv = 1.442695; //!< 1 / log(2.0): the entropy unit size
|
|
double entropy = 0.0;
|
|
|
|
memset(byte_count, 0, sizeof(byte_count));
|
|
|
|
/**
|
|
* first get the amount each byte occurs in the array
|
|
*/
|
|
for (iterator = 0; iterator < ndata; iterator++) {
|
|
byte_count[data[iterator]]++;
|
|
}
|
|
|
|
for (iterator = 0; iterator < 256; iterator++) {
|
|
double probability = (double)byte_count[iterator] / (double)ndata;
|
|
|
|
if (0.0 < probability) {
|
|
entropy += probability * log2inv * (log(1.0 / probability));
|
|
}
|
|
}
|
|
|
|
entropy *= (double)ndata;
|
|
entropy = (entropy < 0.0)? 0.0 : entropy;
|
|
entropy = min((double)(ndata * 8), entropy);
|
|
|
|
return entropy;
|
|
}
|
|
|
|
static
|
|
int
|
|
header_do_print(void * rec, const char * key, const char * value)
|
|
{
|
|
apr_sha1_ctx_t * sha1_ctx = rec;
|
|
|
|
apr_sha1_update(sha1_ctx, value, strlen(value));
|
|
|
|
return 1;
|
|
}
|
|
|
|
static
|
|
apr_status_t
|
|
entropy_filter_in(
|
|
ap_filter_t * filter,
|
|
apr_bucket_brigade * brigade,
|
|
ap_input_mode_t mode,
|
|
apr_read_type_e block,
|
|
apr_off_t readbytes)
|
|
{
|
|
apr_bucket * bucket;
|
|
apr_status_t status;
|
|
request_rec * request = filter->r;
|
|
conn_rec * connection = filter->c;
|
|
apr_sha1_ctx_t sha1_ctx;
|
|
unsigned char digest[APR_SHA1_DIGESTSIZE];
|
|
|
|
struct timespec ts;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
|
|
|
apr_sha1_init(&sha1_ctx);
|
|
|
|
/**
|
|
* add current microtime to sha1
|
|
*/
|
|
apr_sha1_update_binary(
|
|
&sha1_ctx,
|
|
(const unsigned char *)&ts,
|
|
sizeof(ts));
|
|
|
|
/**
|
|
* add client ip to sha1
|
|
*/
|
|
apr_sha1_update(
|
|
&sha1_ctx,
|
|
connection->client_ip,
|
|
strlen(connection->client_ip));
|
|
|
|
/**
|
|
* add request line to sha1
|
|
*/
|
|
apr_sha1_update(
|
|
&sha1_ctx,
|
|
request->the_request,
|
|
strlen(request->the_request));
|
|
|
|
/**
|
|
* add all header values to sha1
|
|
*/
|
|
apr_table_do(header_do_print, &sha1_ctx, request->headers_in, NULL);
|
|
|
|
/**
|
|
* get the request body and add it to the sha1
|
|
*/
|
|
status = ap_get_brigade(filter->next, brigade, mode, block, readbytes);
|
|
|
|
if (status == APR_SUCCESS) {
|
|
for (
|
|
bucket = APR_BRIGADE_FIRST(brigade);
|
|
bucket != APR_BRIGADE_SENTINEL(brigade);
|
|
bucket = APR_BUCKET_NEXT(bucket)) {
|
|
|
|
if (!(APR_BUCKET_IS_METADATA(bucket))) {
|
|
const char * buffer;
|
|
apr_size_t nbuffer;
|
|
|
|
status = apr_bucket_read(
|
|
bucket,
|
|
&buffer,
|
|
&nbuffer,
|
|
APR_BLOCK_READ);
|
|
|
|
if (status == APR_SUCCESS) {
|
|
apr_sha1_update(&sha1_ctx, buffer, nbuffer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get the sha1 digest
|
|
*/
|
|
apr_sha1_final(digest, &sha1_ctx);
|
|
|
|
/**
|
|
* fill /dev/random with sha1 from current request
|
|
*/
|
|
{
|
|
int i;
|
|
int entropy = get_entropy(digest, APR_SHA1_DIGESTSIZE);
|
|
int fd = open("/dev/random", O_WRONLY|O_NONBLOCK);
|
|
struct rand_pool_info * output;
|
|
|
|
output = (struct rand_pool_info *)malloc(
|
|
sizeof(struct rand_pool_info) + APR_SHA1_DIGESTSIZE);
|
|
|
|
output->entropy_count = entropy;
|
|
output->buf_size = APR_SHA1_DIGESTSIZE;
|
|
memcpy(output->buf, digest, APR_SHA1_DIGESTSIZE);
|
|
|
|
fprintf(stderr, "sha1 so far: ");
|
|
for (i=0; i<APR_SHA1_DIGESTSIZE; i++) {
|
|
fprintf(stderr, "%02x", digest[i]);
|
|
}
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "entropy bits: %d\n", entropy);
|
|
|
|
if (ioctl(fd, RNDADDENTROPY, output) == -1) {
|
|
switch(errno) {
|
|
case EBADF:
|
|
fprintf(stderr, "ioctl failed: no valid file descriptor %d\n", fd);
|
|
break;
|
|
|
|
case EFAULT:
|
|
fprintf(stderr, "ioctl failed: invalid argument: %p\n", output);
|
|
break;
|
|
|
|
case EINVAL:
|
|
fprintf(stderr, "ioctl failed: invalid request\n", errno);
|
|
break;
|
|
|
|
case ENOTTY:
|
|
fprintf(stderr, "ioctl failed: discriptor not associated to character device\n", errno);
|
|
break;
|
|
|
|
case EPERM:
|
|
fprintf(stderr, "ioctl failed: invalid permissions\n", errno);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "ioctl(RNDADDENTROPY) failed: %d\n", errno);
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(output);
|
|
close(fd);
|
|
}
|
|
fflush(stderr);
|
|
|
|
ap_remove_input_filter(filter);
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* apache module initialization
|
|
*/
|
|
static
|
|
void
|
|
entropy_register_hook(apr_pool_t *p)
|
|
{
|
|
ap_register_input_filter(
|
|
"ENTROPY",
|
|
entropy_filter_in,
|
|
NULL,
|
|
AP_FTYPE_CONTENT_SET);
|
|
}
|
|
|
|
module AP_MODULE_DECLARE_DATA entropy_module = {
|
|
STANDARD20_MODULE_STUFF,
|
|
NULL, /* create per-directory config structure */
|
|
NULL, /* merge per-directory config structures */
|
|
NULL, /* create per-server config structure */
|
|
NULL, /* merge per-server config structures */
|
|
NULL, /* command apr_table_t */
|
|
entropy_register_hook /* register hooks */
|
|
};
|
|
|
|
// vim: set ts=4 sw=4:
|