]> git.saurik.com Git - apple/security.git/blame - SecurityTests/cspxutils/macCompat/macCompat.c
Security-57740.31.2.tar.gz
[apple/security.git] / SecurityTests / cspxutils / macCompat / macCompat.c
CommitLineData
d8f41ccd
A
1/*
2 * macCompat.c - test compatibilty of two different implementations of a
3 * given MAC algorithm - one in the standard AppleCSP,
4 * one in BSAFE.
5 *
6 * Written by Doug Mitchell.
7 */
8
9#include <stdlib.h>
10#include <stdio.h>
11#include <time.h>
12#include <Security/cssm.h>
13#include <Security/cssmapple.h>
14#include "cspwrap.h"
15#include "common.h"
16#include "bsafeUtils.h"
17#include <string.h>
18#include "cspdlTesting.h"
19#include <openssl/hmac.h>
20
21/*
22 * Defaults.
23 */
24#define LOOPS_DEF 200
25#define MIN_EXP 2 /* for data size 10**exp */
26#define DEFAULT_MAX_EXP 4
27#define MAX_EXP 5
28
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
33
34/*
35 * Enumerate algs our own way to allow iteration.
36 */
37#define ALG_MD5 1
38#define ALG_SHA1 2
39#define ALG_SHA1_LEGACY 3
40#define ALG_FIRST ALG_MD5
41#define ALG_LAST ALG_SHA1_LEGACY
42
43static void usage(char **argv)
44{
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");
56 printf(" q(uiet)\n");
57 printf(" h(elp)\n");
58 exit(1);
59}
60
61/*
62 * generate MAC using reference BSAFE with either one update
63 * (updateSizes == NULL) or specified set of update sizes.
64 */
65static 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
72{
73 CSSM_RETURN crtn;
74 BU_KEY buKey;
75
76 crtn = buGenSymKey(key->Length * 8, key, &buKey);
77 if(crtn) {
78 return crtn;
79 }
80 crtn = buGenMac(buKey,
81 macAlg,
82 inText,
83 updateSizes,
84 outText);
85 buFreeKey(buKey);
86 return crtn;
87}
88
89/*
90 * Produce HMACMD5 with openssl.
91 */
92static int doHmacMD5Ref(
93 const CSSM_DATA *key, // raw key bytes
94 const CSSM_DATA *inText,
95 CSSM_DATA_PTR outText) // mallocd and returned
96{
97 const EVP_MD *md = EVP_md5();
98 unsigned md_len = 16;
99 appSetupCssmData(outText, 16);
100 HMAC(md, key->Data, (int)key->Length,
101 inText->Data, inText->Length,
102 (unsigned char *)outText->Data, &md_len);
103 return 0;
104}
105
106/*
107 * Generate MAC, CSP, specified set of update sizes
108 */
109static CSSM_RETURN cspGenMacWithSizes(CSSM_CSP_HANDLE cspHand,
110 uint32 algorithm,
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
115{
116 CSSM_CC_HANDLE macHand;
117 CSSM_RETURN crtn;
118 CSSM_DATA currData = *text;
119
120 crtn = CSSM_CSP_CreateMacContext(cspHand,
121 algorithm,
122 key,
123 &macHand);
124 if(crtn) {
125 printError("CSSM_CSP_CreateMacContext", crtn);
126 return crtn;
127 }
128 crtn = CSSM_GenerateMacInit(macHand);
129 if(crtn) {
130 printError("CSSM_GenerateMacInit", crtn);
131 goto abort;
132 }
133 /* CSP mallocs */
134 mac->Data = NULL;
135 mac->Length = 0;
136
137 while(*updateSizes) {
138 currData.Length = *updateSizes;
139 crtn = CSSM_GenerateMacUpdate(macHand,
140 &currData,
141 1);
142 if(crtn) {
143 printError("CSSM_GenerateMacUpdate", crtn);
144 goto abort;
145 }
146 currData.Data += *updateSizes;
147 updateSizes++;
148 }
149 crtn = CSSM_GenerateMacFinal(macHand, mac);
150 if(crtn) {
151 printError("CSSM_GenerateMacFinal", crtn);
152 }
153abort:
154 crtn = CSSM_DeleteContext(macHand);
155 if(crtn) {
156 printError("CSSM_DeleteContext", crtn);
157 }
158 return crtn;
159}
160
161/*
162 * Verify MAC, CSP, specified set of update sizes
163 */
164static CSSM_RETURN cspVfyMacWithSizes(CSSM_CSP_HANDLE cspHand,
165 uint32 algorithm,
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)
170{
171 CSSM_CC_HANDLE macHand;
172 CSSM_RETURN crtn;
173 CSSM_DATA currData = *text;
174
175 crtn = CSSM_CSP_CreateMacContext(cspHand,
176 algorithm,
177 key,
178 &macHand);
179 if(crtn) {
180 printError("CSSM_CSP_CreateMacContext", crtn);
181 return crtn;
182 }
183 crtn = CSSM_VerifyMacInit(macHand);
184 if(crtn) {
185 printError("CSSM_VerifyMacInit", crtn);
186 goto abort;
187 }
188
189 while(*updateSizes) {
190 currData.Length = *updateSizes;
191 crtn = CSSM_VerifyMacUpdate(macHand,
192 &currData,
193 1);
194 if(crtn) {
195 printError("CSSM_GenerateMacUpdate", crtn);
196 goto abort;
197 }
198 currData.Data += *updateSizes;
199 updateSizes++;
200 }
201 crtn = CSSM_VerifyMacFinal(macHand, mac);
202 if(crtn) {
203 printError("CSSM_GenerateMacFinal", crtn);
204 }
205abort:
206 crtn = CSSM_DeleteContext(macHand);
207 if(crtn) {
208 printError("CSSM_DeleteContext", crtn);
209 }
210 return crtn;
211}
212
213/*
214 * Generate or verify MAC using CSP with either random-sized staged updates
215 * (updateSizes == NULL) or specified set of update sizes.
216 */
217static CSSM_RETURN genMacCSSM(
218 CSSM_CSP_HANDLE cspHand,
219 CSSM_ALGORITHMS macAlg,
220 CSSM_ALGORITHMS keyAlg,
221 CSSM_BOOL doGen,
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
228{
229 CSSM_KEY_PTR symKey;
230 CSSM_KEY refKey; // in case of genRaw
231 CSSM_BOOL refKeyGenerated = CSSM_FALSE;
232 CSSM_RETURN crtn;
233
234 if(genRaw) {
235 crtn = cspGenSymKeyWithBits(cspHand,
236 keyAlg,
237 CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY,
238 key,
239 key->Length,
240 &refKey);
241 if(crtn) {
242 return crtn;
243 }
244 symKey = &refKey;
245 refKeyGenerated = CSSM_TRUE;
246 }
247 else {
248 /* cook up a raw symmetric key */
249 symKey = cspGenSymKey(cspHand,
250 keyAlg,
251 "noLabel",
252 8,
253 CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY,
254 key->Length * 8,
255 CSSM_FALSE); // ref key
256 if(symKey == NULL) {
257 return CSSM_ERRCODE_INTERNAL_ERROR;
258 }
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;
263 }
264 memmove(symKey->KeyData.Data, key->Data, key->Length);
265 }
266 if(doGen) {
267 /* CSP mallocs */
268 outText->Data = NULL;
269 outText->Length = 0;
270 }
271
272 /* go for it */
273 if(doGen) {
274 if(updateSizes) {
275 crtn = cspGenMacWithSizes(cspHand,
276 macAlg,
277 symKey,
278 inText,
279 updateSizes,
280 outText);
281 }
282 else {
283 crtn = cspStagedGenMac(cspHand,
284 macAlg,
285 symKey,
286 inText,
287 CSSM_TRUE, // multiUpdates
288 CSSM_FALSE, // mallocMac
289 outText);
290 }
291 }
292 else {
293 if(updateSizes) {
294 crtn = cspVfyMacWithSizes(cspHand,
295 macAlg,
296 symKey,
297 inText,
298 updateSizes,
299 outText);
300 }
301 else {
302 crtn = cspMacVerify(cspHand,
303 macAlg,
304 symKey,
305 inText,
306 outText,
307 CSSM_OK);
308 }
309 }
310 cspFreeKey(cspHand, symKey);
311 if(!refKeyGenerated) {
312 /* key itself mallocd by cspGenSymKey */
313 CSSM_FREE(symKey);
314 }
315 return crtn;
316}
317
318#define LOG_FREQ 20
319#define MAX_FIXED_UPDATES 5
320
321static 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)
325 uint32 macAlg,
326 uint32 keyAlg,
327 CSSM_BOOL fixedUpdates, // for testing CSSM_ALGID_SHA1HMAC_LEGACY
328 CSSM_BOOL quiet)
329{
330 CSSM_DATA macRef = {0, NULL}; // MAC, BSAFE reference
331 CSSM_DATA macTest = {0, NULL}; // MAC, CSP test
332 int rtn = 0;
333 CSSM_RETURN crtn;
334 unsigned updateSizes[MAX_FIXED_UPDATES+1];
335 unsigned *updateSizesPtr;
336
337 if(fixedUpdates) {
338 /* calculate up to MAX_FIXED_UPDATES update sizes which add up to
339 * ptext->Length */
340 int i;
341 unsigned bytesToGo = ptext->Length;
342
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];
347 if(bytesToGo == 0) {
348 break;
349 }
350 }
351 updateSizesPtr = updateSizes;
352 }
353 else {
354 /*
355 * CSP : random updates
356 * BSAFE, openssl: single one-shot update
357 */
358 updateSizesPtr = NULL;
359 }
360 /*
361 * generate with each method;
362 * verify MACs compare;
363 * verify with test code;
364 */
365 if(macAlg == CSSM_ALGID_MD5HMAC) {
366 doHmacMD5Ref(keyData, ptext, &macRef);
367 crtn = CSSM_OK;
368 }
369 else {
370 crtn = genMacBSAFE(macAlg,
371 keyData,
372 ptext,
373 updateSizesPtr,
374 &macRef);
375 }
376 if(crtn) {
377 return testError(quiet);
378 }
379 crtn = genMacCSSM(cspHand,
380 macAlg,
381 keyAlg,
382 CSSM_TRUE,
383 keyData,
384 genRaw,
385 ptext,
386 updateSizesPtr,
387 &macTest);
388 if(crtn) {
389 return testError(quiet);
390 }
391
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);
396 if(rtn) {
397 goto abort;
398 }
399 }
400 if(memcmp(macRef.Data, macTest.Data, macTest.Length)) {
401 printf("MAC miscompare\n");
402 rtn = testError(quiet);
403 if(rtn) {
404 goto abort;
405 }
406 }
407
408 /* verify with the test method */
409 crtn = genMacCSSM(cspHand,
410 macAlg,
411 keyAlg,
412 CSSM_FALSE,
413 keyData,
414 genRaw,
415 ptext,
416 updateSizesPtr,
417 &macTest);
418 if(crtn) {
419 printf("***Unexpected MAC verify failure\n");
420 rtn = testError(quiet);
421 }
422 else {
423 rtn = 0;
424 }
425abort:
426 if(macTest.Length) {
427 CSSM_FREE(macTest.Data);
428 }
429 if(macRef.Length) {
430 CSSM_FREE(macRef.Data);
431 }
432 return rtn;
433}
434
435
436int main(int argc, char **argv)
437{
438 int arg;
439 char *argp;
440 unsigned loop;
441 CSSM_DATA ptext;
442 CSSM_CSP_HANDLE cspHand;
443 const char *algStr;
444 uint32 macAlg; // CSSM_ALGID_xxx
445 uint32 keyAlg; // CSSM_ALGID_xxx
446 int i;
447 unsigned currAlg; // ALG_xxx
448 int rtn = 0;
449 CSSM_DATA keyData;
450 CSSM_BOOL genRaw = CSSM_FALSE; // first generate raw key (CSPDL)
451
452 /*
453 * User-spec'd params
454 */
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;
468
469 for(arg=1; arg<argc; arg++) {
470 argp = argv[arg];
471 switch(argp[0]) {
472 case 'l':
473 loops = atoi(&argp[2]);
474 break;
475 case 'n':
476 minExp = atoi(&argp[2]);
477 break;
478 case 'x':
479 maxExp = atoi(&argp[2]);
480 if(maxExp > MAX_EXP) {
481 usage(argv);
482 }
483 break;
484 case 'v':
485 verbose = CSSM_TRUE;
486 break;
487 case 'D':
488 bareCsp = CSSM_FALSE;
489 #if CSPDL_ALL_KEYS_ARE_REF
490 genRaw = CSSM_TRUE;
491 #endif
492 break;
493 case 'q':
494 quiet = CSSM_TRUE;
495 break;
496 case 'p':
497 pauseInterval = atoi(&argp[2]);
498 break;
499 case 'z':
500 allZeroes = CSSM_TRUE;
501 break;
502 case 'k':
503 keySizeSpecd = atoi(&argp[2]);
504 break;
505 case 'P':
506 ptextLenSpecd = atoi(&argp[2]);
507 break;
508 case 'h':
509 default:
510 usage(argv);
511 }
512 }
513 if(minExp > maxExp) {
514 printf("***minExp must be <= maxExp\n");
515 usage(argv);
516 }
517 ptext.Data = (uint8 *)CSSM_MALLOC(MAX_DATA_SIZE);
518 if(ptext.Data == NULL) {
519 printf("Insufficient heap space\n");
520 exit(1);
521 }
522 /* ptext length set in test loop */
523
524 keyData.Data = (uint8 *)CSSM_MALLOC(MAX_KEY_SIZE);
525 if(keyData.Data == NULL) {
526 printf("Insufficient heap space\n");
527 exit(1);
528 }
529 /* key length set in test loop */
530
531 printf("Starting macCompat; args: ");
532 for(i=1; i<argc; i++) {
533 printf("%s ", argv[i]);
534 }
535 printf("\n");
536 cspHand = cspDlDbStartup(bareCsp, NULL);
537 if(cspHand == 0) {
538 exit(1);
539 }
540 if(pauseInterval) {
541 fpurge(stdin);
542 printf("Top of test; hit CR to proceed: ");
543 getchar();
544 }
545 for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) {
546 if((currAlg == ALG_SHA1_LEGACY) && !bareCsp && !CSPDL_SHA1HMAC_LEGACY_ENABLE) {
547 continue;
548 }
549
550 /* some default values... */
551 switch(currAlg) {
552 case ALG_MD5:
553 macAlg = CSSM_ALGID_MD5HMAC;
554 keyAlg = CSSM_ALGID_MD5HMAC;
555 algStr = "MD5";
556 fixedUpdates = CSSM_FALSE;
557 break;
558 case ALG_SHA1:
559 macAlg = CSSM_ALGID_SHA1HMAC;
560 keyAlg = CSSM_ALGID_SHA1HMAC;
561 algStr = "SHA1";
562 fixedUpdates = CSSM_FALSE;
563 break;
564 case ALG_SHA1_LEGACY:
565 macAlg = CSSM_ALGID_SHA1HMAC_LEGACY;
566 keyAlg = CSSM_ALGID_SHA1HMAC;
567 algStr = "SHA1_LEGACY";
568 fixedUpdates = CSSM_TRUE;
569 break;
570 default:
571 printf("***Brrzap. Bad alg.\n");
572 exit(1);
573 }
574
575 if(!quiet || verbose) {
576 printf("Testing alg %s\n", algStr);
577 }
578 for(loop=1; ; loop++) {
579 /* random ptext and key */
580 ptext.Length = genData(ptext.Data, minExp, maxExp, DT_Random);
581 if(ptextLenSpecd) {
582 ptext.Length = ptextLenSpecd;
583 }
584 if(allZeroes) {
585 memset(ptext.Data, 0, ptext.Length);
586 }
587 if(macAlg == CSSM_ALGID_SHA1HMAC_LEGACY) {
588 simpleGenData(&keyData, 20, 20);
589 }
590 else {
591 simpleGenData(&keyData, MIN_KEY_SIZE, MAX_KEY_SIZE);
592 if(keySizeSpecd) {
593 keyData.Length = keySizeSpecd;
594 }
595 }
596 if(allZeroes) {
597 memset(keyData.Data, 0, keyData.Length);
598 }
599 if(!quiet) {
600 if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
601 printf("..loop %d text size %lu keySize %lu\n",
602 loop, ptext.Length, keyData.Length);
603 }
604 }
605
606 if(doTest(cspHand,
607 &ptext,
608 &keyData,
609 genRaw,
610 macAlg,
611 keyAlg,
612 fixedUpdates,
613 quiet)) {
614 rtn = 1;
615 break;
616 }
617 if(pauseInterval && ((loop % pauseInterval) == 0)) {
618 char c;
619 fpurge(stdin);
620 printf("Hit CR to proceed, q to abort: ");
621 c = getchar();
622 if(c == 'q') {
623 goto testDone;
624 }
625 }
626 if(loops && (loop == loops)) {
627 break;
628 }
629 } /* main loop */
630 if(rtn) {
631 break;
632 }
633
634 } /* for algs */
635
636testDone:
637 cspShutdown(cspHand, bareCsp);
638 if(pauseInterval) {
639 fpurge(stdin);
640 printf("ModuleDetach/Unload complete; hit CR to exit: ");
641 getchar();
642 }
643 if((rtn == 0) && !quiet) {
644 printf("%s test complete\n", argv[0]);
645 }
646 CSSM_FREE(ptext.Data);
647 CSSM_FREE(keyData.Data);
648 return rtn;
649}
650
651