]> granicus.if.org Git - apache/blob - modules/filters/mod_crypto.c
for the time being, rename as ProxyProtocolFilter to avoid
[apache] / modules / filters / mod_crypto.c
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /*
18  * mod_crypto.c --- Encrypt / decrypt data in the input and output filter
19  *                  stacks.
20  */
21
22 #include "mod_crypto.h"
23 #include "apr_lib.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"
31 #endif
32 #include "util_filter.h"
33 #include "http_log.h"
34 #include "http_request.h"
35 #include "http_protocol.h"
36 #include "ap_expr.h"
37
38 #if APR_VERSION_AT_LEAST(2,0,0) || \
39     (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 6)
40
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,
44                                       (request_rec *r,
45                                       apr_crypto_block_key_type_t * cipher,
46                                       apr_crypto_block_key_mode_t * mode,
47                                       int pad,
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,
51                                       (request_rec *r,
52                                       apr_crypto_block_key_type_t * cipher,
53                                       const unsigned char **iv), (r, cipher,
54                                       iv), DECLINED)
55 module AP_MODULE_DECLARE_DATA crypto_module;
56
57 #define DEFAULT_BUFFER_SIZE 128*1024
58 #define DEFAULT_CIPHER "aes256"
59 #define DEFAULT_MODE "cbc"
60 #define CRYPTO_KEY "crypto_context"
61
62 typedef struct pass_conf
63 {
64     const char *scheme;
65     const ap_expr_info_t *expr;
66     unsigned char *raw;
67     apr_size_t size;
68 } pass_conf;
69
70 /**
71  * Structure to carry the server wide session config.
72  */
73 typedef struct
74 {
75     const char *library;
76     const char *params;
77     apr_crypto_t **crypto;
78     int library_set;
79 } crypto_conf;
80
81 typedef struct crypto_dir_conf
82 {
83     apr_off_t size;        /* size of the buffer */
84     int size_set;          /* has the size been set */
85     const char *cipher;
86     const char *mode;
87     int cipher_set;
88     pass_conf *key;
89     int key_set;
90     pass_conf *iv;
91     int iv_set;
92 } crypto_dir_conf;
93
94 typedef struct crypto_ctx
95 {
96     apr_bucket_brigade *bb;
97     apr_bucket_brigade *tmp;
98     crypto_dir_conf *conf;
99     unsigned char *out;
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;
105     apr_off_t remaining;
106     apr_off_t written;
107     apr_size_t osize;
108     int seen_eos:1;
109     int encrypt:1;
110     int clength:1;
111 } crypto_ctx;
112
113 static const char *parse_pass_conf_binary(cmd_parms *cmd,
114                                           pass_conf * pass,
115                                           const char *arg)
116 {
117     apr_status_t rv;
118     char ps = *arg;
119
120     if ('f' == ps && !strncmp(arg, "file:", 5)) {
121         const char *name;
122
123         arg += 5;
124         if (!*arg) {
125             return apr_pstrcat(cmd->pool, "No filename specified", NULL);
126         }
127
128         name = ap_server_root_relative(cmd->temp_pool, arg);
129         if (name) {
130             apr_file_t *file;
131
132             rv = apr_file_open(&file, name, APR_FOPEN_READ,
133                                APR_FPROT_OS_DEFAULT, cmd->temp_pool);
134             if (APR_SUCCESS == rv) {
135                 apr_finfo_t finfo;
136
137                 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, file);
138                 if (rv == APR_SUCCESS) {
139                     apr_size_t size;
140
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);
145
146                     rv = apr_file_read_full(file, pass->raw, pass->size,
147                                             &size);
148                     if (APR_SUCCESS == rv && size != pass->size) {
149                         rv = APR_EGENERAL;
150                     }
151
152                 }
153             }
154             if (APR_SUCCESS != rv) {
155                 char buf[120];
156                 return apr_pstrcat(cmd->pool, "Unable to load from file '",
157                                    arg, "': ", apr_strerror(rv, buf,
158                                                             sizeof(buf)),
159                                    NULL);
160             }
161         }
162         else {
163             return apr_pstrcat(cmd->pool, "Unable to locate file from name ",
164                                arg, NULL);
165         }
166     }
167
168     else if ('h' == ps && (!strncmp(arg, "hex:", 4))) {
169         const char *expr_err = NULL;
170         arg += 4;
171
172         if (!*arg) {
173             return apr_pstrcat(cmd->temp_pool,
174                                "Cannot parse expression, it is blank", NULL);
175         }
176
177         pass->scheme = "hex";
178         pass->expr = ap_expr_parse_cmd(cmd, arg, AP_EXPR_FLAG_STRING_RESULT,
179                                        &expr_err, NULL);
180
181         if (expr_err) {
182             return apr_pstrcat(cmd->temp_pool, "Cannot parse ", pass->scheme,
183                                " expression '", arg, "' in: ", expr_err,
184                                NULL);
185         }
186
187     }
188
189     else if ('b' == ps && !strncmp(arg, "base64:", 7)) {
190         const char *expr_err = NULL;
191         arg += 7;
192
193         if (!*arg) {
194             return apr_pstrcat(cmd->temp_pool,
195                                "Cannot parse expression, it is blank", NULL);
196         }
197
198         pass->scheme = "base64";
199         pass->expr = ap_expr_parse_cmd(cmd, arg, AP_EXPR_FLAG_STRING_RESULT,
200                                        &expr_err, NULL);
201
202         if (expr_err) {
203             return apr_pstrcat(cmd->temp_pool, "Cannot parse ", pass->scheme,
204                                " expression '", arg, "' in: ", expr_err,
205                                NULL);
206         }
207
208     }
209
210     else if ('d' == ps && !strncmp(arg, "decimal:", 8)) {
211         const char *expr_err = NULL;
212         arg += 8;
213
214         if (!*arg) {
215             return apr_pstrcat(cmd->temp_pool,
216                                "Cannot parse expression, it is blank", NULL);
217         }
218
219         pass->scheme = "decimal";
220         pass->expr = ap_expr_parse_cmd(cmd, arg, AP_EXPR_FLAG_STRING_RESULT,
221                                        &expr_err, NULL);
222
223         if (expr_err) {
224             return apr_pstrcat(cmd->temp_pool, "Cannot parse ", pass->scheme,
225                                " expression '", arg, "' in: ", expr_err,
226                                NULL);
227         }
228
229     }
230
231     else if ('n' == ps && !strcmp(arg, "none")) {
232         pass->scheme = arg;
233     }
234
235     else {
236         return apr_pstrcat(cmd->pool,
237                            "Scheme must be 'file:', 'hex:', 'base64:', 'decimal:' or 'none': ",
238                            arg, NULL);
239     }
240
241     return NULL;
242 }
243
244 static apr_status_t
245 exec_pass_conf_binary(request_rec *r, pass_conf * pass,
246                       const char *description, apr_size_t size,
247                       const unsigned char **k)
248 {
249
250     if (pass) {
251
252         if (pass->raw) {
253             *k = pass->raw;
254
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);
260                 return APR_EGENERAL;
261             }
262
263             return APR_SUCCESS;
264         }
265
266         else if (pass->expr) {
267             char ps = *pass->scheme;
268             const char *err = NULL;
269
270             const char *arg = ap_expr_str_exec(r, pass->expr, &err);
271             if (err) {
272                 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
273                               APLOGNO(03410) "%s could not be parsed: %s",
274                               description, err);
275                 return APR_EGENERAL;
276             }
277
278             /* hex */
279             if ('h' == ps) {
280                 apr_size_t len;
281                 unsigned char *b;
282
283                 apr_unescape_hex(NULL, arg, strlen(arg), 1, &len);
284                 if (len < size) {
285                     b = apr_palloc(r->pool, size);
286                     memset(b, 0, size - len);
287                     apr_unescape_hex(b + size - len, arg, strlen(arg), 1,
288                                      &len);
289                 }
290                 else {
291                     b = apr_palloc(r->pool, len);
292                     apr_unescape_hex(b, arg, strlen(arg), 1, NULL);
293                     b += len - size;
294                 }
295                 *k = b;
296
297             }
298
299             /* base64 */
300             else if ('b' == ps) {
301                 apr_size_t len;
302                 unsigned char *b;
303
304                 len = apr_base64_decode_len(arg);
305                 if (len < size) {
306                     b = apr_palloc(r->pool, size);
307                     memset(b, 0, size - len);
308                     apr_base64_decode_binary(b + size - len, arg);
309                 }
310                 else {
311                     b = apr_palloc(r->pool, len);
312                     apr_base64_decode_binary(b, arg);
313                     b += len - size;
314                 }
315                 *k = b;
316
317             }
318
319             /* decimal */
320             else if ('d' == ps) {
321                 apr_size_t len;
322                 unsigned char *b;
323                 char n[8];
324                 apr_uint64_t t;
325                 int i;
326
327                 t = (apr_uint64_t) apr_atoi64(arg);
328
329                 for (i = 7; i >= 0; i--) {
330                     n[i] = t & 0xFF;
331                     t = t >> 8;
332                 }
333
334                 len = sizeof(n);
335                 if (len < size) {
336                     b = apr_palloc(r->pool, size);
337                     memset(b, 0, size - len);
338                     memcpy(b + size - len, n, len);
339                 }
340                 else {
341                     b = apr_palloc(r->pool, len);
342                     memcpy(b, n, len);
343                     b += len - size;
344                 }
345                 *k = b;
346
347             }
348
349         }
350
351     }
352
353     return DECLINED;
354 }
355
356 static apr_status_t
357 init_cipher(request_rec *r,
358             apr_crypto_block_key_type_t ** cipher,
359             apr_crypto_block_key_mode_t ** mode)
360 {
361     apr_status_t rv;
362     apr_hash_t *ciphers;
363     apr_hash_t *modes;
364
365     crypto_conf *conf = ap_get_module_config(r->server->module_config,
366                                              &crypto_module);
367     crypto_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
368                                                   &crypto_module);
369
370     if (cipher) {
371
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");
376             return rv;
377         }
378
379         *cipher = apr_hash_get(ciphers, dconf->cipher, APR_HASH_KEY_STRING);
380         if (!*cipher) {
381             apr_hash_index_t *hi;
382             const void *key;
383             apr_ssize_t klen;
384             int sum = 0;
385             int offset = 0;
386             char *options = NULL;
387
388             for (hi = apr_hash_first(r->pool, ciphers); hi;
389                  hi = apr_hash_next(hi)) {
390                 apr_hash_this(hi, NULL, &klen, NULL);
391                 sum += klen + 2;
392             }
393             for (hi = apr_hash_first(r->pool, ciphers); hi;
394                  hi = apr_hash_next(hi)) {
395                 apr_hash_this(hi, &key, &klen, NULL);
396                 if (!options) {
397                     options = apr_palloc(r->pool, sum + 1);
398                 }
399                 else {
400                     options[offset++] = ',';
401                     options[offset++] = ' ';
402                 }
403                 strncpy(options + offset, key, klen);
404                 offset += klen;
405             }
406             options[offset] = 0;
407
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);
411
412             return rv;
413         }
414
415     }
416
417     if (mode) {
418
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");
423             return rv;
424         }
425
426         *mode = apr_hash_get(modes, dconf->mode, APR_HASH_KEY_STRING);
427         if (!*mode) {
428             apr_hash_index_t *hi;
429             const void *key;
430             apr_ssize_t klen;
431             int sum = 0;
432             int offset = 0;
433             char *options = NULL;
434
435             for (hi = apr_hash_first(r->pool, modes); hi;
436                  hi = apr_hash_next(hi)) {
437                 apr_hash_this(hi, NULL, &klen, NULL);
438                 sum += klen + 2;
439             }
440             for (hi = apr_hash_first(r->pool, modes); hi;
441                  hi = apr_hash_next(hi)) {
442                 apr_hash_this(hi, &key, &klen, NULL);
443                 if (!options) {
444                     options = apr_palloc(r->pool, sum + 1);
445                 }
446                 else {
447                     options[offset++] = ',';
448                     options[offset++] = ' ';
449                 }
450                 strncpy(options + offset, key, klen);
451                 offset += klen;
452             }
453             options[offset] = 0;
454
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);
458
459             return rv;
460         }
461
462     }
463
464     return APR_SUCCESS;
465 }
466
467 static apr_status_t init_crypt(ap_filter_t * f)
468 {
469     apr_status_t rv;
470     crypto_ctx *ctx = f->ctx;
471     const apr_crypto_key_rec_t *rec;
472
473     crypto_conf *conf = ap_get_module_config(f->r->server->module_config,
474                                              &crypto_module);
475     crypto_dir_conf *dconf =
476         ap_get_module_config(f->r->per_dir_config, &crypto_module);
477
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");
482         return APR_EGENERAL;
483     }
484
485     /* initial setup of the context */
486     ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
487     ctx->conf = dconf;
488     ctx->remaining = ctx->conf->size;
489     ctx->written = 0;
490     ctx->osize = ctx->conf->size;
491
492     /* fetch the cipher for this location */
493     rv = init_cipher(f->r, &ctx->cipher, &ctx->mode);
494     if (APR_SUCCESS != rv) {
495         return rv;
496     }
497
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);
504         return APR_EGENERAL;
505     }
506
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");
512         return APR_ENOKEY;
513     }
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");
517         return APR_ENOKEY;
518     }
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");
522         return APR_ENOKEY;
523     }
524
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");
530     }
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");
534     }
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");
538     }
539     if (APR_SUCCESS != rv) {
540         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
541                       APLOGNO(03420) "encryption could not be configured.");
542         return rv;
543     }
544
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");
550         return rv;
551     }
552
553     return APR_SUCCESS;
554 }
555
556 static int init_encrypt(ap_filter_t * f)
557 {
558     apr_status_t rv;
559     crypto_ctx *ctx;
560
561     ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
562     ctx->encrypt = 1;
563
564     rv = init_crypt(f);
565     if (APR_SUCCESS != rv) {
566         return HTTP_INTERNAL_SERVER_ERROR;
567     }
568
569     return OK;
570 }
571
572 static int init_decrypt(ap_filter_t * f)
573 {
574     apr_status_t rv;
575     crypto_ctx *ctx;
576
577     ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
578     ctx->encrypt = 0;
579
580     rv = init_crypt(f);
581     if (APR_SUCCESS != rv) {
582         return HTTP_INTERNAL_SERVER_ERROR;
583     }
584
585     return OK;
586 }
587
588 /**
589  * Run the crypto algorithm, write to ctx->out
590  */
591 static apr_status_t
592 do_crypto(ap_filter_t * f, unsigned char *in, apr_off_t size, int finish)
593 {
594     apr_status_t rv;
595     crypto_ctx *ctx = f->ctx;
596     apr_off_t extra = 0;
597     apr_size_t blockSize = 0;
598     int need_iv = (ctx->iv == NULL);
599     unsigned char *out;
600     apr_size_t written;
601
602     /* encrypt the given buffer */
603     if (ctx->encrypt) {
604
605         if (!ctx->block) {
606             rv = apr_crypto_block_encrypt_init(&ctx->block, &ctx->iv,
607                                                ctx->key, &blockSize,
608                                                f->r->pool);
609             if (APR_SUCCESS != rv) {
610                 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
611                               APLOGNO(03421) "could not initialise encryption");
612                 return rv;
613             }
614         }
615
616         if (!ctx->out) {
617
618             if (need_iv && ctx->iv) {
619                 ctx->osize += blockSize;
620             }
621
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);
626
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;
631                 out += blockSize;
632                 extra = blockSize;
633             }
634
635         }
636         else {
637             out = ctx->out + (ctx->osize - ctx->remaining);
638         }
639
640         if (!finish) {
641             rv = apr_crypto_block_encrypt(&out, &written, in, size,
642                                           ctx->block);
643             if (APR_SUCCESS != rv) {
644                 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
645                               APLOGNO(03422) "crypto: attempt to encrypt failed");
646                 return rv;
647             }
648         }
649
650         else {
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");
655                 return rv;
656             }
657         }
658     }
659
660     /* decrypt the given buffer */
661     else {
662
663         if (!ctx->out) {
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);
668         }
669         else {
670             out = ctx->out + (ctx->osize - ctx->remaining);
671         }
672
673         /* no precomputed iv? assume the first block in the stream is the iv */
674         if (need_iv) {
675             apr_off_t isize =
676                 ctx->cipher->blocksize - (ctx->osize - ctx->remaining);
677             if (size < isize) {
678                 memcpy(out, in, size);
679                 ctx->remaining -= size;
680                 return APR_SUCCESS;
681             }
682             else {
683                 memcpy(out, in, isize);
684                 ctx->remaining -= isize;
685                 out += isize;
686                 ctx->iv = ctx->out;
687             }
688         }
689
690         if (!ctx->block) {
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");
696                 return rv;
697             }
698         }
699
700         if (!finish) {
701             rv = apr_crypto_block_decrypt(&out, &written, in, size,
702                                           ctx->block);
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?)");
706                 return rv;
707             }
708         }
709         else {
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?)");
714                 return rv;
715             }
716         }
717     }
718
719     ctx->remaining -= written;
720     ctx->written += written;
721     ctx->written += extra;
722
723     return rv;
724 }
725
726 /**
727  * Encrypt/decrypt buckets being written to the output filter stack.
728  */
729 static apr_status_t
730 crypto_out_filter(ap_filter_t * f, apr_bucket_brigade * bb)
731 {
732     apr_bucket *e, *after;
733     crypto_ctx *ctx = f->ctx;
734     apr_status_t rv = APR_SUCCESS;
735
736     /* Do nothing if asked to filter nothing. */
737     if (APR_BRIGADE_EMPTY(bb)) {
738         return ap_pass_brigade(f->next, bb);
739     }
740
741     /* clear the content length */
742     if (!ctx->clength) {
743         ctx->clength = 1;
744         apr_table_unset(f->r->headers_out, "Content-Length");
745     }
746
747     /* make sure we fit in the buffer snugly */
748     if (APR_BRIGADE_EMPTY(ctx->bb)) {
749         apr_brigade_partition(bb, ctx->remaining, &after);
750     }
751
752     while (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(bb)) {
753         const char *data;
754         apr_size_t size;
755
756         e = APR_BRIGADE_FIRST(bb);
757
758         /* EOS means we are done. */
759         if (APR_BUCKET_IS_EOS(e)) {
760
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;
766             ctx->written = 0;
767             apr_brigade_partition(bb, ctx->remaining, &after);
768
769             /* pass the EOS across */
770             APR_BUCKET_REMOVE(e);
771             APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
772
773             /* pass what we have down the chain */
774             rv = ap_pass_brigade(f->next, ctx->bb);
775
776             ap_remove_output_filter(f);
777             continue;
778         }
779
780         /* handle flush */
781         if (APR_BUCKET_IS_FLUSH(e)) {
782
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
786              * arrives in full.
787              */
788
789             /* pass the flush bucket across */
790             APR_BUCKET_REMOVE(e);
791             APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
792
793             /* pass what we have down the chain */
794             rv = ap_pass_brigade(f->next, ctx->bb);
795             continue;
796         }
797
798         /* metadata buckets are preserved as is */
799         if (APR_BUCKET_IS_METADATA(e)) {
800             /*
801              * Remove meta data bucket from old brigade and insert into the
802              * new.
803              */
804             APR_BUCKET_REMOVE(e);
805             APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
806             continue;
807         }
808
809         if (APR_SUCCESS
810             == (rv = apr_bucket_read(e, &data, &size, APR_BLOCK_READ))) {
811
812             do_crypto(f, (unsigned char *) data, size, 0);
813             apr_bucket_delete(e);
814
815             if (!ctx->remaining) {
816                 apr_brigade_write(ctx->bb, NULL, NULL,
817                                   (const char *) ctx->out, ctx->written);
818                 ctx->remaining = ctx->osize;
819                 ctx->written = 0;
820                 apr_brigade_partition(bb, ctx->remaining, &after);
821                 rv = ap_pass_brigade(f->next, ctx->bb);
822             }
823
824         }
825
826     }
827
828     return rv;
829
830 }
831
832 /**
833  * Decrypt/encrypt buckets being read from the input filter stack.
834  */
835 static apr_status_t
836 crypto_in_filter(ap_filter_t * f, apr_bucket_brigade * bb,
837                  ap_input_mode_t mode, apr_read_type_e block,
838                  apr_off_t readbytes)
839 {
840     apr_bucket *e, *after;
841     apr_status_t rv = APR_SUCCESS;
842     crypto_ctx *ctx = f->ctx;
843
844     if (!ctx->tmp) {
845         ctx->tmp = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
846     }
847
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);
851     }
852
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;
856         ctx->written = 0;
857
858         while (!ctx->seen_eos && ctx->remaining > 0) {
859             const char *data;
860             apr_size_t size = 0;
861
862             if (APR_BRIGADE_EMPTY(ctx->tmp)) {
863                 rv = ap_get_brigade(f->next, ctx->tmp, mode, block,
864                                     ctx->remaining);
865             }
866
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.
873              */
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)) {
879                     return rv;
880                 }
881                 break;
882             }
883             if (APR_SUCCESS != rv) {
884                 return rv;
885             }
886
887             while (!APR_BRIGADE_EMPTY(ctx->tmp)) {
888                 e = APR_BRIGADE_FIRST(ctx->tmp);
889
890                 /* if we see an EOS, we are done */
891                 if (APR_BUCKET_IS_EOS(e)) {
892
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);
897
898                     APR_BUCKET_REMOVE(e);
899                     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
900                     ctx->seen_eos = 1;
901                     break;
902                 }
903
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);
908                     break;
909                 }
910
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);
915                     continue;
916                 }
917
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)) {
922                         return rv;
923                     }
924                     break;
925                 }
926                 if (APR_SUCCESS != rv) {
927                     return rv;
928                 }
929
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);
934                 }
935
936                 apr_bucket_delete(e);
937
938             }
939         }
940     }
941
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);
945     while (e != after) {
946         if (APR_BUCKET_IS_EOS(e)) {
947             /* last bucket read, step out of the way */
948             ap_remove_input_filter(f);
949         }
950         APR_BUCKET_REMOVE(e);
951         APR_BRIGADE_INSERT_TAIL(bb, e);
952         e = APR_BRIGADE_FIRST(ctx->bb);
953     }
954
955     /* clear the content length */
956     if (!ctx->clength) {
957         ctx->clength = 1;
958         apr_table_unset(f->r->headers_in, "Content-Length");
959     }
960
961     return APR_SUCCESS;
962 }
963
964 static int crypto_handler(request_rec *r)
965 {
966     crypto_conf *conf;
967     crypto_dir_conf *dconf;
968     apr_status_t rv;
969
970     if (*r->handler != 'c' || strcmp(r->handler, "crypto-key")) {
971         return DECLINED;
972     }
973
974     conf = ap_get_module_config(r->server->module_config, &crypto_module);
975     dconf = ap_get_module_config(r->per_dir_config, &crypto_module);
976
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");
981         return APR_EGENERAL;
982     }
983
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;
988
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;
993         }
994
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;
1001         }
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;
1006         }
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;
1011         }
1012
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);
1016
1017         return OK;
1018
1019     }
1020     else {
1021
1022         return HTTP_NOT_FOUND;
1023
1024     }
1025
1026 }
1027
1028 static void *create_crypto_config(apr_pool_t * p, server_rec *s)
1029 {
1030     crypto_conf *new = (crypto_conf *) apr_pcalloc(p, sizeof(crypto_conf));
1031
1032     /* if no library has been configured, set the recommended library
1033      * as a sensible default.
1034      */
1035 #ifdef APU_CRYPTO_RECOMMENDED_DRIVER
1036     new->library = APU_CRYPTO_RECOMMENDED_DRIVER;
1037 #endif
1038     new->crypto = apr_pcalloc(p, sizeof(apr_crypto_t *));
1039
1040     return (void *) new;
1041 }
1042
1043 static void *merge_crypto_config(apr_pool_t * p, void *basev, void *addv)
1044 {
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;
1048
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;
1052
1053     new->crypto = base->crypto;
1054
1055     return (void *) new;
1056 }
1057
1058 static void *create_crypto_dir_config(apr_pool_t * p, char *dummy)
1059 {
1060     crypto_dir_conf *new =
1061         (crypto_dir_conf *) apr_pcalloc(p, sizeof(crypto_dir_conf));
1062
1063     new->size = DEFAULT_BUFFER_SIZE;    /* default size */
1064     new->cipher = DEFAULT_CIPHER;
1065     new->mode = DEFAULT_MODE;
1066
1067     return (void *) new;
1068 }
1069
1070 static void *merge_crypto_dir_config(apr_pool_t * p, void *basev, void *addv)
1071 {
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;
1076
1077     new->size = (add->size_set == 0) ? base->size : add->size;
1078     new->size_set = add->size_set || base->size_set;
1079
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;
1083
1084     new->key = (add->key_set == 0) ? base->key : add->key;
1085     new->key_set = add->key_set || base->key_set;
1086
1087     new->iv = (add->iv_set == 0) ? base->iv : add->iv;
1088     new->iv_set = add->iv_set || base->iv_set;
1089
1090     return new;
1091 }
1092
1093 static const char *set_crypto_size(cmd_parms *cmd, void *dconf,
1094                                    const char *arg)
1095 {
1096     crypto_dir_conf *conf = dconf;
1097
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";
1101     }
1102     conf->size_set = 1;
1103
1104     return NULL;
1105 }
1106
1107 static const char *set_crypto_driver(cmd_parms *cmd, void *config,
1108                                      const char *arg)
1109 {
1110     crypto_conf *conf =
1111         (crypto_conf *) ap_get_module_config(cmd->server->module_config,
1112                                              &crypto_module);
1113
1114     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1115
1116     if (err != NULL) {
1117         return err;
1118     }
1119
1120     conf->library = ap_getword_conf(cmd->pool, &arg);
1121     conf->params = arg;
1122     conf->crypto = apr_pcalloc(cmd->pool, sizeof(apr_crypto_t *));
1123     conf->library_set = 1;
1124
1125     return NULL;
1126 }
1127
1128 static const char *set_crypto_cipher(cmd_parms *cmd, void *config,
1129                                      const char *cipher, const char *mode)
1130 {
1131     crypto_dir_conf *dconf = (crypto_dir_conf *) config;
1132
1133     dconf->cipher = cipher;
1134     dconf->mode = mode ? mode : DEFAULT_MODE;
1135     dconf->cipher_set = 1;
1136
1137     return NULL;
1138 }
1139
1140 static const char *set_crypto_key(cmd_parms *cmd, void *config,
1141                                   const char *arg)
1142 {
1143     crypto_dir_conf *dconf = (crypto_dir_conf *) config;
1144
1145     pass_conf *key = dconf->key = apr_pcalloc(cmd->pool, sizeof(pass_conf));
1146     dconf->key_set = 1;
1147
1148     return parse_pass_conf_binary(cmd, key, arg);
1149 }
1150
1151 static const char *set_crypto_iv(cmd_parms *cmd, void *config,
1152                                  const char *arg)
1153 {
1154     crypto_dir_conf *dconf = (crypto_dir_conf *) config;
1155
1156     pass_conf *iv = dconf->iv = apr_pcalloc(cmd->pool, sizeof(pass_conf));
1157     dconf->iv_set = 1;
1158
1159     return parse_pass_conf_binary(cmd, iv, arg);
1160 }
1161
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:'"),
1174     {NULL}
1175 };
1176
1177 /**
1178  * Initialise the SSL in the post_config hook.
1179  */
1180 static int
1181 crypto_init(apr_pool_t * p, apr_pool_t * plog,
1182             apr_pool_t * ptemp, server_rec *s)
1183 {
1184     const apr_crypto_driver_t *driver = NULL;
1185
1186     while (s) {
1187
1188         crypto_conf *conf = ap_get_module_config(s->module_config,
1189                                                  &crypto_module);
1190
1191         if (conf->library_set && !*conf->crypto) {
1192
1193             const apu_err_t *err = NULL;
1194             apr_status_t rv;
1195
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");
1200                 return rv;
1201             }
1202
1203             rv = apr_crypto_get_driver(&driver, conf->library, conf->params,
1204                                        &err, p);
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);
1209                 rv = APR_SUCCESS;
1210             }
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);
1215                 return rv;
1216             }
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",
1220                              conf->library);
1221                 return rv;
1222             }
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",
1226                              conf->library);
1227                 return rv;
1228             }
1229
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",
1234                              conf->library);
1235                 return rv;
1236             }
1237
1238             ap_log_error(APLOG_MARK, APLOG_INFO, rv, s,
1239                          APLOGNO(03441) "The crypto library '%s' was loaded successfully",
1240                          conf->library);
1241
1242         }
1243         s = s->next;
1244     }
1245
1246     return OK;
1247 }
1248
1249 static apr_status_t
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)
1254 {
1255     apr_crypto_key_rec_t *rec;
1256
1257     crypto_dir_conf *conf =
1258         ap_get_module_config(r->per_dir_config, &crypto_module);
1259
1260     pass_conf *key = conf->key;
1261
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;
1266     rec->pad = pad;
1267     rec->k.secret.secretLen = cipher->keysize;
1268
1269     return exec_pass_conf_binary(r, key, "key", cipher->keysize,
1270                                  &(rec->k.secret.secret));
1271 }
1272
1273 static apr_status_t
1274 crypto_iv(request_rec *r,
1275           apr_crypto_block_key_type_t * cipher, const unsigned char **v)
1276 {
1277     crypto_dir_conf *conf =
1278         ap_get_module_config(r->per_dir_config, &crypto_module);
1279
1280     pass_conf *iv = conf->iv;
1281
1282     return exec_pass_conf_binary(r, iv, "iv", cipher->ivsize, v);
1283 }
1284
1285 static void register_hooks(apr_pool_t * p)
1286 {
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,
1292                               AP_FTYPE_RESOURCE);
1293     ap_register_input_filter("ENCRYPT", crypto_in_filter, init_encrypt,
1294                              AP_FTYPE_RESOURCE);
1295     ap_register_output_filter("DECRYPT", crypto_out_filter, init_decrypt,
1296                               AP_FTYPE_RESOURCE);
1297     ap_register_input_filter("DECRYPT", crypto_in_filter, init_decrypt,
1298                              AP_FTYPE_RESOURCE);
1299 }
1300
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 */
1309 };
1310
1311 #else
1312 #error This module requires at least v1.6.0 of apr-util.
1313 #endif