1/* Copyright (c) 2005-2006 Apple Computer, Inc. 2 * 3 * ssl2Padding.cpp - test CSSM_PADDING_APPLE_SSLv2. 4 */ 5 6 7 /* 8 * This table illustrates the combinations of: 9 * 10 * -- SSLv2 (v2) and SSLv3/TLSv1 (v3+) enables (0/1) on the client and server side 11 * -- the resulting negotiated protocols (including those forced by a man-in-the-middle 12 * attacker, denoted by (m)) 13 * -- the padding generated by the client (client pad) 14 * -- the padding style checked by the server (server pad) 15 * -- and the end results 16 * 17 * client server 18 * ------ ------ 19 * v2 v3+ v2 v3+ negotiate client pad server pad result 20 * -- -- -- -- --------- ---------- ---------- ------ 21 * 0 0 x x impossible 22 * x x 0 0 impossible 23 * 0 1 0 1 v3+ PKCS1 PKCS1 normal 24 * 0 1 0 1 v2 (m) Attack fails, client rejects server hello 25 * 0 1 1 0 fail incompatible 26 * 0 1 1 1 v3+ PKCS1 PKCS1 normal 27 * 0 1 1 1 v2 (m) Attack fails, client rejects server hello 28 * 1 0 0 1 fail incompatible 29 * 1 0 1 0 v2 PKCS1 PKCS1 normal, both sides are dumb SSL2 30 * 1 0 1 0 v3+ Attack fails, server rejects client hello 31 * 1 0 1 1 v2 PKCS1 SSLv2 normal, dumb client 32 * 1 0 1 1 v3+ (m) Attack fails, client rejects server hello 33 * 1 1 0 1 v3+ PKCS1 PKCS1 normal 34 * 1 1 0 1 v2 (m) Attack fails, server rejects SSL2 handshake 35 * 1 1 1 0 v2 SSLv2 PKCS1 normal, dumb server 36 * 1 1 1 0 v3+ (m) Attack fails, server rejects SSL3 handshakes 37 * 1 1 1 1 v3+ PKCS1 PKCS1 normal 38 * 1 1 1 1 v2 (m) SSLv2 SSLv2 Attack fails due to SSLv2 pad detect 39 * 40 * The client generates SSLv2 padding if it's capable of v3+ but is currently operating 41 * in v2 per negotiation. 42 * 43 * The server checks for SSLv2 padding if it's capable of v3+ but is currently operating 44 * in v2 per negotiation. If SSLv2 padding is seen, fail. 45 */ 46 47#include <stdlib.h> 48#include <stdio.h> 49#include <string.h> 50#include <time.h> 51#include <Security/cssm.h> 52#include "cspwrap.h" 53#include "common.h" 54#include "cspdlTesting.h" 55 56#define USAGE_NAME "noUsage" 57#define USAGE_NAME_LEN (strlen(USAGE_NAME)) 58#define LOOPS_DEF 10 59 60#define KEY_SIZE_DEF 1024 61#define KEY_SIZE_SMALL 512 62 63#define PTEXT_LEN 32 /* bytes */ 64 65static void usage(char **argv) 66{ 67 printf("usage: %s [options]\n", argv[0]); 68 printf(" Options:\n"); 69 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF); 70 printf(" k=keySizeInBits; default=%d\n", KEY_SIZE_DEF); 71 printf(" D (CSP/DL; default = bare CSP)\n"); 72 printf(" p (pause on each loop)\n"); 73 printf(" u (quick; small keys)\n"); 74 printf(" v(erbose)\n"); 75 printf(" q(uiet)\n"); 76 printf(" h(elp)\n"); 77 exit(1); 78} 79 80/* special-purpose generate-context, encrypt, and decrypt routines just for this test */ 81static int genRsaCryptContext( 82 CSSM_CSP_HANDLE cspHand, 83 CSSM_KEY_PTR key, 84 CSSM_PADDING padding, 85 CSSM_BOOL quiet, 86 CSSM_CC_HANDLE &ccHand) // RETURNED 87{ 88 CSSM_RETURN crtn; 89 CSSM_ACCESS_CREDENTIALS creds; 90 91 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 92 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, 93 CSSM_ALGID_RSA, 94 &creds, // access 95 key, 96 padding, 97 &ccHand); 98 if(crtn) { 99 cssmPerror("CSSM_CSP_CreateAsymmetricContext", crtn); 100 return testError(quiet); 101 } 102 return 0; 103} 104 105static int doRsaEncrypt( 106 CSSM_CSP_HANDLE cspHand, 107 CSSM_KEY_PTR key, 108 CSSM_PADDING padding, 109 CSSM_BOOL quiet, 110 CSSM_DATA *ptext, 111 CSSM_DATA *ctext) 112{ 113 CSSM_CC_HANDLE ccHand; 114 int rtn; 115 CSSM_RETURN crtn; 116 CSSM_SIZE bytesMoved; 117 CSSM_DATA remData = {0, NULL}; 118 119 rtn = genRsaCryptContext(cspHand, key, padding, quiet, ccHand); 120 if(rtn) { 121 return rtn; 122 } 123 crtn = CSSM_EncryptData(ccHand, 124 ptext, 125 1, 126 ctext, 127 1, 128 &bytesMoved, 129 &remData); 130 CSSM_DeleteContext(ccHand); 131 if(crtn == CSSM_OK) { 132 /* 133 * Deal with remData - its contents are included in bytesMoved. 134 */ 135 if(remData.Length != 0) { 136 /* malloc and copy a new one */ 137 uint8 *newCdata = (uint8 *)appMalloc(bytesMoved, NULL); 138 memmove(newCdata, ctext->Data, ctext->Length); 139 memmove(newCdata+ctext->Length, remData.Data, remData.Length); 140 CSSM_FREE(ctext->Data); 141 ctext->Data = newCdata; 142 } 143 ctext->Length = bytesMoved; 144 return 0; 145 } 146 else { 147 cssmPerror("CSSM_EncryptData", crtn); 148 return testError(quiet); 149 } 150} 151 152static int doRsaDecrypt( 153 CSSM_CSP_HANDLE cspHand, 154 CSSM_KEY_PTR key, 155 CSSM_PADDING padding, 156 CSSM_BOOL quiet, 157 CSSM_RETURN expectRtn, 158 CSSM_DATA *ctext, 159 CSSM_DATA *rptext) 160{ 161 CSSM_CC_HANDLE ccHand; 162 int rtn; 163 CSSM_RETURN crtn; 164 CSSM_SIZE bytesMoved; 165 CSSM_DATA remData = {0, NULL}; 166 167 rtn = genRsaCryptContext(cspHand, key, padding, quiet, ccHand); 168 if(rtn) { 169 return rtn; 170 } 171 crtn = CSSM_DecryptData(ccHand, 172 ctext, 173 1, 174 rptext, 175 1, 176 &bytesMoved, 177 &remData); 178 CSSM_DeleteContext(ccHand); 179 if(crtn != expectRtn) { 180 printf(" CSSM_DecryptData: expect %s\n", cssmErrToStr(expectRtn)); 181 printf(" CSSM_DecryptData: got %s\n", cssmErrToStr(crtn)); 182 return testError(quiet); 183 } 184 if(crtn) { 185 /* no need to process further */ 186 return 0; 187 } 188 if(crtn == CSSM_OK) { 189 /* 190 * Deal with remData - its contents are included in bytesMoved. 191 */ 192 if(remData.Length != 0) { 193 /* malloc and copy a new one */ 194 uint8 *newRpdata = (uint8 *)appMalloc(bytesMoved, NULL); 195 memmove(newRpdata, rptext->Data, rptext->Length); 196 memmove(newRpdata+rptext->Length, remData.Data, remData.Length); 197 CSSM_FREE(rptext->Data); 198 rptext->Data = newRpdata; 199 } 200 rptext->Length = bytesMoved; 201 return 0; 202 } 203 else { 204 cssmPerror("CSSM_DecryptData", crtn); 205 return testError(quiet); 206 } 207} 208 209/* 210 * encrypt with specified pad 211 * decrypt with specified pad, verify expected result (which may be failure) 212 */ 213static int doTest( 214 CSSM_CSP_HANDLE cspHand, 215 CSSM_KEY_PTR pubKey, 216 CSSM_KEY_PTR privKey, 217 CSSM_PADDING encrPad, 218 CSSM_PADDING decrPad, 219 CSSM_BOOL quiet, 220 CSSM_RETURN expectResult) 221{ 222 int rtn; 223 uint8 ptext[PTEXT_LEN]; 224 CSSM_DATA ptextData = {PTEXT_LEN, ptext}; 225 CSSM_DATA ctext = {0, NULL}; 226 CSSM_DATA rptext = {0, NULL}; 227 228 simpleGenData(&ptextData, PTEXT_LEN, PTEXT_LEN); 229 rtn = doRsaEncrypt(cspHand, pubKey, encrPad, quiet, &ptextData, &ctext); 230 if(rtn) { 231 goto errOut; 232 } 233 rtn = doRsaDecrypt(cspHand, privKey, decrPad, quiet, expectResult, &ctext, &rptext); 234 if(rtn) { 235 goto errOut; 236 } 237 if(expectResult == CSSM_OK) { 238 if(memcmp(rptext.Data, ptextData.Data, PTEXT_LEN)) { 239 printf("***Data miscomapare after decrypt\n"); 240 rtn = testError(quiet); 241 } 242 } 243errOut: 244 if(ctext.Data) { 245 CSSM_FREE(ctext.Data); 246 } 247 if(rptext.Data) { 248 CSSM_FREE(rptext.Data); 249 } 250 return rtn; 251} 252 253int main(int argc, char **argv) 254{ 255 int arg; 256 char *argp; 257 unsigned loop; 258 CSSM_CSP_HANDLE cspHand; 259 int rtn = 0; 260 261 /* 262 * User-spec'd params 263 */ 264 unsigned loops = LOOPS_DEF; 265 CSSM_BOOL verbose = CSSM_FALSE; 266 CSSM_BOOL quiet = CSSM_FALSE; 267 uint32 keySizeInBits = KEY_SIZE_DEF; 268 CSSM_BOOL bareCsp = CSSM_TRUE; 269 CSSM_BOOL doPause = CSSM_FALSE; 270 271 for(arg=1; arg<argc; arg++) { 272 argp = argv[arg]; 273 switch(argp[0]) { 274 case 'l': 275 loops = atoi(&argp[2]); 276 break; 277 case 'k': 278 keySizeInBits = atoi(&argv[arg][2]); 279 break; 280 case 'D': 281 bareCsp = CSSM_FALSE; 282 break; 283 case 'u': 284 keySizeInBits = KEY_SIZE_SMALL; 285 break; 286 case 'v': 287 verbose = CSSM_TRUE; 288 break; 289 case 'p': 290 doPause = CSSM_TRUE; 291 break; 292 case 'q': 293 quiet = CSSM_TRUE; 294 break; 295 case 'h': 296 default: 297 usage(argv); 298 } 299 } 300 301 testStartBanner("ssl2Padding", argc, argv); 302 303 cspHand = cspDlDbStartup(bareCsp, NULL); 304 if(cspHand == 0) { 305 exit(1); 306 } 307 CSSM_KEY pubKey; 308 CSSM_KEY privKey; 309 310 CSSM_RETURN crtn = cspGenKeyPair(cspHand, CSSM_ALGID_RSA, 311 USAGE_NAME, USAGE_NAME_LEN, 312 keySizeInBits, 313 &pubKey, CSSM_TRUE /* ref */, CSSM_KEYUSE_ANY, CSSM_KEYBLOB_RAW_FORMAT_NONE, 314 &privKey, CSSM_TRUE /* ref */, CSSM_KEYUSE_ANY, CSSM_KEYBLOB_RAW_FORMAT_NONE, 315 CSSM_FALSE); 316 if(crtn) { 317 printf("***Error generating key pair. Aborting.\n"); 318 exit(1); 319 } 320 for(loop=1; ; loop++) { 321 if(doPause) { 322 fpurge(stdin); 323 printf("Top of loop; hit CR to proceed: "); 324 getchar(); 325 } 326 327 /* encrypt by client, decrypt by server. */ 328 329 /* 330 * SSLv3+ negotiated, normal case, or 331 * both sides support SSLv2 only 332 */ 333 if(!quiet) { 334 printf("...loop %u\n", loop); 335 printf(" encrPad PKCS1 decrPad PKCS1\n"); 336 } 337 rtn = doTest(cspHand, &pubKey, &privKey, 338 CSSM_PADDING_PKCS1, CSSM_PADDING_PKCS1, 339 quiet, CSSM_OK); 340 if(rtn) { 341 break; 342 } 343 344 /* 345 * Server supports SSLv2 and SSLv3+, client supports SSLv2 only 346 */ 347 if(!quiet) { 348 printf(" encrPad PKCS1 decrPad SSLv2\n"); 349 } 350 rtn = doTest(cspHand, &pubKey, &privKey, 351 CSSM_PADDING_PKCS1, CSSM_PADDING_APPLE_SSLv2, 352 quiet, CSSM_OK); 353 if(rtn) { 354 break; 355 } 356 357 /* 358 * Server supports SSLv2 only, client supports SSLv2 and SSLv3+ 359 */ 360 if(!quiet) { 361 printf(" encrPad SSLv2 decrPad PKCS1\n"); 362 } 363 rtn = doTest(cspHand, &pubKey, &privKey, 364 CSSM_PADDING_APPLE_SSLv2, CSSM_PADDING_PKCS1, 365 quiet, CSSM_OK); 366 if(rtn) { 367 break; 368 } 369 370 /* 371 * Both sides support SSLv3+ but a man in the middle has forced the 372 * negotiated protocol down to SSLv2 373 */ 374 if(!quiet) { 375 printf(" encrPad SSLv2 decrPad SSLv2, expect failure\n"); 376 } 377 rtn = doTest(cspHand, &pubKey, &privKey, 378 CSSM_PADDING_APPLE_SSLv2, CSSM_PADDING_APPLE_SSLv2, 379 quiet, CSSMERR_CSP_APPLE_SSLv2_ROLLBACK); 380 if(rtn) { 381 break; 382 } 383 384 if(loops && (loop == loops)) { 385 break; 386 } 387 } /* for loop */ 388 389 CSSM_ModuleDetach(cspHand); 390 if((rtn == 0) && !quiet) { 391 printf("%s test complete\n", argv[0]); 392 } 393 return rtn; 394} 395