1 /* Copyright (c) 1998,2003-2005 Apple Computer, Inc.
3 * miniWrap.c - simple key wrap/unwrap exerciser.
7 * 4 May 2000 Doug Mitchell
9 * 22 May 1998 Doug Mitchell at Apple
17 #include <Security/cssm.h>
20 #include "cspdlTesting.h"
23 * Temporary hack to use CSSM_KEYBLOB_WRAPPED_FORMAT_{PKCS7,PKCS8}, which
24 * are no longer supported as of 7/28/00
26 #define PKCS8_FORMAT_ENABLE 1
27 #define PKCS7_FORMAT_ENABLE 0
29 #define ENCR_USAGE_NAME "noLabel"
30 #define ENCR_USAGE_NAME_LEN (strlen(ENCR_USAGE_NAME))
31 #define WRAP_USAGE_NAME "noWrapLabel"
32 #define WRAP_USAGE_NAME_LEN (strlen(WRAP_USAGE_NAME))
34 #define MAX_PTEXT_SIZE 1000
38 * A new restriction for X: when wrapping using an RSA key, you can't
39 * wrap a key which is bigger than the RSA key itself because the
40 * wrap (Encrypt) is a one-shot deal, unlike the OS9 CSP which
41 * handled multiple chunks. This only effectively restricts the
42 * use of an RSA key to wrap symmetric keys, which doesn't seem like
43 * an unreasonable restriction.
45 #define RSA_WRAP_RESTRICTION 1
48 * Currently the CSP can use wrapping keys flagged exclusively for wrapping
49 * (CSSM_KEYUSE_{WRAP,UNWRAP} for the actual wrap sinceĆthe wrap/unwrap op is
50 * done with an encrypt/decrypt op. The WrapKey op doesn't even see the
51 * wrapping key - it's in the context we pass it. Thus for now wrap/unwrap
52 * keys have to be marked with CSSM_KEYUSE_ANY.
54 #define WRAP_USAGE_ANY 0
56 static void usage(char **argv
)
58 printf("usage: %s [options]\n", argv
[0]);
59 printf(" Options:\n");
60 printf(" f (only wrap RSA private key)\n");
61 printf(" d (only wrap DES key)\n");
62 printf(" S (do symmetric wrap only)\n");
63 printf(" a (do asymmetric wrap only)\n");
64 printf(" n (do null wrap only)\n");
65 printf(" m (dump malloc info)\n");
66 printf(" r (ref keys only)\n");
67 printf(" w (wrap only)\n");
68 printf(" e (export)\n");
69 printf(" q (quiet)\n");
70 printf(" k (force PKCS7/8)\n");
71 #if PKCS7_FORMAT_ENABLE || PKCS8_FORMAT_ENABLE
72 printf(" K (skip PKCS7/8) (pkcs normally enable)\n");
74 printf(" K (allow PKCS7/8) (pkcs normally disabled)\n");
75 #endif /* PKCS_FORMAT_ENABLE */
76 printf(" D (CSP/DL; default = bare CSP)\n");
77 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF
);
78 printf(" p(ause every %d loops)\n", LOOP_PAUSE
);
83 /* not all algs need this, pass it in anyway */
84 CSSM_DATA initVector
= {8, (uint8
*)"someVect"};
87 * local verbose wrap/unwrap functions.
89 /* wrap key function. */
90 static CSSM_RETURN
wrapKey(CSSM_CSP_HANDLE cspHand
,
91 const CSSM_KEY_PTR unwrappedKey
, // must be ref
92 const CSSM_KEY_PTR wrappingKey
,
93 CSSM_ALGORITHMS wrapAlg
,
94 CSSM_ENCRYPT_MODE wrapMode
,
95 CSSM_KEYBLOB_FORMAT wrapFormat
, // NONE, PKCS7, PKCS8
97 CSSM_KEY_PTR wrappedKey
) // RETURNED
99 CSSM_CC_HANDLE ccHand
;
102 #if WRAP_KEY_REQUIRES_CREDS
103 CSSM_ACCESS_CREDENTIALS creds
;
107 if(unwrappedKey
->KeyHeader
.BlobType
!= CSSM_KEYBLOB_REFERENCE
) {
108 printf("Hey! you can only wrap a reference key!\n");
109 return CSSM_ERRCODE_INTERNAL_ERROR
;
112 memset(wrappedKey
, 0, sizeof(CSSM_KEY
));
113 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
114 /* special case for NULL wrap - no wrapping key */
115 if((wrappingKey
== NULL
) ||
116 (wrappingKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_SESSION_KEY
)) {
117 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
120 &creds
, // accessCred
127 printError("cspWrapKey/CreateContext", crtn
);
128 return CSSM_ERRCODE_INTERNAL_ERROR
;
132 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
134 &creds
, // passPhrase
139 printError("cspWrapKey/CreateContext", crtn
);
140 return CSSM_ERRCODE_INTERNAL_ERROR
;
142 /* CMS requires 8-byte IV */
143 crtn
= AddContextAttribute(ccHand
,
144 CSSM_ATTRIBUTE_INIT_VECTOR
,
150 printError("CSSM_UpdateContextAttributes", crtn
);
154 if(wrapFormat
!= CSSM_KEYBLOB_WRAPPED_FORMAT_NONE
) {
155 /* only add this attribute if it's not the default */
156 CSSM_CONTEXT_ATTRIBUTE attr
;
157 attr
.AttributeType
= CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
;
158 attr
.AttributeLength
= sizeof(uint32
);
159 attr
.Attribute
.Uint32
= wrapFormat
;
160 crtn
= CSSM_UpdateContextAttributes(
165 printError("CSSM_UpdateContextAttributes", crtn
);
169 crtn
= CSSM_WrapKey(ccHand
,
170 #if WRAP_KEY_REQUIRES_CREDS
176 NULL
, // DescriptiveData
178 if(crtn
!= CSSM_OK
) {
179 printError("CSSM_WrapKey", crtn
);
181 if((crtn2
= CSSM_DeleteContext(ccHand
))) {
182 printError("CSSM_DeleteContext", crtn2
);
187 /* unwrap key function. */
188 static CSSM_RETURN
unwrapKey(CSSM_CSP_HANDLE cspHand
,
189 const CSSM_KEY_PTR wrappedKey
,
190 const CSSM_KEY_PTR unwrappingKey
,
191 CSSM_ALGORITHMS unwrapAlg
,
192 CSSM_ENCRYPT_MODE unwrapMode
,
193 CSSM_PADDING unwrapPad
,
194 CSSM_KEY_PTR unwrappedKey
, // RETURNED
195 const unsigned char *keyLabel
,
196 unsigned keyLabelLen
)
198 CSSM_CC_HANDLE ccHand
;
203 CSSM_DATA descData
= { 0, NULL
};
204 CSSM_ACCESS_CREDENTIALS creds
;
206 memset(unwrappedKey
, 0, sizeof(CSSM_KEY
));
207 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
208 if((unwrappingKey
== NULL
) ||
209 (unwrappingKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_SESSION_KEY
)) {
210 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
213 &creds
, // accessCreds
216 unwrapPad
, // Padding
220 printError("cspUnwrapKey/CreateContext", crtn
);
221 return CSSM_ERRCODE_INTERNAL_ERROR
;
225 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
227 &creds
, // passPhrase,
229 unwrapPad
, // Padding
232 printError("cspUnwrapKey/CreateContext", crtn
);
233 return CSSM_ERRCODE_INTERNAL_ERROR
;
235 /* CMS requires 8-byte IV */
236 crtn
= AddContextAttribute(ccHand
,
237 CSSM_ATTRIBUTE_INIT_VECTOR
,
243 printError("CSSM_UpdateContextAttributes", crtn
);
247 labelData
.Data
= (uint8
*)keyLabel
;
248 labelData
.Length
= keyLabelLen
;
251 * New keyAttr - clear some old bits, make sure we ask for ref key
253 keyAttr
= wrappedKey
->KeyHeader
.KeyAttr
;
254 keyAttr
&= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE
| CSSM_KEYATTR_NEVER_EXTRACTABLE
);
255 keyAttr
|= CSSM_KEYATTR_RETURN_REF
;
256 crtn
= CSSM_UnwrapKey(ccHand
,
259 CSSM_KEYUSE_ANY
, // FIXME
262 NULL
, // CredAndAclEntry
264 &descData
); // required
265 if(crtn
!= CSSM_OK
) {
266 printError("CSSM_UnwrapKey", crtn
);
268 if((crtn2
= CSSM_DeleteContext(ccHand
))) {
269 printError("CSSM_DeleteContext", crtn2
);
274 #define UNWRAPPED_LABEL "unwrapped thing"
278 static int doTest(CSSM_CSP_HANDLE cspHand
,
279 CSSM_KEY_PTR encrKey
,
280 CSSM_KEY_PTR decrKey
, // we wrap this one
281 CSSM_KEY_PTR wrappingKey
, // ...using this key, NULL for null wrap
282 CSSM_KEY_PTR unwrappingKey
,
283 CSSM_ALGORITHMS wrapAlg
,
284 CSSM_ENCRYPT_MODE wrapMode
,
285 CSSM_PADDING wrapPad
,
286 CSSM_ALGORITHMS encrAlg
,
287 CSSM_ENCRYPT_MODE encrMode
,
288 CSSM_PADDING encrPad
,
290 uint32 maxPtextSize
, // max size to encrypt
295 #else /* NULL_TEST */
297 * NULL Wrapping decrKey - a private key - only works for DEBUG CSPs.
298 * We'll always wrap decrKey, except for NULL wrap when
299 * NULL_WRAP_DECR_KEY is false.
301 #define NULL_WRAP_DECR_KEY 1
303 static int doTest(CSSM_CSP_HANDLE cspHand
,
304 CSSM_KEY_PTR encrKey
, // we wrap this one
305 CSSM_KEY_PTR decrKey
, // ...or this one, depending on WRAP_DECR_KEY
306 CSSM_KEY_PTR wrappingKey
, // ...using this key, NULL for null wrap
307 CSSM_KEY_PTR unwrappingKey
,
308 CSSM_ALGORITHMS wrapAlg
,
309 CSSM_ENCRYPT_MODE wrapMode
,
310 CSSM_KEYBLOB_FORMAT wrapFormat
, // NONE, PKCS7, PKCS8
311 CSSM_PADDING wrapPad
,
312 CSSM_ALGORITHMS encrAlg
,
313 CSSM_ENCRYPT_MODE encrMode
,
314 CSSM_PADDING encrPad
,
316 uint32 maxPtextSize
, // max size to encrypt
323 CSSM_KEY unwrappedKey
;
325 CSSM_KEY_PTR realEncrKey
; // encrKey or &unwrappedKey
326 CSSM_KEY_PTR realDecrKey
; // decrKey or &unwrappedKey
328 /* wrap decrKey or encrKey using wrappingKey ==> wrappedKey */
329 if((wrappingKey
== NULL
) && !NULL_WRAP_DECR_KEY
) {
330 /* NULL wrap of pub key */
331 crtn
= wrapKey(cspHand
,
339 realEncrKey
= &unwrappedKey
;
340 realDecrKey
= decrKey
;
343 /* normal case, wrap priv key (may be NULL if NULL_WRAP_DECR_KEY) */
344 crtn
= wrapKey(cspHand
,
352 realEncrKey
= encrKey
;
353 realDecrKey
= &unwrappedKey
;
357 return testError(quiet
);
359 if((wrappingKey
!= NULL
) && // skip for NULL wrap
360 (wrapFormat
!= CSSM_KEYBLOB_WRAPPED_FORMAT_NONE
)) {
361 /* don't want default, verify we got what we want */
362 if(wrappedKey
.KeyHeader
.Format
!= wrapFormat
) {
363 printf("wrapped key format mismatch: expect %u; got %u\n",
364 (unsigned)wrapFormat
, (unsigned)wrappedKey
.KeyHeader
.Format
);
365 if(testError(quiet
)) {
371 cspFreeKey(cspHand
, &wrappedKey
);
374 /* unwrap wrappedKey using unwrappingKey ==> unwrappedKey; */
375 crtn
= unwrapKey(cspHand
,
382 (uint8
*)UNWRAPPED_LABEL
,
385 return testError(quiet
);
389 ptext
.Data
= (uint8
*)CSSM_MALLOC(maxPtextSize
);
390 simpleGenData(&ptext
, 1, maxPtextSize
);
391 /* encrypt using realEncrKey ==> ctext */
394 crtn
= cspEncrypt(cspHand
,
400 0, // effectiveKeySize
405 CSSM_TRUE
); // mallocCtext
407 return testError(quiet
);
410 /* decrypt ctext with realDecrKey ==> rptext; */
413 crtn
= cspDecrypt(cspHand
,
419 0, // effectiveKeySize
426 return testError(quiet
);
429 /* compare ptext vs. rptext; */
430 if(ptext
.Length
!= rptext
.Length
) {
431 printf("ptext length mismatch\n");
432 return testError(quiet
);
434 if(memcmp(ptext
.Data
, rptext
.Data
, ptext
.Length
)) {
435 printf("***data miscompare\n");
436 return testError(quiet
);
439 cspFreeKey(cspHand
, &wrappedKey
);
440 cspFreeKey(cspHand
, &unwrappedKey
);
441 CSSM_FREE(ptext
.Data
);
442 CSSM_FREE(ctext
.Data
);
443 CSSM_FREE(rptext
.Data
);
447 #endif /* NULL_TEST */
449 int main(int argc
, char **argv
)
454 CSSM_CSP_HANDLE cspHand
;
456 CSSM_KEY origPub
; // we generate if !desSubj
458 CSSM_KEY_PTR origSess
; // we generate if desSubj
459 CSSM_KEY_PTR origEncrKey
; // pts to origPub or origSess
460 CSSM_KEY_PTR origDecrKey
; // pts to origPriv or origSess
461 CSSM_ALGORITHMS encrAlg
;
462 CSSM_ENCRYPT_MODE encrMode
;
463 CSSM_PADDING encrPad
;
467 CSSM_BOOL encrIsRef
= CSSM_TRUE
;
468 CSSM_BOOL decrIsRef
= CSSM_TRUE
;
469 CSSM_KEYBLOB_FORMAT wrapFormat
= CSSM_KEYBLOB_WRAPPED_FORMAT_NONE
;
472 /* user-specified vars */
473 unsigned loops
= LOOPS_DEF
;
474 CSSM_BOOL pause
= CSSM_FALSE
;
475 CSSM_BOOL doSymmWrap
= CSSM_TRUE
;
476 CSSM_BOOL doAsymmWrap
= CSSM_TRUE
;
477 CSSM_BOOL doNullWrap
= CSSM_TRUE
;
478 CSSM_BOOL doSymmEncrOnly
= CSSM_FALSE
;
479 CSSM_BOOL doAsymmEncrOnly
= CSSM_FALSE
;
480 CSSM_BOOL wrapOnly
= CSSM_FALSE
;
481 CSSM_BOOL quiet
= CSSM_FALSE
;
482 CSSM_BOOL bareCsp
= CSSM_TRUE
;
483 CSSM_BOOL forcePkcs
= CSSM_FALSE
;
484 CSSM_BOOL refKeysOnly
= CSSM_FALSE
;
485 #if PKCS_FORMAT_ENABLE
486 CSSM_BOOL skipPkcs
= CSSM_FALSE
;
488 CSSM_BOOL skipPkcs
= CSSM_TRUE
;
491 for(arg
=1; arg
<argc
; arg
++) {
495 doAsymmWrap
= CSSM_FALSE
;
496 doNullWrap
= CSSM_FALSE
;
499 doSymmWrap
= CSSM_FALSE
;
500 doNullWrap
= CSSM_FALSE
;
503 doSymmWrap
= CSSM_FALSE
;
504 doAsymmWrap
= CSSM_FALSE
;
507 doAsymmEncrOnly
= CSSM_TRUE
;
509 case 'd': // symmetric encrypt only option
510 case 'e': // export option - avoids asymetric encrypt/decrypt
511 doSymmEncrOnly
= CSSM_TRUE
;
514 loops
= atoi(&argp
[2]);
517 wrapOnly
= CSSM_TRUE
;
523 bareCsp
= CSSM_FALSE
;
524 #if CSPDL_ALL_KEYS_ARE_REF
525 refKeysOnly
= CSSM_TRUE
;
529 forcePkcs
= CSSM_TRUE
;
532 #if PKCS7_FORMAT_ENABLE || PKCS8_FORMAT_ENABLE
533 skipPkcs
= CSSM_TRUE
;
535 skipPkcs
= CSSM_FALSE
;
539 refKeysOnly
= CSSM_TRUE
;
550 #if !PKCS_FORMAT_ENABLE
552 if(doAsymmEncrOnly
) {
553 printf("Asymmetric keys can only be wrapped via PKCS; aborting\n");
556 else if(!doSymmWrap
) {
557 printf("AsymmetricWrapping can only be done via PKCS; aborting\n");
560 doSymmEncrOnly
= CSSM_TRUE
;
561 doSymmWrap
= CSSM_TRUE
;
562 doAsymmWrap
= CSSM_FALSE
;
564 #endif /* !PKCS_FORMAT_ENABLE */
567 cspHand
= cspDlDbStartup(bareCsp
, NULL
);
572 printf("Starting miniWrap; args: ");
573 for(i
=1; i
<argc
; i
++) {
574 printf("%s ", argv
[i
]);
578 for(loop
=1; ; loop
++) {
579 if((loop
% LOOP_PAUSE
) == 0) {
581 printf("...loop %d\n", loop
);
585 printf("Hit CR to proceed: ");
590 /* mix up ref and raw keys - with X, we can wrap a raw key */
592 encrIsRef
= (loop
& 2) ? CSSM_TRUE
: CSSM_FALSE
;
593 decrIsRef
= (loop
& 4) ? CSSM_TRUE
: CSSM_FALSE
;
596 /* first generate key to be wrapped */
597 if(!doAsymmEncrOnly
&& (doSymmEncrOnly
|| ((loop
& 1) == 0))) {
599 printf("...wrapping DES key (%s)\n",
600 encrIsRef
? "ref" : "raw");
602 origSess
= cspGenSymKey(cspHand
,
606 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
607 CSP_KEY_SIZE_DEFAULT
,
609 if(origSess
== NULL
) {
613 origDecrKey
= origEncrKey
= origSess
;
614 encrAlg
= CSSM_ALGID_DES
;
615 encrMode
= CSSM_ALGMODE_CBCPadIV8
;
616 encrPad
= CSSM_PADDING_PKCS5
;
617 maxPtextSize
= MAX_PTEXT_SIZE
; // i.e., unlimited
622 if(!doSymmEncrOnly
&& (doAsymmEncrOnly
|| ((loop
& 1) == 1))) {
624 printf("...wrapping RSA key (pub %s priv %s)\n",
625 (encrIsRef
? "ref" : "raw"),
626 (decrIsRef
? "ref" : "raw"));
628 crtn
= cspGenKeyPair(cspHand
,
632 CSP_KEY_SIZE_DEFAULT
,
634 encrIsRef
, // pubIsRef
636 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
638 decrIsRef
, // privIsRef
640 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
641 CSSM_FALSE
); // genSeed
646 origDecrKey
= &origPriv
;
647 origEncrKey
= &origPub
;
648 encrAlg
= CSSM_ALGID_RSA
;
649 encrMode
= CSSM_ALGMODE_NONE
;
650 encrPad
= CSSM_PADDING_PKCS1
;
651 genRsaKey
= CSSM_TRUE
;
652 maxPtextSize
= origPriv
.KeyHeader
.LogicalKeySizeInBits
/ 8;
653 // a weird BSAFE requirement which is not documented
657 genRsaKey
= CSSM_FALSE
;
660 /* now the tests, symmetric and/or asymmetric wrapping */
662 CSSM_KEY_PTR wrapKey
;
664 printf(" ...Doing symmetric wrap\n");
666 wrapKey
= cspGenSymKey(cspHand
,
670 /* for now, wrapping keys have to have keyuse_any */
671 /* CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP, */
672 WRAP_USAGE_ANY
? CSSM_KEYUSE_ANY
:
673 CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
,
674 CSP_KEY_SIZE_DEFAULT
,
675 CSSM_TRUE
); // FIXME - try both
676 if(wrapKey
== NULL
) {
681 /* symmetric wrapping key ==> PKCS7 */
682 wrapFormat
= CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7
;
686 wrapFormat
= CSSM_KEYBLOB_WRAPPED_FORMAT_NONE
;
693 CSSM_ALGID_DES
, // wrapAlg
694 CSSM_ALGMODE_CBCPadIV8
, // wrapMode
696 CSSM_PADDING_PKCS5
, // wrapPad
706 cspFreeKey(cspHand
, wrapKey
);
707 CSSM_FREE(wrapKey
); // mallocd by cspGenSymKey
711 !(RSA_WRAP_RESTRICTION
&& (origEncrKey
!= origDecrKey
))) {
712 /* skip wrapping asymmetric key with asymmetric key */
713 CSSM_KEY wrapPrivKey
;
717 printf(" ...Doing asymmetric wrap\n");
719 crtn
= cspGenKeyPair(cspHand
,
723 CSP_RSA_KEY_SIZE_DEFAULT
,
725 CSSM_TRUE
, // both are ref
726 WRAP_USAGE_ANY
? CSSM_KEYUSE_ANY
: CSSM_KEYUSE_WRAP
,
727 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
729 CSSM_TRUE
, // FIXME privIsRef
730 WRAP_USAGE_ANY
? CSSM_KEYUSE_ANY
: CSSM_KEYUSE_UNWRAP
,
731 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
732 CSSM_FALSE
); // genSeed
738 /* asymmetric wrapping key ==> PKCS8 */
739 wrapFormat
= CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8
;
742 wrapFormat
= CSSM_KEYBLOB_WRAPPED_FORMAT_NONE
;
749 CSSM_ALGID_RSA
, // wrapAlg
750 CSSM_ALGMODE_NONE
, // wrapMode
752 CSSM_PADDING_PKCS1
, // wrapPad
762 cspFreeKey(cspHand
, &wrapPubKey
);
763 cspFreeKey(cspHand
, &wrapPrivKey
);
765 //if(doNullWrap && (origDecrKey != origEncrKey)) {
767 /* with X, we can do NULL wrap/unwrap of any key */
769 printf(" ...Doing NULL wrap\n");
776 CSSM_ALGID_NONE
, // wrapAlg
777 CSSM_ALGMODE_NONE
, // wrapMode
778 CSSM_KEYBLOB_WRAPPED_FORMAT_NONE
,
779 CSSM_PADDING_NONE
, // wrapPad
791 if(origSess
!= NULL
) {
792 cspFreeKey(cspHand
, origSess
);
796 cspFreeKey(cspHand
, &origPub
);
797 cspFreeKey(cspHand
, &origPriv
);
799 if(loops
&& (loop
== loops
)) {
804 CSSM_ModuleDetach(cspHand
);
805 if((rtn
== 0) && !quiet
) {
806 printf("%s test complete\n", argv
[0]);