1 /* Copyright (c) 1998,2003-2006,2008 Apple Inc.
3 * asymTest.c - test CSP asymmetric encrypt/decrypt.
7 * 10 May 2000 Doug Mitchell
9 * 14 May 1998 Doug Mitchell at Apple
17 #include <Security/cssm.h>
20 #include "cspdlTesting.h"
22 #define USAGE_NAME "noUsage"
23 #define USAGE_NAME_LEN (strlen(USAGE_NAME))
24 #define USAGE2_NAME "noUsage2"
25 #define USAGE2_NAME_LEN (strlen(USAGE2_NAME))
27 #define MIN_EXP 2 /* for data size 10**exp */
28 #define DEFAULT_MAX_EXP 2
32 * Enumerate algs our own way to allow iteration.
37 #define ALG_FEE_CFILE 4
38 #define ALG_FIRST ALG_RSA
39 #define ALG_LAST ALG_FEEDEXP
40 #define MAX_DATA_SIZE (10000 + 100) /* bytes */
41 #define FEE_PASSWD_LEN 32 /* private data length in bytes, FEE only */
43 #define DUMP_KEY_DATA 0
46 * RSA encryption now allows arbitrary plaintext size. BSAFE was limited to
49 #define RSA_PLAINTEXT_LIMIT 0
51 static void usage(char **argv
)
53 printf("usage: %s [options]\n", argv
[0]);
54 printf(" Options:\n");
55 printf(" a=algorithm (f=FEED; x=FEEDExp; c=FEE_Cfile; r=RSA; default=all)\n");
56 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF
);
57 printf(" n=minExp (default=%d)\n", MIN_EXP
);
58 printf(" x=maxExp (default=%d, max=%d)\n", DEFAULT_MAX_EXP
, MAX_EXP
);
59 printf(" k=keySize\n");
60 printf(" P=primeType (m=Mersenne, f=FEE, g=general; FEE only)\n");
61 printf(" C=curveType (m=Montgomery, w=Weierstrass, g=general; FEE only)\n");
62 printf(" e(xport)\n");
63 printf(" r(eference keys only)\n");
64 printf(" K (skip decrypt)\n");
65 printf(" N(o padding, RSA only)\n");
66 printf(" S (no staging)\n");
67 printf(" D (CSP/DL; default = bare CSP)\n");
68 printf(" p (pause on each loop)\n");
69 printf(" u (quick; small keys)\n");
70 printf(" t=plainTextSize; default=random\n");
71 printf(" z(ero data)\n");
72 printf(" v(erbose)\n");
78 static int doTest(CSSM_CSP_HANDLE cspHand
,
79 CSSM_ALGORITHMS alg
, // CSSM_ALGID_xxx
84 uint32 keySizeInBits
, // may be 0, i.e., default per alg
85 uint32 primeType
, // FEE only
86 uint32 curveType
, // ditto
88 CSSM_KEYBLOB_FORMAT rawPubForm
,
90 CSSM_KEYBLOB_FORMAT rawPrivForm
,
91 CSSM_BOOL secondPubIsRaw
, // FEED via CSPDL: 2nd key must be raw
94 CSSM_BOOL mallocPtext
, // only meaningful if !stagedDecr
95 CSSM_BOOL mallocCtext
, // only meaningful if !stagedEncr
96 CSSM_BOOL skipDecrypt
,
97 CSSM_BOOL genSeed
) // FEE keys only
99 // these two are always generated
101 CSSM_KEY recvPrivKey
;
102 // these two are for two-key FEE algorithms only
104 CSSM_KEY sendPrivKey
;
105 // these two are optionally created by cspRefKeyToRaw if (FEED && secondPubIsRaw)
106 CSSM_KEY sendPubKeyRaw
;
107 CSSM_KEY recvPubKeyRaw
;
108 CSSM_BOOL rawPubKeysCreated
= CSSM_FALSE
;
110 /* two-key FEE, CSP : &{send,recv}PubKey
111 * two-key FEE, CSPDL: &{send,recv}PubKeyRaw
112 * else : NULL, &recvPubKey
114 CSSM_KEY_PTR sendPubKeyPtr
= NULL
;
115 CSSM_KEY_PTR recvPubKeyPtr
= NULL
;
117 CSSM_DATA ctext
= {0, NULL
};
118 CSSM_DATA rptext
= {0, NULL
};
122 uint32 mode
= CSSM_ALGMODE_NONE
; // FIXME - does this need testing?
123 CSSM_BOOL twoKeys
= CSSM_FALSE
;
126 case CSSM_ALGID_FEED
:
127 case CSSM_ALGID_FEECFILE
:
130 case CSSM_ALGID_FEEDEXP
:
131 keyGenAlg
= CSSM_ALGID_FEE
;
134 keyGenAlg
= CSSM_ALGID_RSA
;
137 printf("bogus algorithm\n");
141 /* one key pair for all algs except CFILE and FEED, which need two */
142 if(keyGenAlg
== CSSM_ALGID_FEE
) {
143 uint8 passwd
[FEE_PASSWD_LEN
];
144 CSSM_DATA pwdData
= {FEE_PASSWD_LEN
, passwd
};
145 CSSM_DATA_PTR pwdDataPtr
;
147 simpleGenData(&pwdData
, FEE_PASSWD_LEN
, FEE_PASSWD_LEN
);
148 pwdDataPtr
= &pwdData
;
154 * Note we always generate public keys per the pubIsRef argument, even if
155 * secondPubIsRaw is true, 'cause the CSPDL can't generate raw keys.
157 rtn
= cspGenFEEKeyPair(cspHand
,
166 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
170 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
174 return testError(quiet
);
177 rtn
= cspGenFEEKeyPair(cspHand
,
186 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
190 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
194 return testError(quiet
);
198 if(secondPubIsRaw
&& pubIsRef
) {
200 * Convert ref public keys to raw - they're going into a Context; the
201 * SecurityServer doesn't deal with ref keys there.
202 * Leak all sorts of stuff on any error here.
204 crtn
= cspRefKeyToRaw(cspHand
, &sendPubKey
, &sendPubKeyRaw
);
206 return testError(quiet
);
208 crtn
= cspRefKeyToRaw(cspHand
, &recvPubKey
, &recvPubKeyRaw
);
210 return testError(quiet
);
212 /* two keys, CSPDL */
213 sendPubKeyPtr
= &sendPubKeyRaw
;
214 recvPubKeyPtr
= &recvPubKeyRaw
;
215 rawPubKeysCreated
= CSSM_TRUE
;
219 sendPubKeyPtr
= &sendPubKey
;
220 recvPubKeyPtr
= &recvPubKey
;
224 /* one key pair, standard config */
225 sendPubKeyPtr
= NULL
;
226 recvPubKeyPtr
= &recvPubKey
;
230 CSSM_KEYBLOB_FORMAT expectPubForm
= rawPubForm
;
231 CSSM_KEYBLOB_FORMAT expectPrivForm
= rawPrivForm
;
233 rtn
= cspGenKeyPair(cspHand
,
240 twoKeys
? CSSM_KEYUSE_ANY
: CSSM_KEYUSE_ENCRYPT
,
244 twoKeys
? CSSM_KEYUSE_ANY
: CSSM_KEYUSE_DECRYPT
,
248 return testError(quiet
);
250 /* one key pair, standard config */
251 sendPubKeyPtr
= NULL
;
252 recvPubKeyPtr
= &recvPubKey
;
254 /* verify defaults - only for RSA */
256 if(rawPubForm
== CSSM_KEYBLOB_RAW_FORMAT_NONE
) {
257 expectPubForm
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
259 if(recvPubKey
.KeyHeader
.Format
!= expectPubForm
) {
260 printf("***Bad raw RSA pub key format - exp %u got %u\n",
261 (unsigned)expectPubForm
,
262 (unsigned)recvPubKey
.KeyHeader
.Format
);
263 if(testError(quiet
)) {
269 if(rawPrivForm
== CSSM_KEYBLOB_RAW_FORMAT_NONE
) {
270 expectPrivForm
= CSSM_KEYBLOB_RAW_FORMAT_PKCS8
;
272 if(recvPrivKey
.KeyHeader
.Format
!= expectPrivForm
) {
273 printf("***Bad raw RSA priv key format - exp %u got %u\n",
274 (unsigned)expectPrivForm
,
275 (unsigned)recvPrivKey
.KeyHeader
.Format
);
276 if(testError(quiet
)) {
283 dumpBuffer("Pub Key Data", recvPubKey
.KeyData
.Data
, recvPubKey
.KeyData
.Length
);
284 dumpBuffer("Priv Key Data", recvPrivKey
.KeyData
.Data
, recvPrivKey
.KeyData
.Length
);
287 crtn
= cspStagedEncrypt(cspHand
,
291 /* Two keys: second must be pub */
292 twoKeys
? &sendPrivKey
: &recvPubKey
,
293 twoKeys
? recvPubKeyPtr
: NULL
,
294 0, // effectiveKeySize
295 0, // cipherBlockSize
303 crtn
= cspEncrypt(cspHand
,
307 /* Two keys: second must be pub */
308 twoKeys
? &sendPrivKey
: &recvPubKey
,
309 twoKeys
? recvPubKeyPtr
: NULL
,
310 0, // effectiveKeySize
318 rtn
= testError(quiet
);
322 printf(" ..ptext size %lu ctext size %lu\n",
323 (unsigned long)ptext
->Length
, (unsigned long)ctext
.Length
);
329 crtn
= cspStagedDecrypt(cspHand
,
333 /* Two keys: second must be pub */
336 0, // effectiveKeySize
337 0, // cipherBlockSize
345 crtn
= cspDecrypt(cspHand
,
351 0, // effectiveKeySize
359 rtn
= testError(quiet
);
362 /* compare ptext, rptext */
363 if(ptext
->Length
!= rptext
.Length
) {
364 printf("Ptext length mismatch: expect %lu, got %lu\n",
365 (unsigned long)ptext
->Length
, (unsigned long)rptext
.Length
);
366 rtn
= testError(quiet
);
371 if(memcmp(ptext
->Data
, rptext
.Data
, ptext
->Length
)) {
372 printf("***data miscompare\n");
373 rtn
= testError(quiet
);
377 if(cspFreeKey(cspHand
, &recvPubKey
)) {
378 printf("Error freeing recvPubKey\n");
381 if(cspFreeKey(cspHand
, &recvPrivKey
)) {
382 printf("Error freeing recvPrivKey\n");
386 if(cspFreeKey(cspHand
, &sendPubKey
)) {
387 printf("Error freeing sendPubKey\n");
390 if(cspFreeKey(cspHand
, &sendPrivKey
)) {
391 printf("Error freeing sendPrivKey\n");
394 if(rawPubKeysCreated
) {
395 if(cspFreeKey(cspHand
, &sendPubKeyRaw
)) {
396 printf("Error freeing sendPubKeyRaw\n");
399 if(cspFreeKey(cspHand
, &recvPubKeyRaw
)) {
400 printf("Error freeing recvPubKeyRaw\n");
405 /* free rptext, ctext */
406 appFreeCssmData(&rptext
, CSSM_FALSE
);
407 appFreeCssmData(&ctext
, CSSM_FALSE
);
411 static const char *formStr(
412 CSSM_KEYBLOB_FORMAT form
)
415 case CSSM_KEYBLOB_RAW_FORMAT_NONE
: return "NONE";
416 case CSSM_KEYBLOB_RAW_FORMAT_PKCS1
: return "PKCS1";
417 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8
: return "PKCS8";
418 case CSSM_KEYBLOB_RAW_FORMAT_X509
: return "X509";
419 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH
: return "SSH1";
420 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2
: return "SSH2";
422 printf("***BRRRZAP! formStr needs work\n");
427 int main(int argc
, char **argv
)
433 CSSM_CSP_HANDLE cspHand
;
434 CSSM_BOOL pubIsRef
= CSSM_TRUE
;
435 CSSM_BOOL privIsRef
= CSSM_TRUE
;
436 CSSM_BOOL stagedEncr
;
437 CSSM_BOOL stagedDecr
;
439 uint32 encAlg
; // CSSM_ALGID_xxx
440 unsigned currAlg
; // ALG_xxx
442 CSSM_BOOL mallocCtext
;
443 CSSM_BOOL mallocPtext
;
445 CSSM_BOOL genSeed
; // for FEE key gen
446 CSSM_PADDING padding
;
447 CSSM_KEYBLOB_FORMAT rawPubFormat
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
448 CSSM_KEYBLOB_FORMAT rawPrivFormat
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
453 unsigned loops
= LOOPS_DEF
;
454 CSSM_BOOL verbose
= CSSM_FALSE
;
455 unsigned minExp
= MIN_EXP
;
456 unsigned maxExp
= DEFAULT_MAX_EXP
;
457 CSSM_BOOL quiet
= CSSM_FALSE
;
458 uint32 keySizeInBits
= CSP_KEY_SIZE_DEFAULT
;
459 CSSM_BOOL keySizeSpec
= CSSM_FALSE
;
460 unsigned minAlg
= ALG_FIRST
;
461 uint32 maxAlg
= ALG_LAST
;
462 CSSM_BOOL skipDecrypt
= CSSM_FALSE
;
463 CSSM_BOOL bareCsp
= CSSM_TRUE
;
464 CSSM_BOOL doPause
= CSSM_FALSE
;
465 CSSM_BOOL smallKeys
= CSSM_FALSE
;
466 uint32 primeType
= CSSM_FEE_PRIME_TYPE_DEFAULT
; // FEE only
467 uint32 curveType
= CSSM_FEE_CURVE_TYPE_DEFAULT
; // FEE only
468 uint32 ptextSize
= 0; // 0 means random
469 dataType dtype
= DT_Random
;
470 CSSM_BOOL refKeysOnly
= CSSM_FALSE
;
471 CSSM_BOOL noPadding
= CSSM_FALSE
;
472 CSSM_BOOL stagingEnabled
= CSSM_TRUE
;
474 for(arg
=1; arg
<argc
; arg
++) {
483 minAlg
= maxAlg
= ALG_FEED
;
486 minAlg
= maxAlg
= ALG_FEEDEXP
;
489 minAlg
= maxAlg
= ALG_FEE_CFILE
;
492 minAlg
= maxAlg
= ALG_RSA
;
503 loops
= atoi(&argp
[2]);
506 minExp
= atoi(&argp
[2]);
509 maxExp
= atoi(&argp
[2]);
510 if(maxExp
> MAX_EXP
) {
515 keySizeInBits
= atoi(&argv
[arg
][2]);
516 keySizeSpec
= CSSM_TRUE
;
519 skipDecrypt
= CSSM_TRUE
;
522 ptextSize
= atoi(&argp
[2]);
525 bareCsp
= CSSM_FALSE
;
526 #if CSPDL_ALL_KEYS_ARE_REF
527 refKeysOnly
= CSSM_TRUE
;
531 smallKeys
= CSSM_TRUE
;
534 noPadding
= CSSM_TRUE
;
543 refKeysOnly
= CSSM_TRUE
;
546 stagingEnabled
= CSSM_FALSE
;
557 curveType
= CSSM_FEE_CURVE_TYPE_MONTGOMERY
;
560 curveType
= CSSM_FEE_CURVE_TYPE_WEIERSTRASS
;
569 primeType
= CSSM_FEE_PRIME_TYPE_MERSENNE
;
572 primeType
= CSSM_FEE_PRIME_TYPE_FEE
;
575 primeType
= CSSM_FEE_PRIME_TYPE_GENERAL
;
586 ptext
.Data
= (uint8
*)CSSM_MALLOC(MAX_DATA_SIZE
);
588 /* length set in test loop */
589 if(ptext
.Data
== NULL
) {
590 printf("Insufficient heap\n");
595 printf("**WARNING NoPad mode will fail with random plaintext size\n");
598 printf("**WARNING NoPad mode will fail with random key size\n");
601 uint32 keyBytes
= keySizeInBits
/ 8;
602 if(ptextSize
!= keyBytes
) {
604 * FIXME: I actually do not understand why this fails, but
605 * doing raw RSA encryption with ptextSize != keySize results
606 * in random-looking failures, probably based on the plaintext
607 * itself (it doesn't fail with zero data).
609 printf("***WARNING NoPad mode requires plaintext size = key size\n");
613 printf("Starting asymTest; args: ");
614 for(i
=1; i
<argc
; i
++) {
615 printf("%s ", argv
[i
]);
618 cspHand
= cspDlDbStartup(bareCsp
, NULL
);
622 for(currAlg
=minAlg
; currAlg
<=maxAlg
; currAlg
++) {
625 encAlg
= CSSM_ALGID_FEED
;
627 padding
= CSSM_PADDING_NONE
;
630 encAlg
= CSSM_ALGID_FEEDEXP
;
632 padding
= CSSM_PADDING_NONE
;
635 encAlg
= CSSM_ALGID_FEECFILE
;
636 algStr
= "FEE_CFILE";
637 padding
= CSSM_PADDING_NONE
;
640 encAlg
= CSSM_ALGID_RSA
;
643 padding
= CSSM_PADDING_NONE
;
646 padding
= CSSM_PADDING_PKCS1
;
651 printf("Testing alg %s\n", algStr
);
653 for(loop
=1; ; loop
++) {
656 printf("Top of loop; hit CR to proceed: ");
660 if(dtype
== DT_Zero
) {
661 memset(ptext
.Data
, 0, ptextSize
);
662 ptext
.Length
= ptextSize
;
665 simpleGenData(&ptext
, ptextSize
, ptextSize
);
669 ptext
.Length
= genData(ptext
.Data
, minExp
, maxExp
, dtype
);
672 /* raw RSA, no padding, ensure top two bits are zero */
673 if((encAlg
== CSSM_ALGID_RSA
) && (padding
== CSSM_PADDING_NONE
)) {
674 ptext
.Data
[0] &= 0x3f;
678 /* random per alg unless user overrides */
679 if(encAlg
== CSSM_ALGID_RSA
) {
681 keySizeInBits
= CSP_RSA_KEY_SIZE_DEFAULT
;
684 keySizeInBits
= randKeySizeBits(CSSM_ALGID_RSA
, OT_Encrypt
);
691 /* default curveType = Weierstrass */
694 randFeeKeyParams(encAlg
,
701 #if RSA_PLAINTEXT_LIMIT
702 if(encAlg
== CSSM_ALGID_RSA
) {
703 /* total ptext size can't exceed (modulus size - 11) */
704 /* we should probably get this from the CSP, but this
705 * whole thing is such a kludge. What's the point?
706 * Only RSA encrypt/decrypt has a max total size.
710 if(keySizeInBits
== CSP_KEY_SIZE_DEFAULT
) {
711 modSize
= CSP_RSA_KEY_SIZE_DEFAULT
/ 8;
714 modSize
= keySizeInBits
/ 8;
716 maxSize
= modSize
- 11;
717 ptext
.Length
= genRand(1, maxSize
);
721 if(encAlg
== CSSM_ALGID_RSA
) {
722 printf("..loop %d text size %lu keySize %u\n",
723 loop
, (unsigned long)ptext
.Length
, (unsigned)keySizeInBits
);
726 printf("..loop %d text size %lu keySize %u primeType %s "
728 loop
, (unsigned long)ptext
.Length
, (unsigned)keySizeInBits
,
729 primeTypeStr(primeType
), curveTypeStr(curveType
));
733 /* mix up some ref and data keys, as well as staging and mallocing */
735 pubIsRef
= (loop
& 1) ? CSSM_TRUE
: CSSM_FALSE
;
736 privIsRef
= (loop
& 8) ? CSSM_TRUE
: CSSM_FALSE
;
738 if((currAlg
== ALG_FEE_CFILE
) || !stagingEnabled
) {
739 /* staged ops unsupported */
740 stagedEncr
= CSSM_FALSE
;
741 stagedDecr
= CSSM_FALSE
;
744 stagedEncr
= (loop
& 2) ? CSSM_TRUE
: CSSM_FALSE
;
745 stagedDecr
= (loop
& 4) ? CSSM_TRUE
: CSSM_FALSE
;
748 mallocCtext
= (ptext
.Data
[0] & 1) ? CSSM_TRUE
: CSSM_FALSE
;
751 mallocCtext
= CSSM_FALSE
;
754 mallocPtext
= (ptext
.Data
[0] & 2) ? CSSM_TRUE
: CSSM_FALSE
;
757 mallocPtext
= CSSM_FALSE
;
762 genSeed
= (ptext
.Data
[0] & 4) ? CSSM_TRUE
: CSSM_FALSE
;
765 genSeed
= CSSM_FALSE
;
767 rawPubFormat
= rawPrivFormat
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
768 if(currAlg
== ALG_RSA
) {
769 /* mix up raw key formats */
773 die
= ptext
.Data
[1] % 5;
776 rawPubFormat
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
779 rawPubFormat
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
782 rawPubFormat
= CSSM_KEYBLOB_RAW_FORMAT_OPENSSH
;
785 rawPubFormat
= CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2
;
788 rawPubFormat
= CSSM_KEYBLOB_RAW_FORMAT_X509
;
794 die
= ptext
.Data
[2] % 4;
797 rawPrivFormat
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
800 rawPrivFormat
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
803 rawPrivFormat
= CSSM_KEYBLOB_RAW_FORMAT_OPENSSH
;
806 rawPrivFormat
= CSSM_KEYBLOB_RAW_FORMAT_PKCS8
;
812 if(encAlg
== CSSM_ALGID_RSA
) {
813 /* FIXME - another restriction - the MS bits of each block
814 * of plaintext must be zero, to make the numerical value of the
815 * block less than the modulus!
816 * Aug 7 1998: Now that we're using AI_PKCS_RSA{Public,Private}, the
817 * numerical value of the data no longer has to be less than
820 stagedEncr
= stagedDecr
= CSSM_TRUE
;
825 printf(" pubRef %d privRef %d stgEncr %d stgdDecr %d "
826 "malPtext %d malCtext %d genSeed %d pubForm %s privForm %s\n",
827 (int)pubIsRef
, (int)privIsRef
, (int)stagedEncr
, (int)stagedDecr
,
828 (int)mallocPtext
, (int)mallocCtext
, (int)genSeed
,
829 formStr(rawPubFormat
), formStr(rawPrivFormat
));
844 #if CSPDL_2ND_PUB_KEY_IS_RAW
846 bareCsp
? CSSM_FALSE
: CSSM_TRUE
,
859 if(loops
&& (loop
== loops
)) {
865 CSSM_ModuleDetach(cspHand
);
866 if((rtn
== 0) && !quiet
) {
867 printf("%s test complete\n", argv
[0]);