1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * mod_crypto.c --- Encrypt / decrypt data in the input and output filter
22 #include "mod_crypto.h"
24 #include "apr_strings.h"
25 #include "apr_crypto.h"
26 #include "apr_base64.h"
27 #include "apr_escape.h"
28 #include "apr_version.h"
29 #if !APR_VERSION_AT_LEAST(2,0,0)
30 #include "apu_version.h"
32 #include "util_filter.h"
34 #include "http_request.h"
35 #include "http_protocol.h"
38 #if APR_VERSION_AT_LEAST(2,0,0) || \
39 (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 6)
41 APR_HOOK_STRUCT(APR_HOOK_LINK(crypto_key)
42 APR_HOOK_LINK(crypto_iv))
43 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ap, CRYPTO, apr_status_t, crypto_key,
45 apr_crypto_block_key_type_t * cipher,
46 apr_crypto_block_key_mode_t * mode,
48 const apr_crypto_key_rec_t ** rec),
49 (r, cipher, mode, pad, rec), DECLINED)
50 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ap, CRYPTO, apr_status_t, crypto_iv,
52 apr_crypto_block_key_type_t * cipher,
53 const unsigned char **iv), (r, cipher,
55 module AP_MODULE_DECLARE_DATA crypto_module;
57 #define DEFAULT_BUFFER_SIZE 128*1024
58 #define DEFAULT_CIPHER "aes256"
59 #define DEFAULT_MODE "cbc"
60 #define CRYPTO_KEY "crypto_context"
62 typedef struct pass_conf
65 const ap_expr_info_t *expr;
71 * Structure to carry the server wide session config.
77 apr_crypto_t **crypto;
81 typedef struct crypto_dir_conf
83 apr_off_t size; /* size of the buffer */
84 int size_set; /* has the size been set */
94 typedef struct crypto_ctx
96 apr_bucket_brigade *bb;
97 apr_bucket_brigade *tmp;
98 crypto_dir_conf *conf;
100 apr_crypto_key_t *key;
101 apr_crypto_block_key_type_t *cipher;
102 apr_crypto_block_key_mode_t *mode;
103 apr_crypto_block_t *block;
104 const unsigned char *iv;
113 static const char *parse_pass_conf_binary(cmd_parms *cmd,
120 if ('f' == ps && !strncmp(arg, "file:", 5)) {
125 return apr_pstrcat(cmd->pool, "No filename specified", NULL);
128 name = ap_server_root_relative(cmd->temp_pool, arg);
132 rv = apr_file_open(&file, name, APR_FOPEN_READ,
133 APR_FPROT_OS_DEFAULT, cmd->temp_pool);
134 if (APR_SUCCESS == rv) {
137 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, file);
138 if (rv == APR_SUCCESS) {
141 pass->scheme = "file";
142 pass->raw = apr_palloc(cmd->pool, finfo.size);
143 pass->size = finfo.size;
144 apr_crypto_clear(cmd->pool, pass->raw, pass->size);
146 rv = apr_file_read_full(file, pass->raw, pass->size,
148 if (APR_SUCCESS == rv && size != pass->size) {
154 if (APR_SUCCESS != rv) {
156 return apr_pstrcat(cmd->pool, "Unable to load from file '",
157 arg, "': ", apr_strerror(rv, buf,
163 return apr_pstrcat(cmd->pool, "Unable to locate file from name ",
168 else if ('h' == ps && (!strncmp(arg, "hex:", 4))) {
169 const char *expr_err = NULL;
173 return apr_pstrcat(cmd->temp_pool,
174 "Cannot parse expression, it is blank", NULL);
177 pass->scheme = "hex";
178 pass->expr = ap_expr_parse_cmd(cmd, arg, AP_EXPR_FLAG_STRING_RESULT,
182 return apr_pstrcat(cmd->temp_pool, "Cannot parse ", pass->scheme,
183 " expression '", arg, "' in: ", expr_err,
189 else if ('b' == ps && !strncmp(arg, "base64:", 7)) {
190 const char *expr_err = NULL;
194 return apr_pstrcat(cmd->temp_pool,
195 "Cannot parse expression, it is blank", NULL);
198 pass->scheme = "base64";
199 pass->expr = ap_expr_parse_cmd(cmd, arg, AP_EXPR_FLAG_STRING_RESULT,
203 return apr_pstrcat(cmd->temp_pool, "Cannot parse ", pass->scheme,
204 " expression '", arg, "' in: ", expr_err,
210 else if ('d' == ps && !strncmp(arg, "decimal:", 8)) {
211 const char *expr_err = NULL;
215 return apr_pstrcat(cmd->temp_pool,
216 "Cannot parse expression, it is blank", NULL);
219 pass->scheme = "decimal";
220 pass->expr = ap_expr_parse_cmd(cmd, arg, AP_EXPR_FLAG_STRING_RESULT,
224 return apr_pstrcat(cmd->temp_pool, "Cannot parse ", pass->scheme,
225 " expression '", arg, "' in: ", expr_err,
231 else if ('n' == ps && !strcmp(arg, "none")) {
236 return apr_pstrcat(cmd->pool,
237 "Scheme must be 'file:', 'hex:', 'base64:', 'decimal:' or 'none': ",
245 exec_pass_conf_binary(request_rec *r, pass_conf * pass,
246 const char *description, apr_size_t size,
247 const unsigned char **k)
255 if (size != pass->size) {
256 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
257 APLOGNO(03409) "%s has wrong size (was %"
258 APR_SIZE_T_FMT ", must be %" APR_SIZE_T_FMT ")",
259 description, pass->size, size);
266 else if (pass->expr) {
267 char ps = *pass->scheme;
268 const char *err = NULL;
270 const char *arg = ap_expr_str_exec(r, pass->expr, &err);
272 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
273 APLOGNO(03410) "%s could not be parsed: %s",
283 apr_unescape_hex(NULL, arg, strlen(arg), 1, &len);
285 b = apr_palloc(r->pool, size);
286 memset(b, 0, size - len);
287 apr_unescape_hex(b + size - len, arg, strlen(arg), 1,
291 b = apr_palloc(r->pool, len);
292 apr_unescape_hex(b, arg, strlen(arg), 1, NULL);
300 else if ('b' == ps) {
304 len = apr_base64_decode_len(arg);
306 b = apr_palloc(r->pool, size);
307 memset(b, 0, size - len);
308 apr_base64_decode_binary(b + size - len, arg);
311 b = apr_palloc(r->pool, len);
312 apr_base64_decode_binary(b, arg);
320 else if ('d' == ps) {
327 t = (apr_uint64_t) apr_atoi64(arg);
329 for (i = 7; i >= 0; i--) {
336 b = apr_palloc(r->pool, size);
337 memset(b, 0, size - len);
338 memcpy(b + size - len, n, len);
341 b = apr_palloc(r->pool, len);
357 init_cipher(request_rec *r,
358 apr_crypto_block_key_type_t ** cipher,
359 apr_crypto_block_key_mode_t ** mode)
365 crypto_conf *conf = ap_get_module_config(r->server->module_config,
367 crypto_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
372 rv = apr_crypto_get_block_key_types(&ciphers, *conf->crypto);
373 if (APR_SUCCESS != rv) {
374 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
375 APLOGNO(03411) "no ciphers returned by APR");
379 *cipher = apr_hash_get(ciphers, dconf->cipher, APR_HASH_KEY_STRING);
381 apr_hash_index_t *hi;
386 char *options = NULL;
388 for (hi = apr_hash_first(r->pool, ciphers); hi;
389 hi = apr_hash_next(hi)) {
390 apr_hash_this(hi, NULL, &klen, NULL);
393 for (hi = apr_hash_first(r->pool, ciphers); hi;
394 hi = apr_hash_next(hi)) {
395 apr_hash_this(hi, &key, &klen, NULL);
397 options = apr_palloc(r->pool, sum + 1);
400 options[offset++] = ',';
401 options[offset++] = ' ';
403 strncpy(options + offset, key, klen);
408 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
409 APLOGNO(03428) "cipher '%s' not recognised by crypto driver. "
410 "Options: %s", dconf->cipher, options);
419 rv = apr_crypto_get_block_key_modes(&modes, *conf->crypto);
420 if (APR_SUCCESS != rv) {
421 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
422 APLOGNO(03412) "no cipher modes returned by APR");
426 *mode = apr_hash_get(modes, dconf->mode, APR_HASH_KEY_STRING);
428 apr_hash_index_t *hi;
433 char *options = NULL;
435 for (hi = apr_hash_first(r->pool, modes); hi;
436 hi = apr_hash_next(hi)) {
437 apr_hash_this(hi, NULL, &klen, NULL);
440 for (hi = apr_hash_first(r->pool, modes); hi;
441 hi = apr_hash_next(hi)) {
442 apr_hash_this(hi, &key, &klen, NULL);
444 options = apr_palloc(r->pool, sum + 1);
447 options[offset++] = ',';
448 options[offset++] = ' ';
450 strncpy(options + offset, key, klen);
455 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
456 APLOGNO(03429) "cipher mode '%s' not recognised by crypto driver. "
457 "Options: %s", dconf->mode, options);
467 static apr_status_t init_crypt(ap_filter_t * f)
470 crypto_ctx *ctx = f->ctx;
471 const apr_crypto_key_rec_t *rec;
473 crypto_conf *conf = ap_get_module_config(f->r->server->module_config,
475 crypto_dir_conf *dconf =
476 ap_get_module_config(f->r->per_dir_config, &crypto_module);
478 /* sanity check - has crypto been switched on? */
479 if (!conf->crypto || !*conf->crypto) {
480 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, f->r,
481 APLOGNO(03430) "crypto driver has not been enabled for this server");
485 /* initial setup of the context */
486 ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
488 ctx->remaining = ctx->conf->size;
490 ctx->osize = ctx->conf->size;
492 /* fetch the cipher for this location */
493 rv = init_cipher(f->r, &ctx->cipher, &ctx->mode);
494 if (APR_SUCCESS != rv) {
498 /* sanity check - buffer size multiple of block size? */
499 if (ctx->conf->size % ctx->cipher->blocksize) {
500 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, f->r,
501 APLOGNO(03413) "Buffer size %" APR_OFF_T_FMT
502 " is not a multiple of the block size %d of cipher '%s'",
503 ctx->conf->size, ctx->cipher->blocksize, dconf->cipher);
507 /* fetch the key we'll be using for decryption */
508 rv = ap_run_crypto_key(f->r, ctx->cipher, ctx->mode, 1, &rec);
509 if (DECLINED == rv) {
510 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
511 APLOGNO(03414) "no key specified for this URL");
514 if (APR_SUCCESS != rv || !rec) {
515 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
516 APLOGNO(03415) "key could not be retrieved");
519 if (rec->ktype != APR_CRYPTO_KTYPE_SECRET) {
520 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
521 APLOGNO(03416) "key is not a symmetrical key");
525 /* attempt to import the key */
526 rv = apr_crypto_key(&ctx->key, rec, *conf->crypto, f->r->pool);
527 if (APR_STATUS_IS_ENOKEY(rv)) {
528 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
529 APLOGNO(03417) "key could not be loaded");
531 if (APR_STATUS_IS_EPADDING(rv)) {
532 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
533 APLOGNO(03418) "padding is not supported for cipher");
535 if (APR_STATUS_IS_EKEYTYPE(rv)) {
536 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
537 APLOGNO(03419) "the key type is not known");
539 if (APR_SUCCESS != rv) {
540 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
541 APLOGNO(03420) "encryption could not be configured.");
545 /* fetch the optional iv */
546 rv = ap_run_crypto_iv(f->r, ctx->cipher, &ctx->iv);
547 if (DECLINED != rv && APR_SUCCESS != rv) {
548 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
549 APLOGNO(03431) "initialisation vector could not be retrieved");
556 static int init_encrypt(ap_filter_t * f)
561 ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
565 if (APR_SUCCESS != rv) {
566 return HTTP_INTERNAL_SERVER_ERROR;
572 static int init_decrypt(ap_filter_t * f)
577 ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
581 if (APR_SUCCESS != rv) {
582 return HTTP_INTERNAL_SERVER_ERROR;
589 * Run the crypto algorithm, write to ctx->out
592 do_crypto(ap_filter_t * f, unsigned char *in, apr_off_t size, int finish)
595 crypto_ctx *ctx = f->ctx;
597 apr_size_t blockSize = 0;
598 int need_iv = (ctx->iv == NULL);
602 /* encrypt the given buffer */
606 rv = apr_crypto_block_encrypt_init(&ctx->block, &ctx->iv,
607 ctx->key, &blockSize,
609 if (APR_SUCCESS != rv) {
610 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
611 APLOGNO(03421) "could not initialise encryption");
618 if (need_iv && ctx->iv) {
619 ctx->osize += blockSize;
622 out = ctx->out = apr_palloc(f->r->pool,
623 ctx->osize + ctx->cipher->blocksize);
624 apr_crypto_clear(f->r->pool, ctx->out,
625 ctx->osize + ctx->cipher->blocksize);
627 /* no precomputed iv? write the generated iv as the first block of the stream */
628 if (need_iv && ctx->iv) {
629 memcpy(out, ctx->iv, blockSize);
630 ctx->remaining += blockSize;
637 out = ctx->out + (ctx->osize - ctx->remaining);
641 rv = apr_crypto_block_encrypt(&out, &written, in, size,
643 if (APR_SUCCESS != rv) {
644 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
645 APLOGNO(03422) "crypto: attempt to encrypt failed");
651 rv = apr_crypto_block_encrypt_finish(out, &written, ctx->block);
652 if (APR_SUCCESS != rv) {
653 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
654 APLOGNO(03432) "crypto: attempt to finish encrypt failed");
660 /* decrypt the given buffer */
664 out = ctx->out = apr_palloc(f->r->pool,
665 ctx->osize + ctx->cipher->blocksize);
666 apr_crypto_clear(f->r->pool, ctx->out,
667 ctx->osize + ctx->cipher->blocksize);
670 out = ctx->out + (ctx->osize - ctx->remaining);
673 /* no precomputed iv? assume the first block in the stream is the iv */
676 ctx->cipher->blocksize - (ctx->osize - ctx->remaining);
678 memcpy(out, in, size);
679 ctx->remaining -= size;
683 memcpy(out, in, isize);
684 ctx->remaining -= isize;
691 rv = apr_crypto_block_decrypt_init(&ctx->block, &blockSize,
692 ctx->iv, ctx->key, f->r->pool);
693 if (APR_SUCCESS != rv) {
694 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
695 APLOGNO(03423) "could not initialise decryption");
701 rv = apr_crypto_block_decrypt(&out, &written, in, size,
703 if (APR_SUCCESS != rv) {
704 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
705 APLOGNO(03433) "crypto: attempt to decrypt failed (key/iv incorrect?)");
710 rv = apr_crypto_block_decrypt_finish(out, &written, ctx->block);
711 if (APR_SUCCESS != rv) {
712 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
713 APLOGNO(03434) "crypto: attempt to finish decrypt failed (key/iv incorrect?)");
719 ctx->remaining -= written;
720 ctx->written += written;
721 ctx->written += extra;
727 * Encrypt/decrypt buckets being written to the output filter stack.
730 crypto_out_filter(ap_filter_t * f, apr_bucket_brigade * bb)
732 apr_bucket *e, *after;
733 crypto_ctx *ctx = f->ctx;
734 apr_status_t rv = APR_SUCCESS;
736 /* Do nothing if asked to filter nothing. */
737 if (APR_BRIGADE_EMPTY(bb)) {
738 return ap_pass_brigade(f->next, bb);
741 /* clear the content length */
744 apr_table_unset(f->r->headers_out, "Content-Length");
747 /* make sure we fit in the buffer snugly */
748 if (APR_BRIGADE_EMPTY(ctx->bb)) {
749 apr_brigade_partition(bb, ctx->remaining, &after);
752 while (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(bb)) {
756 e = APR_BRIGADE_FIRST(bb);
758 /* EOS means we are done. */
759 if (APR_BUCKET_IS_EOS(e)) {
761 /* handle any leftovers */
762 do_crypto(f, NULL, 0, 1);
763 apr_brigade_write(ctx->bb, NULL, NULL, (const char *) ctx->out,
764 ctx->conf->size - ctx->remaining);
765 ctx->remaining = ctx->osize;
767 apr_brigade_partition(bb, ctx->remaining, &after);
769 /* pass the EOS across */
770 APR_BUCKET_REMOVE(e);
771 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
773 /* pass what we have down the chain */
774 rv = ap_pass_brigade(f->next, ctx->bb);
776 ap_remove_output_filter(f);
781 if (APR_BUCKET_IS_FLUSH(e)) {
783 /* we cannot change the laws of physics: crypto can only happen
784 * on a block boundary. As a result, just pass the flush bucket
785 * through as is, we'll send the rest of the block when it
789 /* pass the flush bucket across */
790 APR_BUCKET_REMOVE(e);
791 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
793 /* pass what we have down the chain */
794 rv = ap_pass_brigade(f->next, ctx->bb);
798 /* metadata buckets are preserved as is */
799 if (APR_BUCKET_IS_METADATA(e)) {
801 * Remove meta data bucket from old brigade and insert into the
804 APR_BUCKET_REMOVE(e);
805 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
810 == (rv = apr_bucket_read(e, &data, &size, APR_BLOCK_READ))) {
812 do_crypto(f, (unsigned char *) data, size, 0);
813 apr_bucket_delete(e);
815 if (!ctx->remaining) {
816 apr_brigade_write(ctx->bb, NULL, NULL,
817 (const char *) ctx->out, ctx->written);
818 ctx->remaining = ctx->osize;
820 apr_brigade_partition(bb, ctx->remaining, &after);
821 rv = ap_pass_brigade(f->next, ctx->bb);
833 * Decrypt/encrypt buckets being read from the input filter stack.
836 crypto_in_filter(ap_filter_t * f, apr_bucket_brigade * bb,
837 ap_input_mode_t mode, apr_read_type_e block,
840 apr_bucket *e, *after;
841 apr_status_t rv = APR_SUCCESS;
842 crypto_ctx *ctx = f->ctx;
845 ctx->tmp = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
848 /* just get out of the way of things we don't want. */
849 if (mode != AP_MODE_READBYTES) {
850 return ap_get_brigade(f->next, bb, mode, block, readbytes);
853 /* if our buffer is empty, read off the network until the buffer is full */
854 if (APR_BRIGADE_EMPTY(ctx->bb)) {
855 ctx->remaining = ctx->osize;
858 while (!ctx->seen_eos && ctx->remaining > 0) {
862 if (APR_BRIGADE_EMPTY(ctx->tmp)) {
863 rv = ap_get_brigade(f->next, ctx->tmp, mode, block,
867 /* if an error was received, bail out now. If the error is
868 * EAGAIN and we have not yet seen an EOS, we will definitely
869 * be called again, at which point we will send our buffered
870 * data. Instead of sending EAGAIN, some filters return an
871 * empty brigade instead when data is not yet available. In
872 * this case, we drop through and pass buffered data, if any.
874 if (APR_STATUS_IS_EAGAIN(rv)
875 || (rv == APR_SUCCESS
876 && block == APR_NONBLOCK_READ
877 && APR_BRIGADE_EMPTY(ctx->tmp))) {
878 if (APR_BRIGADE_EMPTY(ctx->bb)) {
883 if (APR_SUCCESS != rv) {
887 while (!APR_BRIGADE_EMPTY(ctx->tmp)) {
888 e = APR_BRIGADE_FIRST(ctx->tmp);
890 /* if we see an EOS, we are done */
891 if (APR_BUCKET_IS_EOS(e)) {
893 /* handle any leftovers */
894 do_crypto(f, NULL, 0, 1);
895 apr_brigade_write(ctx->bb, NULL, NULL,
896 (const char *) ctx->out, ctx->written);
898 APR_BUCKET_REMOVE(e);
899 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
904 /* flush buckets clear the buffer */
905 if (APR_BUCKET_IS_FLUSH(e)) {
906 APR_BUCKET_REMOVE(e);
907 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
911 /* pass metadata buckets through */
912 if (APR_BUCKET_IS_METADATA(e)) {
913 APR_BUCKET_REMOVE(e);
914 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
918 /* read the bucket in, pack it into the buffer */
919 rv = apr_bucket_read(e, &data, &size, block);
920 if (APR_STATUS_IS_EAGAIN(rv)) {
921 if (APR_BRIGADE_EMPTY(ctx->bb)) {
926 if (APR_SUCCESS != rv) {
930 do_crypto(f, (unsigned char *) data, size, 0);
931 if (!ctx->remaining || APR_STATUS_IS_EAGAIN(rv)) {
932 apr_brigade_write(ctx->bb, NULL, NULL,
933 (const char *) ctx->out, ctx->written);
936 apr_bucket_delete(e);
942 /* give the caller the data they asked for from the buffer */
943 apr_brigade_partition(ctx->bb, readbytes, &after);
944 e = APR_BRIGADE_FIRST(ctx->bb);
946 if (APR_BUCKET_IS_EOS(e)) {
947 /* last bucket read, step out of the way */
948 ap_remove_input_filter(f);
950 APR_BUCKET_REMOVE(e);
951 APR_BRIGADE_INSERT_TAIL(bb, e);
952 e = APR_BRIGADE_FIRST(ctx->bb);
955 /* clear the content length */
958 apr_table_unset(f->r->headers_in, "Content-Length");
964 static int crypto_handler(request_rec *r)
967 crypto_dir_conf *dconf;
970 if (*r->handler != 'c' || strcmp(r->handler, "crypto-key")) {
974 conf = ap_get_module_config(r->server->module_config, &crypto_module);
975 dconf = ap_get_module_config(r->per_dir_config, &crypto_module);
977 /* sanity check - has crypto been switched on? */
978 if (!conf->crypto || !*conf->crypto) {
979 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
980 APLOGNO(03435) "crypto driver has not been enabled for this server");
984 if (dconf->key_set) {
985 const apr_crypto_key_rec_t *rec;
986 apr_crypto_block_key_type_t *cipher;
987 apr_crypto_block_key_mode_t *mode;
989 /* fetch the cipher for this location */
990 rv = init_cipher(r, &cipher, &mode);
991 if (APR_SUCCESS != rv) {
992 return HTTP_INTERNAL_SERVER_ERROR;
995 /* fetch the key we'll be using for encryption / decryption */
996 rv = ap_run_crypto_key(r, cipher, mode, 1, &rec);
997 if (DECLINED == rv) {
998 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
999 APLOGNO(03424) "no key specified for this URL");
1000 return HTTP_INTERNAL_SERVER_ERROR;
1002 if (APR_SUCCESS != rv || !rec) {
1003 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
1004 APLOGNO(03425) "key could not be retrieved");
1005 return HTTP_INTERNAL_SERVER_ERROR;
1007 if (rec->ktype != APR_CRYPTO_KTYPE_SECRET) {
1008 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
1009 APLOGNO(03426) "key is not a symmetrical key");
1010 return HTTP_INTERNAL_SERVER_ERROR;
1013 ap_set_content_type(r, "application/octet-stream");
1014 ap_set_content_length(r, rec->k.secret.secretLen);
1015 ap_rwrite(rec->k.secret.secret, rec->k.secret.secretLen, r);
1022 return HTTP_NOT_FOUND;
1028 static void *create_crypto_config(apr_pool_t * p, server_rec *s)
1030 crypto_conf *new = (crypto_conf *) apr_pcalloc(p, sizeof(crypto_conf));
1032 /* if no library has been configured, set the recommended library
1033 * as a sensible default.
1035 #ifdef APU_CRYPTO_RECOMMENDED_DRIVER
1036 new->library = APU_CRYPTO_RECOMMENDED_DRIVER;
1038 new->crypto = apr_pcalloc(p, sizeof(apr_crypto_t *));
1040 return (void *) new;
1043 static void *merge_crypto_config(apr_pool_t * p, void *basev, void *addv)
1045 crypto_conf *new = (crypto_conf *) apr_pcalloc(p, sizeof(crypto_conf));
1046 crypto_conf *add = (crypto_conf *) addv;
1047 crypto_conf *base = (crypto_conf *) basev;
1049 new->library = (add->library_set == 0) ? base->library : add->library;
1050 new->params = (add->library_set == 0) ? base->params : add->params;
1051 new->library_set = add->library_set || base->library_set;
1053 new->crypto = base->crypto;
1055 return (void *) new;
1058 static void *create_crypto_dir_config(apr_pool_t * p, char *dummy)
1060 crypto_dir_conf *new =
1061 (crypto_dir_conf *) apr_pcalloc(p, sizeof(crypto_dir_conf));
1063 new->size = DEFAULT_BUFFER_SIZE; /* default size */
1064 new->cipher = DEFAULT_CIPHER;
1065 new->mode = DEFAULT_MODE;
1067 return (void *) new;
1070 static void *merge_crypto_dir_config(apr_pool_t * p, void *basev, void *addv)
1072 crypto_dir_conf *new =
1073 (crypto_dir_conf *) apr_pcalloc(p, sizeof(crypto_dir_conf));
1074 crypto_dir_conf *add = (crypto_dir_conf *) addv;
1075 crypto_dir_conf *base = (crypto_dir_conf *) basev;
1077 new->size = (add->size_set == 0) ? base->size : add->size;
1078 new->size_set = add->size_set || base->size_set;
1080 new->cipher = (add->cipher_set == 0) ? base->cipher : add->cipher;
1081 new->mode = (add->cipher_set == 0) ? base->mode : add->mode;
1082 new->cipher_set = add->cipher_set || base->cipher_set;
1084 new->key = (add->key_set == 0) ? base->key : add->key;
1085 new->key_set = add->key_set || base->key_set;
1087 new->iv = (add->iv_set == 0) ? base->iv : add->iv;
1088 new->iv_set = add->iv_set || base->iv_set;
1093 static const char *set_crypto_size(cmd_parms *cmd, void *dconf,
1096 crypto_dir_conf *conf = dconf;
1098 if (APR_SUCCESS != apr_strtoff(&(conf->size), arg, NULL, 10)
1099 || conf->size <= 0) {
1100 return "CryptoSize must be a size in bytes, and greater than zero";
1107 static const char *set_crypto_driver(cmd_parms *cmd, void *config,
1111 (crypto_conf *) ap_get_module_config(cmd->server->module_config,
1114 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1120 conf->library = ap_getword_conf(cmd->pool, &arg);
1122 conf->crypto = apr_pcalloc(cmd->pool, sizeof(apr_crypto_t *));
1123 conf->library_set = 1;
1128 static const char *set_crypto_cipher(cmd_parms *cmd, void *config,
1129 const char *cipher, const char *mode)
1131 crypto_dir_conf *dconf = (crypto_dir_conf *) config;
1133 dconf->cipher = cipher;
1134 dconf->mode = mode ? mode : DEFAULT_MODE;
1135 dconf->cipher_set = 1;
1140 static const char *set_crypto_key(cmd_parms *cmd, void *config,
1143 crypto_dir_conf *dconf = (crypto_dir_conf *) config;
1145 pass_conf *key = dconf->key = apr_pcalloc(cmd->pool, sizeof(pass_conf));
1148 return parse_pass_conf_binary(cmd, key, arg);
1151 static const char *set_crypto_iv(cmd_parms *cmd, void *config,
1154 crypto_dir_conf *dconf = (crypto_dir_conf *) config;
1156 pass_conf *iv = dconf->iv = apr_pcalloc(cmd->pool, sizeof(pass_conf));
1159 return parse_pass_conf_binary(cmd, iv, arg);
1162 static const command_rec crypto_cmds[] = {
1163 AP_INIT_TAKE1("CryptoSize", set_crypto_size, NULL, ACCESS_CONF,
1164 "Maximum size of the buffer used by the crypto filters"),
1165 AP_INIT_RAW_ARGS("CryptoDriver", set_crypto_driver, NULL, RSRC_CONF,
1166 "The underlying crypto library driver to use"),
1167 AP_INIT_TAKE12("CryptoCipher", set_crypto_cipher, NULL,
1168 RSRC_CONF | OR_AUTHCFG,
1169 "The underlying crypto cipher and mode to use. If unspecified, the mode defaults to 'cbc'"),
1170 AP_INIT_TAKE1("CryptoKey", set_crypto_key, NULL, RSRC_CONF | OR_AUTHCFG,
1171 "The crypto key scheme and value to use. Scheme is one of 'none', 'file:', 'hex:', 'base64:' or 'decimal:'"),
1172 AP_INIT_TAKE1("CryptoIV", set_crypto_iv, NULL, RSRC_CONF | OR_AUTHCFG,
1173 "The crypto IV scheme and value to use. Scheme is one of 'none', 'file:', 'hex:', 'base64:' or 'decimal:'"),
1178 * Initialise the SSL in the post_config hook.
1181 crypto_init(apr_pool_t * p, apr_pool_t * plog,
1182 apr_pool_t * ptemp, server_rec *s)
1184 const apr_crypto_driver_t *driver = NULL;
1188 crypto_conf *conf = ap_get_module_config(s->module_config,
1191 if (conf->library_set && !*conf->crypto) {
1193 const apu_err_t *err = NULL;
1196 rv = apr_crypto_init(p);
1197 if (APR_SUCCESS != rv) {
1198 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
1199 APLOGNO(03427) "APR crypto could not be initialised");
1203 rv = apr_crypto_get_driver(&driver, conf->library, conf->params,
1205 if (APR_EREINIT == rv) {
1206 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s,
1207 APLOGNO(03436) "warning: crypto for '%s' was already initialised, "
1208 "using existing configuration", conf->library);
1211 if (APR_SUCCESS != rv && err) {
1212 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
1213 APLOGNO(03437) "The crypto library '%s' could not be loaded: %s (%s: %d)",
1214 conf->library, err->msg, err->reason, err->rc);
1217 if (APR_ENOTIMPL == rv) {
1218 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
1219 APLOGNO(03438) "The crypto library '%s' could not be found",
1223 if (APR_SUCCESS != rv || !driver) {
1224 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
1225 APLOGNO(03439) "The crypto library '%s' could not be loaded",
1230 rv = apr_crypto_make(conf->crypto, driver, conf->params, p);
1231 if (APR_SUCCESS != rv) {
1232 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
1233 APLOGNO(03440) "The crypto library '%s' could not be initialised",
1238 ap_log_error(APLOG_MARK, APLOG_INFO, rv, s,
1239 APLOGNO(03441) "The crypto library '%s' was loaded successfully",
1250 crypto_key(request_rec *r,
1251 apr_crypto_block_key_type_t * cipher,
1252 apr_crypto_block_key_mode_t * mode, int pad,
1253 const apr_crypto_key_rec_t ** recptr)
1255 apr_crypto_key_rec_t *rec;
1257 crypto_dir_conf *conf =
1258 ap_get_module_config(r->per_dir_config, &crypto_module);
1260 pass_conf *key = conf->key;
1262 *recptr = rec = apr_palloc(r->pool, sizeof(apr_crypto_key_rec_t));
1263 rec->ktype = APR_CRYPTO_KTYPE_SECRET;
1264 rec->type = cipher->type;
1265 rec->mode = mode->mode;
1267 rec->k.secret.secretLen = cipher->keysize;
1269 return exec_pass_conf_binary(r, key, "key", cipher->keysize,
1270 &(rec->k.secret.secret));
1274 crypto_iv(request_rec *r,
1275 apr_crypto_block_key_type_t * cipher, const unsigned char **v)
1277 crypto_dir_conf *conf =
1278 ap_get_module_config(r->per_dir_config, &crypto_module);
1280 pass_conf *iv = conf->iv;
1282 return exec_pass_conf_binary(r, iv, "iv", cipher->ivsize, v);
1285 static void register_hooks(apr_pool_t * p)
1287 ap_hook_crypto_key(crypto_key, NULL, NULL, APR_HOOK_REALLY_LAST);
1288 ap_hook_crypto_iv(crypto_iv, NULL, NULL, APR_HOOK_REALLY_LAST);
1289 ap_hook_post_config(crypto_init, NULL, NULL, APR_HOOK_LAST);
1290 ap_hook_handler(crypto_handler, NULL, NULL, APR_HOOK_MIDDLE);
1291 ap_register_output_filter("ENCRYPT", crypto_out_filter, init_encrypt,
1293 ap_register_input_filter("ENCRYPT", crypto_in_filter, init_encrypt,
1295 ap_register_output_filter("DECRYPT", crypto_out_filter, init_decrypt,
1297 ap_register_input_filter("DECRYPT", crypto_in_filter, init_decrypt,
1301 AP_DECLARE_MODULE(crypto) = {
1302 STANDARD20_MODULE_STUFF,
1303 create_crypto_dir_config, /* create per-directory config structure */
1304 merge_crypto_dir_config, /* merge per-directory config structures */
1305 create_crypto_config, /* create per-server config structure */
1306 merge_crypto_config, /* merge per-server config structures */
1307 crypto_cmds, /* command apr_table_t */
1308 register_hooks /* register hooks */
1312 #error This module requires at least v1.6.0 of apr-util.