2 * macCompat.c - test compatibilty of two different implementations of a
3 * given MAC algorithm - one in the standard AppleCSP,
6 * Written by Doug Mitchell.
12 #include <Security/cssm.h>
13 #include <Security/cssmapple.h>
16 #include "bsafeUtils.h"
18 #include "cspdlTesting.h"
19 #include <openssl/hmac.h>
25 #define MIN_EXP 2 /* for data size 10**exp */
26 #define DEFAULT_MAX_EXP 4
29 #define MAX_DATA_SIZE (100000 + 100) /* bytes */
30 #define MIN_KEY_SIZE 20 /* bytes - should be smaller */
31 #define MAX_KEY_SIZE 64 /* bytes */
32 #define LOOP_NOTIFY 20
35 * Enumerate algs our own way to allow iteration.
39 #define ALG_SHA1_LEGACY 3
40 #define ALG_FIRST ALG_MD5
41 #define ALG_LAST ALG_SHA1_LEGACY
43 static void usage(char **argv
)
45 printf("usage: %s [options]\n", argv
[0]);
46 printf(" Options:\n");
47 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF
);
48 printf(" n=minExp (default=%d)\n", MIN_EXP
);
49 printf(" x=maxExp (default=%d, max=%d)\n", DEFAULT_MAX_EXP
, MAX_EXP
);
50 printf(" k=keySizeInBytes\n");
51 printf(" P=plainTextLen\n");
52 printf(" z (keys and plaintext all zeroes)\n");
53 printf(" p=pauseInterval (default=0, no pause)\n");
54 printf(" D (CSP/DL; default = bare CSP)\n");
55 printf(" v(erbose)\n");
62 * generate MAC using reference BSAFE with either one update
63 * (updateSizes == NULL) or specified set of update sizes.
65 static CSSM_RETURN
genMacBSAFE(
66 CSSM_ALGORITHMS macAlg
,
67 const CSSM_DATA
*key
, // raw key bytes
68 const CSSM_DATA
*inText
,
69 unsigned *updateSizes
, // NULL --> random updates
70 // else null-terminated list of sizes
71 CSSM_DATA_PTR outText
) // mallocd and returned
76 crtn
= buGenSymKey(key
->Length
* 8, key
, &buKey
);
80 crtn
= buGenMac(buKey
,
90 * Produce HMACMD5 with openssl.
92 static int doHmacMD5Ref(
93 const CSSM_DATA
*key
, // raw key bytes
94 const CSSM_DATA
*inText
,
95 CSSM_DATA_PTR outText
) // mallocd and returned
97 const EVP_MD
*md
= EVP_md5();
99 appSetupCssmData(outText
, 16);
100 HMAC(md
, key
->Data
, (int)key
->Length
,
101 inText
->Data
, inText
->Length
,
102 (unsigned char *)outText
->Data
, &md_len
);
107 * Generate MAC, CSP, specified set of update sizes
109 static CSSM_RETURN
cspGenMacWithSizes(CSSM_CSP_HANDLE cspHand
,
111 CSSM_KEY_PTR key
, // session key
112 const CSSM_DATA
*text
,
113 unsigned *updateSizes
, // null-terminated list of sizes
114 CSSM_DATA_PTR mac
) // RETURNED
116 CSSM_CC_HANDLE macHand
;
118 CSSM_DATA currData
= *text
;
120 crtn
= CSSM_CSP_CreateMacContext(cspHand
,
125 printError("CSSM_CSP_CreateMacContext", crtn
);
128 crtn
= CSSM_GenerateMacInit(macHand
);
130 printError("CSSM_GenerateMacInit", crtn
);
137 while(*updateSizes
) {
138 currData
.Length
= *updateSizes
;
139 crtn
= CSSM_GenerateMacUpdate(macHand
,
143 printError("CSSM_GenerateMacUpdate", crtn
);
146 currData
.Data
+= *updateSizes
;
149 crtn
= CSSM_GenerateMacFinal(macHand
, mac
);
151 printError("CSSM_GenerateMacFinal", crtn
);
154 crtn
= CSSM_DeleteContext(macHand
);
156 printError("CSSM_DeleteContext", crtn
);
162 * Verify MAC, CSP, specified set of update sizes
164 static CSSM_RETURN
cspVfyMacWithSizes(CSSM_CSP_HANDLE cspHand
,
166 CSSM_KEY_PTR key
, // session key
167 const CSSM_DATA
*text
,
168 unsigned *updateSizes
, // null-terminated list of sizes
169 const CSSM_DATA
*mac
)
171 CSSM_CC_HANDLE macHand
;
173 CSSM_DATA currData
= *text
;
175 crtn
= CSSM_CSP_CreateMacContext(cspHand
,
180 printError("CSSM_CSP_CreateMacContext", crtn
);
183 crtn
= CSSM_VerifyMacInit(macHand
);
185 printError("CSSM_VerifyMacInit", crtn
);
189 while(*updateSizes
) {
190 currData
.Length
= *updateSizes
;
191 crtn
= CSSM_VerifyMacUpdate(macHand
,
195 printError("CSSM_GenerateMacUpdate", crtn
);
198 currData
.Data
+= *updateSizes
;
201 crtn
= CSSM_VerifyMacFinal(macHand
, mac
);
203 printError("CSSM_GenerateMacFinal", crtn
);
206 crtn
= CSSM_DeleteContext(macHand
);
208 printError("CSSM_DeleteContext", crtn
);
214 * Generate or verify MAC using CSP with either random-sized staged updates
215 * (updateSizes == NULL) or specified set of update sizes.
217 static CSSM_RETURN
genMacCSSM(
218 CSSM_CSP_HANDLE cspHand
,
219 CSSM_ALGORITHMS macAlg
,
220 CSSM_ALGORITHMS keyAlg
,
222 const CSSM_DATA
*key
, // raw key bytes
223 CSSM_BOOL genRaw
, // first generate raw key (CSPDL)
224 const CSSM_DATA
*inText
,
225 unsigned *updateSizes
, // NULL --> random updates
226 // else null-terminated list of sizes
227 CSSM_DATA_PTR outText
) // mallocd and returned if doGen
230 CSSM_KEY refKey
; // in case of genRaw
231 CSSM_BOOL refKeyGenerated
= CSSM_FALSE
;
235 crtn
= cspGenSymKeyWithBits(cspHand
,
237 CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
,
245 refKeyGenerated
= CSSM_TRUE
;
248 /* cook up a raw symmetric key */
249 symKey
= cspGenSymKey(cspHand
,
253 CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
,
255 CSSM_FALSE
); // ref key
257 return CSSM_ERRCODE_INTERNAL_ERROR
;
259 if(symKey
->KeyData
.Length
!= key
->Length
) {
260 printf("***Generated key size error (exp %lu, got %lu)\n",
261 key
->Length
, symKey
->KeyData
.Length
);
262 return CSSM_ERRCODE_INTERNAL_ERROR
;
264 memmove(symKey
->KeyData
.Data
, key
->Data
, key
->Length
);
268 outText
->Data
= NULL
;
275 crtn
= cspGenMacWithSizes(cspHand
,
283 crtn
= cspStagedGenMac(cspHand
,
287 CSSM_TRUE
, // multiUpdates
288 CSSM_FALSE
, // mallocMac
294 crtn
= cspVfyMacWithSizes(cspHand
,
302 crtn
= cspMacVerify(cspHand
,
310 cspFreeKey(cspHand
, symKey
);
311 if(!refKeyGenerated
) {
312 /* key itself mallocd by cspGenSymKey */
319 #define MAX_FIXED_UPDATES 5
321 static int doTest(CSSM_CSP_HANDLE cspHand
,
322 const CSSM_DATA
*ptext
,
323 const CSSM_DATA
*keyData
,
324 CSSM_BOOL genRaw
, // first generate raw key (CSPDL)
327 CSSM_BOOL fixedUpdates
, // for testing CSSM_ALGID_SHA1HMAC_LEGACY
330 CSSM_DATA macRef
= {0, NULL
}; // MAC, BSAFE reference
331 CSSM_DATA macTest
= {0, NULL
}; // MAC, CSP test
334 unsigned updateSizes
[MAX_FIXED_UPDATES
+1];
335 unsigned *updateSizesPtr
;
338 /* calculate up to MAX_FIXED_UPDATES update sizes which add up to
341 unsigned bytesToGo
= ptext
->Length
;
343 memset(updateSizes
, 0, sizeof(unsigned) * (MAX_FIXED_UPDATES
+1));
344 for(i
=0; i
<MAX_FIXED_UPDATES
; i
++) {
345 updateSizes
[i
] = genRand(1, bytesToGo
);
346 bytesToGo
-= updateSizes
[i
];
351 updateSizesPtr
= updateSizes
;
355 * CSP : random updates
356 * BSAFE, openssl: single one-shot update
358 updateSizesPtr
= NULL
;
361 * generate with each method;
362 * verify MACs compare;
363 * verify with test code;
365 if(macAlg
== CSSM_ALGID_MD5HMAC
) {
366 doHmacMD5Ref(keyData
, ptext
, &macRef
);
370 crtn
= genMacBSAFE(macAlg
,
377 return testError(quiet
);
379 crtn
= genMacCSSM(cspHand
,
389 return testError(quiet
);
392 /* ensure both methods resulted in same MAC */
393 if(macRef
.Length
!= macTest
.Length
) {
394 printf("MAC length mismatch (1)\n");
395 rtn
= testError(quiet
);
400 if(memcmp(macRef
.Data
, macTest
.Data
, macTest
.Length
)) {
401 printf("MAC miscompare\n");
402 rtn
= testError(quiet
);
408 /* verify with the test method */
409 crtn
= genMacCSSM(cspHand
,
419 printf("***Unexpected MAC verify failure\n");
420 rtn
= testError(quiet
);
427 CSSM_FREE(macTest
.Data
);
430 CSSM_FREE(macRef
.Data
);
436 int main(int argc
, char **argv
)
442 CSSM_CSP_HANDLE cspHand
;
444 uint32 macAlg
; // CSSM_ALGID_xxx
445 uint32 keyAlg
; // CSSM_ALGID_xxx
447 unsigned currAlg
; // ALG_xxx
450 CSSM_BOOL genRaw
= CSSM_FALSE
; // first generate raw key (CSPDL)
455 unsigned minAlg
= ALG_FIRST
;
456 unsigned maxAlg
= ALG_LAST
;
457 unsigned loops
= LOOPS_DEF
;
458 CSSM_BOOL verbose
= CSSM_FALSE
;
459 unsigned minExp
= MIN_EXP
;
460 unsigned maxExp
= DEFAULT_MAX_EXP
;
461 CSSM_BOOL quiet
= CSSM_FALSE
;
462 unsigned pauseInterval
= 0;
463 CSSM_BOOL bareCsp
= CSSM_TRUE
;
464 CSSM_BOOL fixedUpdates
;
465 CSSM_BOOL allZeroes
= CSSM_FALSE
;
466 unsigned keySizeSpecd
= 0;
467 unsigned ptextLenSpecd
= 0;
469 for(arg
=1; arg
<argc
; arg
++) {
473 loops
= atoi(&argp
[2]);
476 minExp
= atoi(&argp
[2]);
479 maxExp
= atoi(&argp
[2]);
480 if(maxExp
> MAX_EXP
) {
488 bareCsp
= CSSM_FALSE
;
489 #if CSPDL_ALL_KEYS_ARE_REF
497 pauseInterval
= atoi(&argp
[2]);
500 allZeroes
= CSSM_TRUE
;
503 keySizeSpecd
= atoi(&argp
[2]);
506 ptextLenSpecd
= atoi(&argp
[2]);
513 if(minExp
> maxExp
) {
514 printf("***minExp must be <= maxExp\n");
517 ptext
.Data
= (uint8
*)CSSM_MALLOC(MAX_DATA_SIZE
);
518 if(ptext
.Data
== NULL
) {
519 printf("Insufficient heap space\n");
522 /* ptext length set in test loop */
524 keyData
.Data
= (uint8
*)CSSM_MALLOC(MAX_KEY_SIZE
);
525 if(keyData
.Data
== NULL
) {
526 printf("Insufficient heap space\n");
529 /* key length set in test loop */
531 printf("Starting macCompat; args: ");
532 for(i
=1; i
<argc
; i
++) {
533 printf("%s ", argv
[i
]);
536 cspHand
= cspDlDbStartup(bareCsp
, NULL
);
542 printf("Top of test; hit CR to proceed: ");
545 for(currAlg
=minAlg
; currAlg
<=maxAlg
; currAlg
++) {
546 if((currAlg
== ALG_SHA1_LEGACY
) && !bareCsp
&& !CSPDL_SHA1HMAC_LEGACY_ENABLE
) {
550 /* some default values... */
553 macAlg
= CSSM_ALGID_MD5HMAC
;
554 keyAlg
= CSSM_ALGID_MD5HMAC
;
556 fixedUpdates
= CSSM_FALSE
;
559 macAlg
= CSSM_ALGID_SHA1HMAC
;
560 keyAlg
= CSSM_ALGID_SHA1HMAC
;
562 fixedUpdates
= CSSM_FALSE
;
564 case ALG_SHA1_LEGACY
:
565 macAlg
= CSSM_ALGID_SHA1HMAC_LEGACY
;
566 keyAlg
= CSSM_ALGID_SHA1HMAC
;
567 algStr
= "SHA1_LEGACY";
568 fixedUpdates
= CSSM_TRUE
;
571 printf("***Brrzap. Bad alg.\n");
575 if(!quiet
|| verbose
) {
576 printf("Testing alg %s\n", algStr
);
578 for(loop
=1; ; loop
++) {
579 /* random ptext and key */
580 ptext
.Length
= genData(ptext
.Data
, minExp
, maxExp
, DT_Random
);
582 ptext
.Length
= ptextLenSpecd
;
585 memset(ptext
.Data
, 0, ptext
.Length
);
587 if(macAlg
== CSSM_ALGID_SHA1HMAC_LEGACY
) {
588 simpleGenData(&keyData
, 20, 20);
591 simpleGenData(&keyData
, MIN_KEY_SIZE
, MAX_KEY_SIZE
);
593 keyData
.Length
= keySizeSpecd
;
597 memset(keyData
.Data
, 0, keyData
.Length
);
600 if(verbose
|| ((loop
% LOOP_NOTIFY
) == 0)) {
601 printf("..loop %d text size %lu keySize %lu\n",
602 loop
, ptext
.Length
, keyData
.Length
);
617 if(pauseInterval
&& ((loop
% pauseInterval
) == 0)) {
620 printf("Hit CR to proceed, q to abort: ");
626 if(loops
&& (loop
== loops
)) {
637 cspShutdown(cspHand
, bareCsp
);
640 printf("ModuleDetach/Unload complete; hit CR to exit: ");
643 if((rtn
== 0) && !quiet
) {
644 printf("%s test complete\n", argv
[0]);
646 CSSM_FREE(ptext
.Data
);
647 CSSM_FREE(keyData
.Data
);