1/* Copyright (c) 1997,2003-2005,2008 Apple Inc. 2 * 3 * badmac.c - Verify bad MAC detect. 4 * 5 * Revision History 6 * ---------------- 7 * 4 May 2000 Doug Mitchell 8 * Ported to X/CDSA2. 9 * 21 Dec 1998 Doug Mitchell at Apple 10 * Created. 11 */ 12/* 13 * text size = {random, from 100 bytes to 1 megabyte, in 14 * geometrical steps, i.e. the number of 15 * bytes would be 10^r, where r is random out of 16 * {2,3,4,5,6}, plus a random integer in {0,..99}}; 17 * 18 * for loop_count 19 * text contents = {random data, random size as specified above}; 20 * generate random MAC key; 21 * generate MAC, validate; 22 * for various bytes of ptext { 23 * corrupt text byte; 24 * verify bad MAC; 25 * restore corrupted byte; 26 * } 27 * } 28 */ 29 30#include <stdlib.h> 31#include <stdio.h> 32#include <time.h> 33#include <string.h> 34#include <Security/cssm.h> 35#include "cspwrap.h" 36#include "common.h" 37#include "cspdlTesting.h" 38 39#define USAGE_NAME "noUsage" 40#define USAGE_NAME_LEN (strlen(USAGE_NAME)) 41 42/* 43 * HMAC/SHA1 can not do multiple updates with BSAFE (though the CSP's current 44 * internal implementation can.) 45 * Fixed in Puma; the bug was in BSAFE. 46 */ 47#define HMACSHA_MULTI_UPDATES 1 48 49/* 50 * Defaults. 51 */ 52#define LOOPS_DEF 10 53#define MIN_EXP 2 /* for data size 10**exp */ 54#define DEFAULT_MAX_EXP 2 55#define MAX_EXP 5 56#define INCR_DEFAULT 0 /* munge every incr bytes - zero means 57 * "adjust per ptext size" */ 58 59/* 60 * Enumerate algs our own way to allow iteration. 61 */ 62#define ALG_SHA1HMAC 1 63#define ALG_MD5HMAC 2 64#define ALG_FIRST ALG_SHA1HMAC 65#define ALG_LAST ALG_MD5HMAC 66#define MAX_DATA_SIZE (100000 + 100) /* bytes */ 67 68static void usage(char **argv) 69{ 70 printf("usage: %s [options]\n", argv[0]); 71 printf(" Options:\n"); 72 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF); 73 printf(" n=minExp (default=%d)\n", MIN_EXP); 74 printf(" x=maxExp (default=%d, max=%d)\n", DEFAULT_MAX_EXP, MAX_EXP); 75 printf(" i=increment (default=%d)\n", INCR_DEFAULT); 76 printf(" r(eference keys only)\n"); 77 printf(" m (CSM mallocs MAC)\n"); 78 printf(" p=pauseInterval (default=0, no pause)\n"); 79 printf(" D (CSP/DL; default = bare CSP)\n"); 80 printf(" v(erbose)\n"); 81 printf(" q(uiet)\n"); 82 printf(" h(elp)\n"); 83 exit(1); 84} 85 86#define LOG_FREQ 20 87static int doTest(CSSM_CSP_HANDLE cspHand, 88 uint32 macAlg, // CSSM_ALGID_xxx mac algorithm 89 CSSM_DATA_PTR ptext, 90 CSSM_BOOL verbose, 91 CSSM_BOOL quiet, 92 unsigned keySize, 93 unsigned incr, 94 CSSM_BOOL stagedGen, 95 CSSM_BOOL stagedVerify, 96 CSSM_BOOL mallocMac, 97 CSSM_BOOL refKey) 98{ 99 CSSM_KEY_PTR symmKey; 100 CSSM_DATA mac = {0, NULL}; 101 unsigned length; 102 unsigned byte; 103 unsigned char *data; 104 unsigned char origData; 105 unsigned char bits; 106 int rtn = 0; 107 CSSM_RETURN crtn; 108 uint32 keyGenAlg; 109 unsigned loop = 0; 110 111 switch(macAlg) { 112 case CSSM_ALGID_SHA1HMAC: 113 keyGenAlg = CSSM_ALGID_SHA1HMAC; 114 break; 115 case CSSM_ALGID_MD5HMAC: 116 keyGenAlg = CSSM_ALGID_MD5HMAC; 117 break; 118 default: 119 printf("bogus algorithm\n"); 120 return 1; 121 } 122 symmKey = cspGenSymKey(cspHand, 123 keyGenAlg, 124 "noLabel", 125 7, 126 CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY, 127 keySize, 128 refKey); 129 if(symmKey == NULL) { 130 rtn = testError(quiet); 131 goto abort; 132 } 133 if(stagedGen) { 134 crtn = cspStagedGenMac(cspHand, 135 macAlg, 136 symmKey, 137 ptext, 138 mallocMac, 139 CSSM_TRUE, // multi 140 &mac); 141 } 142 else { 143 crtn = cspGenMac(cspHand, 144 macAlg, 145 symmKey, 146 ptext, 147 &mac); 148 } 149 if(crtn) { 150 rtn = 1; 151 goto abort; 152 } 153 if(stagedVerify) { 154 crtn = cspStagedMacVerify(cspHand, 155 macAlg, 156 symmKey, 157 ptext, 158 &mac, 159 CSSM_TRUE, // multi 160 CSSM_OK); // expectedResult 161 } 162 else { 163 crtn = cspMacVerify(cspHand, 164 macAlg, 165 symmKey, 166 ptext, 167 &mac, 168 CSSM_OK); 169 } 170 if(crtn) { 171 printf("**Unexpected BAD MAC\n"); 172 return testError(quiet); 173 } 174 data = (unsigned char *)ptext->Data; 175 length = ptext->Length; 176 for(byte=0; byte<length; byte += incr) { 177 if(verbose && ((loop++ % LOG_FREQ) == 0)) { 178 printf(" ..byte %d\n", byte); 179 } 180 origData = data[byte]; 181 /* 182 * Generate random non-zero byte 183 */ 184 do { 185 bits = genRand(1, 0xff) & 0xff; 186 } while(bits == 0); 187 data[byte] ^= bits; 188 if(stagedVerify) { 189 crtn = cspStagedMacVerify(cspHand, 190 macAlg, 191 symmKey, 192 ptext, 193 &mac, 194 CSSM_TRUE, // multi 195 CSSMERR_CSP_VERIFY_FAILED); // expect failure 196 } 197 else { 198 crtn = cspMacVerify(cspHand, 199 macAlg, 200 symmKey, 201 ptext, 202 &mac, 203 CSSMERR_CSP_VERIFY_FAILED); 204 } 205 if(crtn) { 206 return testError(quiet); 207 } 208 data[byte] = origData; 209 } 210abort: 211 /* free key */ 212 if(cspFreeKey(cspHand, symmKey)) { 213 printf("Error freeing symmKey\n"); 214 rtn = 1; 215 } 216 CSSM_FREE(mac.Data); 217 return rtn; 218} 219 220int main(int argc, char **argv) 221{ 222 int arg; 223 char *argp; 224 unsigned loop; 225 CSSM_DATA ptext; 226 CSSM_CSP_HANDLE CSPHandle; 227 CSSM_BOOL stagedSign; 228 CSSM_BOOL stagedVfy; 229 CSSM_BOOL mallocMac; 230 CSSM_BOOL refKey; 231 const char *algStr; 232 unsigned actualIncr; 233 uint32 macAlg; // CSSM_ALGID_xxx 234 unsigned currAlg; // ALG_xxx 235 int i; 236 int rtn = 0; 237 238 /* 239 * User-spec'd params 240 */ 241 unsigned loops = LOOPS_DEF; 242 CSSM_BOOL verbose = CSSM_FALSE; 243 unsigned minExp = MIN_EXP; 244 unsigned maxExp = DEFAULT_MAX_EXP; 245 CSSM_BOOL quiet = CSSM_FALSE; 246 unsigned keySizeInBits = CSP_KEY_SIZE_DEFAULT; 247 unsigned incr = INCR_DEFAULT; 248 unsigned minAlg = ALG_FIRST; 249 uint32 maxAlg = ALG_LAST; 250 unsigned pauseInterval = 0; 251 CSSM_BOOL bareCsp = CSSM_TRUE; 252 CSSM_BOOL refKeysOnly = CSSM_FALSE; 253 CSSM_BOOL cspMallocs = CSSM_FALSE; 254 255 #if macintosh 256 argc = ccommand(&argv); 257 #endif 258 for(arg=1; arg<argc; arg++) { 259 argp = argv[arg]; 260 switch(argp[0]) { 261 /* no Alg or keySizeInBits spec for now */ 262 case 'l': 263 loops = atoi(&argp[2]); 264 break; 265 case 'n': 266 minExp = atoi(&argp[2]); 267 break; 268 case 'x': 269 maxExp = atoi(&argp[2]); 270 if(maxExp > MAX_EXP) { 271 usage(argv); 272 } 273 break; 274 case 'i': 275 incr = atoi(&argp[2]); 276 break; 277 case 'p': 278 pauseInterval = atoi(&argp[2]); 279 break; 280 case 'D': 281 bareCsp = CSSM_FALSE; 282 #if CSPDL_ALL_KEYS_ARE_REF 283 refKeysOnly = CSSM_TRUE; 284 #endif 285 break; 286 case 'r': 287 refKeysOnly = CSSM_TRUE; 288 break; 289 case 'm': 290 cspMallocs = CSSM_TRUE; 291 break; 292 case 'v': 293 verbose = CSSM_TRUE; 294 break; 295 case 'q': 296 quiet = CSSM_TRUE; 297 break; 298 case 'h': 299 default: 300 usage(argv); 301 } 302 } 303 ptext.Data = (uint8 *)CSSM_MALLOC(MAX_DATA_SIZE); 304 /* length set in test loop */ 305 if(ptext.Data == NULL) { 306 printf("Insufficient heap\n"); 307 exit(1); 308 } 309 printf("Starting badmac; args: "); 310 for(i=1; i<argc; i++) { 311 printf("%s ", argv[i]); 312 } 313 printf("\n"); 314 CSPHandle = cspDlDbStartup(bareCsp, NULL); 315 if(CSPHandle == 0) { 316 exit(1); 317 } 318 for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) { 319 switch(currAlg) { 320 case ALG_SHA1HMAC: 321 macAlg = CSSM_ALGID_SHA1HMAC; 322 algStr = "SHA1HMAC"; 323 break; 324 case ALG_MD5HMAC: 325 macAlg = CSSM_ALGID_MD5HMAC; 326 algStr = "MD5HMAC"; 327 break; 328 } 329 if(!quiet) { 330 printf("Testing alg %s\n", algStr); 331 } 332 for(loop=1; ; loop++) { 333 ptext.Length = genData(ptext.Data, minExp, maxExp, DT_Random); 334 if(!quiet) { 335 printf("..loop %d text size %lu\n", loop, ptext.Length); 336 } 337 if(incr == 0) { 338 /* adjust increment as appropriate */ 339 actualIncr = (ptext.Length / 50) + 1; 340 } 341 else { 342 actualIncr = incr; 343 } 344 /* mix up staging & ref key format*/ 345 stagedSign = (loop & 1) ? CSSM_TRUE : CSSM_FALSE; 346 stagedVfy = (loop & 2) ? CSSM_TRUE : CSSM_FALSE; 347 if(refKeysOnly) { 348 refKey = CSSM_TRUE; 349 } 350 else { 351 refKey = (loop & 4) ? CSSM_TRUE : CSSM_FALSE; 352 } 353 if(cspMallocs) { 354 mallocMac = CSSM_FALSE; 355 } 356 else { 357 mallocMac = (loop & 8) ? CSSM_TRUE : CSSM_FALSE; 358 } 359 360 #if !HMACSHA_MULTI_UPDATES 361 if(macAlg == CSSM_ALGID_SHA1HMAC) { 362 stagedSign = stagedVfy = CSSM_FALSE; 363 } 364 #endif /* HMACSHA_MULTI_UPDATES */ 365 366 if(!quiet) { 367 printf(" stagedSign %d stagedVfy %d refKey %d mallocMac %d\n", 368 (int)stagedSign, (int)stagedVfy, (int)refKey, (int)mallocMac); 369 } 370 if(doTest(CSPHandle, 371 macAlg, 372 &ptext, 373 verbose, 374 quiet, 375 keySizeInBits, 376 actualIncr, 377 stagedSign, 378 stagedVfy, 379 mallocMac, 380 refKey)) { 381 rtn = 1; 382 goto testDone; 383 } 384 if(loops && (loop == loops)) { 385 break; 386 } 387 if(pauseInterval && ((loop % pauseInterval) == 0)) { 388 fpurge(stdin); 389 printf("Hit CR to proceed: "); 390 getchar(); 391 } 392 } /* for loop */ 393 } /* for alg */ 394testDone: 395 CSSM_ModuleDetach(CSPHandle); 396 if((rtn == 0) && !quiet) { 397 printf("%s test complete\n", argv[0]); 398 } 399 return rtn; 400} 401