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