Apache HTTPD
apr_crypto_nss.c
Go to the documentation of this file.
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#include "apr_lib.h"
18#include "apu.h"
19#include "apu_config.h"
20#include "apu_errno.h"
21
22#include <ctype.h>
23#include <stdlib.h>
24
25#include "apr_strings.h"
26#include "apr_time.h"
27#include "apr_buckets.h"
28
29#include "apr_crypto_internal.h"
30
31#if APU_HAVE_CRYPTO
32
33#include <prerror.h>
34
35#ifdef HAVE_NSS_NSS_H
36#include <nss/nss.h>
37#endif
38#ifdef HAVE_NSS_H
39#include <nss.h>
40#endif
41
42#ifdef HAVE_NSS_PK11PUB_H
43#include <nss/pk11pub.h>
44#endif
45#ifdef HAVE_PK11PUB_H
46#include <pk11pub.h>
47#endif
48
49struct apr_crypto_t {
51 const apr_crypto_driver_t *provider;
53 apr_crypto_config_t *config;
56};
57
59 void *opaque;
60};
61
62struct apr_crypto_key_t {
64 const apr_crypto_driver_t *provider;
65 const apr_crypto_t *f;
69 int ivSize;
70 int keyLength;
71};
72
73struct apr_crypto_block_t {
75 const apr_crypto_driver_t *provider;
76 const apr_crypto_t *f;
80 int blockSize;
81};
82
84{
85{ APR_KEY_3DES_192, 24, 8, 8 },
86{ APR_KEY_AES_128, 16, 16, 16 },
87{ APR_KEY_AES_192, 24, 16, 16 },
88{ APR_KEY_AES_256, 32, 16, 16 } };
89
91{
92{ APR_MODE_ECB },
93{ APR_MODE_CBC } };
94
95/* sufficient space to wrap a key */
96#define BUFFER_SIZE 128
97
102 const apr_crypto_t *f)
103{
104 *result = f->result;
105 return APR_SUCCESS;
106}
107
113static apr_status_t crypto_shutdown(void)
114{
115 if (NSS_IsInitialized()) {
117 if (s != SECSuccess) {
118 fprintf(stderr, "NSS failed to shutdown, possible leak: %d: %s",
120 return APR_EINIT;
121 }
122 }
123 return APR_SUCCESS;
124}
125
127{
128 return crypto_shutdown();
129}
130
134static apr_status_t crypto_init(apr_pool_t *pool, const char *params,
135 const apu_err_t **result)
136{
137 SECStatus s;
138 const char *dir = NULL;
139 const char *keyPrefix = NULL;
140 const char *certPrefix = NULL;
141 const char *secmod = NULL;
142 int noinit = 0;
143 PRUint32 flags = 0;
144
145 struct {
146 const char *field;
147 const char *value;
148 int set;
149 } fields[] = {
150 { "dir", NULL, 0 },
151 { "key3", NULL, 0 },
152 { "cert7", NULL, 0 },
153 { "secmod", NULL, 0 },
154 { "noinit", NULL, 0 },
155 { NULL, NULL, 0 }
156 };
157 const char *ptr;
158 size_t klen;
159 char **elts = NULL;
160 char *elt;
161 int i = 0, j;
163
164 if (params) {
165 if (APR_SUCCESS != (status = apr_tokenize_to_argv(params, &elts, pool))) {
166 return status;
167 }
168 while ((elt = elts[i])) {
169 ptr = strchr(elt, '=');
170 if (ptr) {
171 for (klen = ptr - elt; klen && apr_isspace(elt[klen - 1]); --klen)
172 ;
173 ptr++;
174 }
175 else {
176 for (klen = strlen(elt); klen && apr_isspace(elt[klen - 1]); --klen)
177 ;
178 }
179 elt[klen] = 0;
180
181 for (j = 0; fields[j].field != NULL; ++j) {
182 if (klen && !strcasecmp(fields[j].field, elt)) {
183 fields[j].set = 1;
184 if (ptr) {
185 fields[j].value = ptr;
186 }
187 break;
188 }
189 }
190
191 i++;
192 }
193 dir = fields[0].value;
194 keyPrefix = fields[1].value;
195 certPrefix = fields[2].value;
196 secmod = fields[3].value;
197 noinit = fields[4].set;
198 }
199
200 /* if we've been asked to bypass, do so here */
201 if (noinit) {
202 return APR_SUCCESS;
203 }
204
205 /* sanity check - we can only initialise NSS once */
206 if (NSS_IsInitialized()) {
207 return APR_EREINIT;
208 }
209
210 if (keyPrefix || certPrefix || secmod) {
212 }
213 else if (dir) {
215 }
216 else {
218 }
219 if (s != SECSuccess) {
220 if (result) {
221 /* Note: all memory must be owned by the caller, in case we're unloaded */
223 err->rc = PR_GetError();
225 err->reason = apr_pstrdup(pool, "Error during 'nss' initialisation");
226 *result = err;
227 }
228
229 return APR_ECRYPT;
230 }
231
234
235 return APR_SUCCESS;
236
237}
238
246{
247
248 if (block->secParam) {
249 SECITEM_FreeItem(block->secParam, PR_TRUE);
250 block->secParam = NULL;
251 }
252
253 if (block->ctx) {
255 block->ctx = NULL;
256 }
257
258 return APR_SUCCESS;
259
260}
261
263{
266}
267
269{
271 if (key->symKey) {
272 PK11_FreeSymKey(key->symKey);
273 key->symKey = NULL;
274 }
275 return APR_SUCCESS;
276}
284{
285 return APR_SUCCESS;
286}
287
289{
291 return crypto_cleanup(f);
292}
293
307 const apr_crypto_driver_t *provider, const char *params,
309{
310 apr_crypto_config_t *config = NULL;
312
313 f = apr_pcalloc(pool, sizeof(apr_crypto_t));
314 if (!f) {
315 return APR_ENOMEM;
316 }
317 *ff = f;
318 f->pool = pool;
319 f->provider = provider;
320 config = f->config = apr_pcalloc(pool, sizeof(apr_crypto_config_t));
321 if (!config) {
322 return APR_ENOMEM;
323 }
324 f->result = apr_pcalloc(pool, sizeof(apu_err_t));
325 if (!f->result) {
326 return APR_ENOMEM;
327 }
328
329 f->types = apr_hash_make(pool);
330 if (!f->types) {
331 return APR_ENOMEM;
332 }
333 apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_types[0]));
334 apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_types[1]));
335 apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_types[2]));
336 apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_types[3]));
337
338 f->modes = apr_hash_make(pool);
339 if (!f->modes) {
340 return APR_ENOMEM;
341 }
342 apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(key_modes[0]));
343 apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(key_modes[1]));
344
347
348 return APR_SUCCESS;
349
350}
351
361 const apr_crypto_t *f)
362{
363 *types = f->types;
364 return APR_SUCCESS;
365}
366
376 const apr_crypto_t *f)
377{
378 *modes = f->modes;
379 return APR_SUCCESS;
380}
381
382/*
383 * Work out which mechanism to use.
384 */
387 const apr_crypto_block_key_mode_e mode, const int doPad)
388{
389
390 /* decide on what cipher mechanism we will be using */
391 switch (type) {
392
393 case (APR_KEY_3DES_192):
394 if (APR_MODE_CBC == mode) {
395 key->cipherOid = SEC_OID_DES_EDE3_CBC;
396 }
397 else if (APR_MODE_ECB == mode) {
398 return APR_ENOCIPHER;
399 /* No OID for CKM_DES3_ECB; */
400 }
401 key->keyLength = 24;
402 break;
403 case (APR_KEY_AES_128):
404 if (APR_MODE_CBC == mode) {
405 key->cipherOid = SEC_OID_AES_128_CBC;
406 }
407 else {
408 key->cipherOid = SEC_OID_AES_128_ECB;
409 }
410 key->keyLength = 16;
411 break;
412 case (APR_KEY_AES_192):
413 if (APR_MODE_CBC == mode) {
414 key->cipherOid = SEC_OID_AES_192_CBC;
415 }
416 else {
417 key->cipherOid = SEC_OID_AES_192_ECB;
418 }
419 key->keyLength = 24;
420 break;
421 case (APR_KEY_AES_256):
422 if (APR_MODE_CBC == mode) {
423 key->cipherOid = SEC_OID_AES_256_CBC;
424 }
425 else {
426 key->cipherOid = SEC_OID_AES_256_ECB;
427 }
428 key->keyLength = 32;
429 break;
430 default:
431 /* unknown key type, give up */
432 return APR_EKEYTYPE;
433 }
434
435 /* AES_128_CBC --> CKM_AES_CBC --> CKM_AES_CBC_PAD */
436 key->cipherMech = PK11_AlgtagToMechanism(key->cipherOid);
437 if (key->cipherMech == CKM_INVALID_MECHANISM) {
438 return APR_ENOCIPHER;
439 }
440 if (doPad) {
442 paddedMech = PK11_GetPadMechanism(key->cipherMech);
444 || key->cipherMech == paddedMech) {
445 return APR_EPADDING;
446 }
447 key->cipherMech = paddedMech;
448 }
449
450 key->ivSize = PK11_GetIVLength(key->cipherMech);
451
452 return APR_SUCCESS;
453}
454
473{
475 PK11SlotInfo *slot, *tslot;
481 SECStatus s;
485 void *wincx = NULL; /* what is wincx? */
487 int blockSize;
488 int remainder;
489
490 key = *k;
491 if (!key) {
492 *k = key = apr_pcalloc(p, sizeof *key);
493 if (!key) {
494 return APR_ENOMEM;
495 }
498 }
499
500 key->f = f;
501 key->provider = f->provider;
502
503 /* decide on what cipher mechanism we will be using */
504 rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad);
505 if (APR_SUCCESS != rv) {
506 return rv;
507 }
508
509 switch (rec->ktype) {
510
512
513 /* Turn the raw passphrase and salt into SECItems */
514 passItem.data = (unsigned char*) rec->k.passphrase.pass;
515 passItem.len = rec->k.passphrase.passLen;
516 saltItem.data = (unsigned char*) rec->k.passphrase.salt;
517 saltItem.len = rec->k.passphrase.saltLen;
518
519 /* generate the key */
520 /* pbeAlg and cipherAlg are the same. */
521 algid = PK11_CreatePBEV2AlgorithmID(key->cipherOid, key->cipherOid,
522 SEC_OID_HMAC_SHA1, key->keyLength,
523 rec->k.passphrase.iterations, &saltItem);
524 if (algid) {
525 slot = PK11_GetBestSlot(key->cipherMech, wincx);
526 if (slot) {
528 wincx);
530 }
532 }
533
534 break;
535 }
536
538
539 /*
540 * NSS is by default in FIPS mode, which disallows the use of unencrypted
541 * symmetrical keys. As per http://permalink.gmane.org/gmane.comp.mozilla.crypto/7947
542 * we do the following:
543 *
544 * 1. Generate a (temporary) symmetric key in NSS.
545 * 2. Use that symmetric key to encrypt your symmetric key as data.
546 * 3. Unwrap your wrapped symmetric key, using the symmetric key
547 * you generated in Step 1 as the unwrapping key.
548 *
549 * http://permalink.gmane.org/gmane.comp.mozilla.crypto/7947
550 */
551
552 /* generate the key */
553 slot = PK11_GetBestSlot(key->cipherMech, NULL);
554 if (slot) {
555 unsigned char data[BUFFER_SIZE];
556
557 /* sanity check - key correct size? */
558 if (rec->k.secret.secretLen != key->keyLength) {
560 return APR_EKEYLENGTH;
561 }
562
564 if (tslot) {
565
566 /* generate a temporary wrapping key */
568
569 /* prepare the key to wrap */
570 secretItem.data = (unsigned char *) rec->k.secret.secret;
571 secretItem.len = rec->k.secret.secretLen;
572
573 /* ensure our key matches the blocksize */
576 remainder = rec->k.secret.secretLen % blockSize;
577 if (remainder) {
578 secretItem.data =
579 apr_pcalloc(p, rec->k.secret.secretLen + remainder);
581 rec->k.secret.secretLen);
582 memcpy(secretItem.data, rec->k.secret.secret,
583 rec->k.secret.secretLen);
584 secretItem.len += remainder;
585 }
586
587 /* prepare a space for the wrapped key */
588 wrappedItem.data = data;
589
590 /* wrap the key */
592 secParam);
593 if (ctx) {
595 (int *) (&wrappedItem.len), BUFFER_SIZE,
596 secretItem.data, secretItem.len);
597 if (s == SECSuccess) {
598
599 /* unwrap the key again */
602 key->cipherMech, CKA_ENCRYPT,
603 rec->k.secret.secretLen, 0);
604
605 }
606
608 }
609
610 /* clean up */
613 PK11_FreeSlot(tslot);
614
615 }
616
618 }
619
620 break;
621 }
622
623 default: {
624
625 return APR_ENOKEY;
626
627 }
628 }
629
630 /* sanity check? */
631 if (!key->symKey) {
633 if (perr) {
634 f->result->rc = perr;
635 f->result->msg = PR_ErrorToName(perr);
636 rv = APR_ENOKEY;
637 }
638 }
639
640 return rv;
641}
642
672 const char *pass, apr_size_t passLen, const unsigned char * salt,
674 const apr_crypto_block_key_mode_e mode, const int doPad,
675 const int iterations, const apr_crypto_t *f, apr_pool_t *p)
676{
682 void *wincx = NULL; /* what is wincx? */
683 apr_crypto_key_t *key = *k;
684
685 if (!key) {
686 *k = key = apr_pcalloc(p, sizeof *key);
687 if (!key) {
688 return APR_ENOMEM;
689 }
692 }
693
694 key->f = f;
695 key->provider = f->provider;
696
697 /* decide on what cipher mechanism we will be using */
699 if (APR_SUCCESS != rv) {
700 return rv;
701 }
702
703 /* Turn the raw passphrase and salt into SECItems */
704 passItem.data = (unsigned char*) pass;
705 passItem.len = passLen;
706 saltItem.data = (unsigned char*) salt;
707 saltItem.len = saltLen;
708
709 /* generate the key */
710 /* pbeAlg and cipherAlg are the same. */
711 algid = PK11_CreatePBEV2AlgorithmID(key->cipherOid, key->cipherOid,
713 if (algid) {
714 slot = PK11_GetBestSlot(key->cipherMech, wincx);
715 if (slot) {
717 wincx);
719 }
721 }
722
723 /* sanity check? */
724 if (!key->symKey) {
726 if (perr) {
727 f->result->rc = perr;
728 f->result->msg = PR_ErrorToName(perr);
729 rv = APR_ENOKEY;
730 }
731 }
732
733 if (ivSize) {
734 *ivSize = key->ivSize;
735 }
736
737 return rv;
738}
739
757 const unsigned char **iv, const apr_crypto_key_t *key,
759{
762 unsigned char * usedIv;
764 if (!block) {
766 }
767 if (!block) {
768 return APR_ENOMEM;
769 }
770 block->f = key->f;
771 block->pool = p;
772 block->provider = key->provider;
773
776
777 if (key->ivSize) {
778 if (iv == NULL) {
779 return APR_ENOIV;
780 }
781 if (*iv == NULL) {
782 SECStatus s;
783 usedIv = apr_pcalloc(p, key->ivSize);
784 if (!usedIv) {
785 return APR_ENOMEM;
786 }
787 apr_crypto_clear(p, usedIv, key->ivSize);
788 s = PK11_GenerateRandom(usedIv, key->ivSize);
789 if (s != SECSuccess) {
790 return APR_ENOIV;
791 }
792 *iv = usedIv;
793 }
794 else {
795 usedIv = (unsigned char *) *iv;
796 }
797 ivItem.data = usedIv;
798 ivItem.len = key->ivSize;
799 block->secParam = PK11_ParamFromIV(key->cipherMech, &ivItem);
800 }
801 else {
802 block->secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
803 }
804 block->blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
806 key->symKey, block->secParam);
807
808 /* did an error occur? */
810 if (perr || !block->ctx) {
811 key->f->result->rc = perr;
812 key->f->result->msg = PR_ErrorToName(perr);
813 return APR_EINIT;
814 }
815
816 if (blockSize) {
817 *blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
818 }
819
820 return APR_SUCCESS;
821
822}
823
842static apr_status_t crypto_block_encrypt(unsigned char **out,
843 apr_size_t *outlen, const unsigned char *in, apr_size_t inlen,
845{
846
847 unsigned char *buffer;
848 int outl = (int) *outlen;
849 SECStatus s;
850 if (!out) {
851 *outlen = inlen + block->blockSize;
852 return APR_SUCCESS;
853 }
854 if (!*out) {
855 buffer = apr_palloc(block->pool, inlen + block->blockSize);
856 if (!buffer) {
857 return APR_ENOMEM;
858 }
859 apr_crypto_clear(block->pool, buffer, inlen + block->blockSize);
860 *out = buffer;
861 }
862
863 s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*) in,
864 inlen);
865 if (s != SECSuccess) {
867 if (perr) {
868 block->f->result->rc = perr;
869 block->f->result->msg = PR_ErrorToName(perr);
870 }
871 return APR_ECRYPT;
872 }
873 *outlen = outl;
874
875 return APR_SUCCESS;
876
877}
878
897static apr_status_t crypto_block_encrypt_finish(unsigned char *out,
899{
900
902 unsigned int outl = *outlen;
903
904 SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize);
905 *outlen = outl;
906
907 if (s != SECSuccess) {
909 if (perr) {
910 block->f->result->rc = perr;
911 block->f->result->msg = PR_ErrorToName(perr);
912 }
913 rv = APR_ECRYPT;
914 }
916
917 return rv;
918
919}
920
937 apr_size_t *blockSize, const unsigned char *iv,
939{
942 if (!block) {
944 }
945 if (!block) {
946 return APR_ENOMEM;
947 }
948 block->f = key->f;
949 block->pool = p;
950 block->provider = key->provider;
951
954
955 if (key->ivSize) {
957 if (iv == NULL) {
958 return APR_ENOIV; /* Cannot initialise without an IV */
959 }
960 ivItem.data = (unsigned char*) iv;
961 ivItem.len = key->ivSize;
962 block->secParam = PK11_ParamFromIV(key->cipherMech, &ivItem);
963 }
964 else {
965 block->secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
966 }
967 block->blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
969 key->symKey, block->secParam);
970
971 /* did an error occur? */
973 if (perr || !block->ctx) {
974 key->f->result->rc = perr;
975 key->f->result->msg = PR_ErrorToName(perr);
976 return APR_EINIT;
977 }
978
979 if (blockSize) {
980 *blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
981 }
982
983 return APR_SUCCESS;
984
985}
986
1005static apr_status_t crypto_block_decrypt(unsigned char **out,
1006 apr_size_t *outlen, const unsigned char *in, apr_size_t inlen,
1008{
1009
1010 unsigned char *buffer;
1011 int outl = (int) *outlen;
1012 SECStatus s;
1013 if (!out) {
1014 *outlen = inlen + block->blockSize;
1015 return APR_SUCCESS;
1016 }
1017 if (!*out) {
1018 buffer = apr_palloc(block->pool, inlen + block->blockSize);
1019 if (!buffer) {
1020 return APR_ENOMEM;
1021 }
1022 apr_crypto_clear(block->pool, buffer, inlen + block->blockSize);
1023 *out = buffer;
1024 }
1025
1026 s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*) in,
1027 inlen);
1028 if (s != SECSuccess) {
1030 if (perr) {
1031 block->f->result->rc = perr;
1032 block->f->result->msg = PR_ErrorToName(perr);
1033 }
1034 return APR_ECRYPT;
1035 }
1036 *outlen = outl;
1037
1038 return APR_SUCCESS;
1039
1040}
1041
1060static apr_status_t crypto_block_decrypt_finish(unsigned char *out,
1062{
1063
1065 unsigned int outl = *outlen;
1066
1067 SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize);
1068 *outlen = outl;
1069
1070 if (s != SECSuccess) {
1072 if (perr) {
1073 block->f->result->rc = perr;
1074 block->f->result->msg = PR_ErrorToName(perr);
1075 }
1076 rv = APR_ECRYPT;
1077 }
1079
1080 return rv;
1081
1082}
1083
1095};
1096
1097#endif
APR-UTIL Buckets/Bucket Brigades.
APR general purpose library routines.
#define BUFFER_SIZE
APR Strings library.
APR Time Library.
APR-Util Error Codes.
#define APR_ENOMEM
Definition apr_errno.h:683
#define APR_EINIT
Definition apr_errno.h:474
const char * salt
Definition apr_md5.h:139
apr_file_t * f
apr_brigade_flush void * ctx
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
apr_pool_t const char * params
Definition apr_dbd.h:141
const char apr_ssize_t int flags
Definition apr_encode.h:168
#define APR_EREINIT
Definition apu_errno.h:85
#define APR_ENOIV
Definition apu_errno.h:65
#define APR_ECRYPT
Definition apu_errno.h:71
#define APR_EKEYTYPE
Definition apu_errno.h:67
#define APR_ENOCIPHER
Definition apu_errno.h:77
#define APR_EKEYLENGTH
Definition apu_errno.h:75
#define APR_ENOKEY
Definition apu_errno.h:63
#define APR_EPADDING
Definition apu_errno.h:73
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define apr_isspace(c)
Definition apr_lib.h:225
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
void * data
int type
char * buffer
apr_array_header_t ** result
int strcasecmp(const char *a, const char *b)
apr_ssize_t * klen
Definition apr_hash.h:71
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
void * rec
Definition apr_hash.h:270
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
apr_dir_t * dir
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
apr_int32_t in
int int status
apr_pool_t * p
Definition md_event.c:32
static apr_file_t * out
Definition mod_info.c:85
static const char *const types[]
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
static const char * key_types[]
apr_pool_t * pool
typedef int(WSAAPI *apr_winapi_fpt_WSAPoll)(IN OUT LPWSAPOLLFD fdArray