1/*
2 * Tool to cook up key pair, sign & verify, any which way
3 * with tons of options.
4 */
5#include <string.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include <time.h>
9#include <Security/cssm.h>
10#include <Security/cssmapple.h>
11#include "cspwrap.h"
12#include "common.h"
13#include <security_cdsa_utils/cuFileIo.h>
14
15#define DATA_SIZE_DEF	100
16#define USAGE_DEF		"noUsage"
17#define LOOPS_DEF		10
18#define FEE_PASSWD_LEN	32		/* private data length in bytes, FEE only */
19
20static void usage(char **argv)
21{
22	printf("usage: %s [options]\n", argv[0]);
23	printf("Options:\n");
24	printf("  a=algorithm\n");
25	printf("     f=FEE/MD5 F=FEE/SHA1 e=ECDSA r=RSA/MD5 2=RSA/MD2 \n");
26	printf("     s=RSA/SHA1 d=DSA R=rawRSA (No digest) \n");
27	printf("     4=RSA/SHA224 6=RSA/SHA256 3=RSA/SHA384 5=RSA/SHA512;\n");
28	printf("     E=ECDSA/ANSI; 7=ECDSA/SHA256; 8=ECDSA/SHA384; 9=ECDSA/512; default=RSA/SHA1\n");
29	printf("  d=dataSize (default = %d)\n", DATA_SIZE_DEF);
30	printf("  k=keySize\n");
31	printf("  b (pub is blob)\n");
32	printf("  r (priv is blob)\n");
33	printf("  B=[1xboOt] (pub  key in PKCS1/X509/BSAFE/OpenSSH1/OpenSSH2/Octet form)\n");
34	printf("          RSA = {PKCS1,X509,OpenSSH1,OpenSSH2}     default = PKCS1\n");
35	printf("          DSA = {BSAFE,X509,OpenSSH2}              default = X509\n");
36	printf("        ECDSA = {X509, Only!}                      default = X509\n");
37	printf("  P=primeType (m=Mersenne, f=FEE, g=general; FEE only)\n");
38	printf("  C=curveType (m=Montgomery, w=Weierstrass, a=ANSI; FEE only)\n");
39	printf("  l=loops (0=forever)\n");
40	printf("  s(ign only)\n");
41	printf("  V(erify only)\n");
42	printf("  c(ontexts only)\n");
43	printf("  S (we generate seed, for FEE only)\n");
44	printf("  n(o padding; default is PKCS1)\n");
45	printf("  p=pauseInterval (default=0, no pause)\n");
46	printf("  D (CSP/DL; default = bare CSP)\n");
47	printf("  L (dump key and signature blobs)\n");
48	printf("  o (key blobs in OCTET_STRING format)\n");
49	printf("  q(uiet)\n");
50	printf("  v(erbose))\n");
51	exit(1);
52}
53
54/* parse public key format character */
55static CSSM_KEYBLOB_FORMAT parsePubKeyFormat(char c, char **argv)
56{
57	switch(c) {
58		case '1':
59			return CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
60		case 'x':
61			return CSSM_KEYBLOB_RAW_FORMAT_X509;
62		case 'b':
63			return CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
64		case 'o':
65			return CSSM_KEYBLOB_RAW_FORMAT_OPENSSH;
66		case 'O':
67			return CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2;
68		default:
69			usage(argv);
70	}
71	/* not reached */
72	return -1;
73}
74
75int main(int argc, char **argv)
76{
77	int		 				arg;
78	char					*argp;
79	CSSM_CSP_HANDLE 		cspHand;
80	CSSM_CC_HANDLE			pubSigHand;
81	CSSM_CC_HANDLE			privSigHand;
82	CSSM_RETURN				crtn;
83	CSSM_DATA				randData = {0, NULL};
84	CSSM_KEY				privKey;
85	CSSM_KEY				pubKey;
86	CSSM_DATA				sigData = {0, NULL};
87	unsigned				loop;
88	int 					i;
89	unsigned 				dataSize = DATA_SIZE_DEF;
90	unsigned				keySize = CSP_KEY_SIZE_DEFAULT;
91	uint32					sigAlg = CSSM_ALGID_SHA1WithRSA;
92	uint32					keyGenAlg = CSSM_ALGID_RSA;
93	unsigned				pauseInterval = 0;
94	unsigned				loops = LOOPS_DEF;
95	CSSM_BOOL				quiet = CSSM_FALSE;
96	CSSM_BOOL				pubIsRef = CSSM_TRUE;
97	CSSM_BOOL				privIsRef = CSSM_TRUE;
98	CSSM_BOOL				doSign = CSSM_TRUE;
99	CSSM_BOOL				doVerify = CSSM_TRUE;
100	CSSM_BOOL				contextsOnly = CSSM_FALSE;
101	CSSM_BOOL				noPadding = CSSM_FALSE;
102	CSSM_BOOL				verbose = CSSM_FALSE;
103	CSSM_BOOL				bareCsp = CSSM_TRUE;
104	CSSM_BOOL				genSeed = CSSM_FALSE;
105	CSSM_BOOL				dumpBlobs = CSSM_FALSE;
106	CSSM_KEYBLOB_FORMAT		privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_NONE;
107	CSSM_KEYBLOB_FORMAT		pubKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_NONE;
108	uint32					primeType = CSSM_FEE_PRIME_TYPE_DEFAULT;	// FEE only
109	uint32					curveType = CSSM_FEE_CURVE_TYPE_DEFAULT;	// FEE only
110
111	for(arg=1; arg<argc; arg++) {
112		argp = argv[arg];
113	    switch(argv[arg][0]) {
114	    	case 'a':
115				if(argp[1] != '=') {
116					usage(argv);
117				}
118				switch(argp[2]) {
119					case 'f':
120						sigAlg    = CSSM_ALGID_FEE_MD5;
121						keyGenAlg = CSSM_ALGID_FEE;
122						break;
123					case 'F':
124						sigAlg    = CSSM_ALGID_FEE_SHA1;
125						keyGenAlg = CSSM_ALGID_FEE;
126						break;
127					case 'e':
128						sigAlg    = CSSM_ALGID_SHA1WithECDSA;
129						keyGenAlg = CSSM_ALGID_FEE;
130						break;
131					case 'E':
132						sigAlg    = CSSM_ALGID_SHA1WithECDSA;
133						keyGenAlg = CSSM_ALGID_ECDSA;
134						break;
135					case '7':
136						sigAlg    = CSSM_ALGID_SHA256WithECDSA;
137						keyGenAlg = CSSM_ALGID_ECDSA;
138						break;
139					case '8':
140						sigAlg    = CSSM_ALGID_SHA384WithECDSA;
141						keyGenAlg = CSSM_ALGID_ECDSA;
142						break;
143					case '9':
144						sigAlg    = CSSM_ALGID_SHA512WithECDSA;
145						keyGenAlg = CSSM_ALGID_ECDSA;
146						break;
147					case 'r':
148						sigAlg    = CSSM_ALGID_MD5WithRSA;
149						keyGenAlg = CSSM_ALGID_RSA;
150						break;
151					case '2':
152						sigAlg    = CSSM_ALGID_MD2WithRSA;
153						keyGenAlg = CSSM_ALGID_RSA;
154						break;
155					case 's':
156						sigAlg    = CSSM_ALGID_SHA1WithRSA;
157						keyGenAlg = CSSM_ALGID_RSA;
158						break;
159					case 'd':
160						sigAlg    = CSSM_ALGID_SHA1WithDSA;
161						keyGenAlg = CSSM_ALGID_DSA;
162						break;
163					case 'R':
164						sigAlg    = CSSM_ALGID_RSA;
165						keyGenAlg = CSSM_ALGID_RSA;
166						break;
167					case '4':
168						sigAlg    = CSSM_ALGID_SHA224WithRSA;
169						keyGenAlg = CSSM_ALGID_RSA;
170						break;
171					case '6':
172						sigAlg    = CSSM_ALGID_SHA256WithRSA;
173						keyGenAlg = CSSM_ALGID_RSA;
174						break;
175					case '3':
176						sigAlg    = CSSM_ALGID_SHA384WithRSA;
177						keyGenAlg = CSSM_ALGID_RSA;
178						break;
179					case '5':
180						sigAlg    = CSSM_ALGID_SHA512WithRSA;
181						keyGenAlg = CSSM_ALGID_RSA;
182						break;
183					default:
184						usage(argv);
185				}
186				break;
187			case 'd':
188				dataSize = atoi(&argv[arg][2]);
189				break;
190			case 'k':
191				keySize = atoi(&argv[arg][2]);
192				break;
193		    case 'l':
194				loops = atoi(&argv[arg][2]);
195				break;
196		    case 'p':
197				pauseInterval = atoi(&argv[arg][2]);
198				break;
199			case 'b':
200				pubIsRef = CSSM_FALSE;
201				break;
202			case 'r':
203				privIsRef = CSSM_FALSE;
204				break;
205			case 'B':
206				if(argp[1] != '=') {
207					usage(argv);
208				}
209				pubKeyFormat = parsePubKeyFormat(argp[2], argv);
210				break;
211			case 's':
212				doVerify = CSSM_FALSE;
213				break;
214			case 'V':
215				doSign = CSSM_FALSE;
216				break;
217			case 'S':
218				genSeed = CSSM_TRUE;
219				break;
220			case 'n':
221				noPadding = CSSM_TRUE;
222				break;
223			case 'L':
224				dumpBlobs = CSSM_TRUE;
225				break;
226			case 'c':
227				contextsOnly = CSSM_TRUE;
228				break;
229			case 'D':
230				bareCsp = CSSM_FALSE;
231				break;
232			case 'q':
233				quiet = CSSM_TRUE;
234				break;
235		    case 'v':
236		    	verbose = CSSM_TRUE;
237				break;
238		    case 'o':
239				/* this is for FEE only */
240		    	pubKeyFormat = privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
241				break;
242			case 'C':
243				switch(argp[2]) {
244					case 'm':
245						curveType = CSSM_FEE_CURVE_TYPE_MONTGOMERY;
246						break;
247					case 'w':
248						curveType = CSSM_FEE_CURVE_TYPE_WEIERSTRASS;
249						break;
250					case 'a':
251						curveType = CSSM_FEE_CURVE_TYPE_ANSI_X9_62;
252						break;
253					default:
254						usage(argv);
255				}
256				break;
257			case 'P':
258				switch(argp[2]) {
259					case 'm':
260						primeType = CSSM_FEE_PRIME_TYPE_MERSENNE;
261						break;
262					case 'f':
263						primeType = CSSM_FEE_PRIME_TYPE_FEE;
264						break;
265					case 'g':
266						primeType = CSSM_FEE_PRIME_TYPE_GENERAL;
267						break;
268					default:
269						usage(argv);
270				}
271				break;
272			default:
273				usage(argv);
274		}
275	}
276	if(!doSign && !doVerify) {
277		printf("s and v mutually exclusive\n");
278		exit(1);
279	}
280	cspHand = cspDlDbStartup(bareCsp, NULL);
281	if(cspHand == 0) {
282		exit(1);
283	}
284	printf("Starting sigtest; args: ");
285	for(i=1; i<argc; i++) {
286		printf("%s ", argv[i]);
287	}
288	if(keyGenAlg == CSSM_ALGID_FEE) {
289		uint8 			passwd[FEE_PASSWD_LEN];
290		CSSM_DATA		pwdData = {FEE_PASSWD_LEN, passwd};
291		CSSM_DATA_PTR	pwdDataPtr;
292
293		if(genSeed) {
294			simpleGenData(&pwdData, FEE_PASSWD_LEN, FEE_PASSWD_LEN);
295			pwdDataPtr = &pwdData;
296		}
297		else {
298			pwdDataPtr = NULL;
299		}
300		crtn = cspGenFEEKeyPair(cspHand,
301				USAGE_DEF,
302				strlen(USAGE_DEF),
303				keySize,
304				primeType,
305				curveType,
306				&pubKey,
307				pubIsRef,
308				CSSM_KEYUSE_VERIFY,
309				pubKeyFormat,
310				&privKey,
311				privIsRef,
312				CSSM_KEYUSE_SIGN,
313				CSSM_KEYBLOB_RAW_FORMAT_NONE,
314				pwdDataPtr);
315
316	}
317	else if((keyGenAlg == CSSM_ALGID_DSA) && !bareCsp) {
318		/* CSPDL doesn't do gen alg params */
319		crtn = cspGenDSAKeyPair(cspHand,
320				USAGE_DEF,
321				strlen(USAGE_DEF),
322				keySize,
323				&pubKey,
324				pubIsRef,
325				CSSM_KEYUSE_VERIFY,
326				pubKeyFormat,
327				&privKey,
328				privIsRef,
329				CSSM_KEYUSE_SIGN,
330				CSSM_KEYBLOB_RAW_FORMAT_NONE,
331				CSSM_FALSE,
332				NULL);
333	}
334	else {
335		crtn = cspGenKeyPair(cspHand,
336			keyGenAlg,
337			USAGE_DEF,
338			strlen(USAGE_DEF),
339			keySize,
340			&pubKey,
341			pubIsRef,
342			CSSM_KEYUSE_VERIFY,
343			pubKeyFormat,
344			&privKey,
345			privIsRef,
346			CSSM_KEYUSE_SIGN,
347			privKeyFormat,
348			genSeed);
349	}
350	if(crtn) {
351		CSSM_ModuleDetach(cspHand);
352		exit(1);
353	}
354	if(dumpBlobs) {
355		if(!pubIsRef) {
356			writeFile("pubKey.blob", pubKey.KeyData.Data, pubKey.KeyData.Length);
357			printf("...wrote %lu bytes to pubKey.blob\n", pubKey.KeyData.Length);
358		}
359		if(!privIsRef) {
360			writeFile("privKey.blob", privKey.KeyData.Data, privKey.KeyData.Length);
361			printf("...wrote %lu bytes to privKey.blob\n", privKey.KeyData.Length);
362		}
363	}
364	randData.Data = (uint8 *)CSSM_MALLOC(dataSize);
365	randData.Length = dataSize;
366	simpleGenData(&randData, dataSize, dataSize);
367	printf("\n");
368	for(loop=1; ; loop++) {
369		if(!quiet) {
370			printf("...Loop %d\n", loop);
371		}
372		if((loop == 1) || doSign) {
373			crtn = CSSM_CSP_CreateSignatureContext(cspHand,
374				sigAlg,
375				NULL,				// passPhrase
376				&privKey,
377				&privSigHand);
378			if(crtn) {
379				printError("CSSM_CSP_CreateSignatureContext (1)", crtn);
380				break;
381			}
382			if(noPadding) {
383				crtn = AddContextAttribute(privSigHand,
384					CSSM_ATTRIBUTE_PADDING,
385					sizeof(uint32),
386					CAT_Uint32,
387					NULL,
388					CSSM_PADDING_NONE);
389				if(crtn) {
390					break;
391				}
392			}
393			if(!contextsOnly) {
394				crtn = CSSM_SignData(privSigHand,
395					&randData,
396					1,
397					CSSM_ALGID_NONE,
398					&sigData);
399				if(crtn) {
400					printError("CSSM_SignData error", crtn);
401					break;
402				}
403			}
404			crtn = CSSM_DeleteContext(privSigHand);
405			if(crtn) {
406				printError("CSSM_DeleteContext", crtn);
407				break;
408			}
409			if(dumpBlobs) {
410				writeFile("sig.blob", sigData.Data, sigData.Length);
411				printf("...wrote %lu bytes to sig.blob\n", sigData.Length);
412			}
413		}
414		if(doVerify) {
415			crtn = CSSM_CSP_CreateSignatureContext(cspHand,
416				sigAlg,
417				NULL,				// passPhrase
418				&pubKey,
419				&pubSigHand);
420			if(crtn) {
421				printError("CSSM_CSP_CreateSignatureContext (2)", crtn);
422				break;
423			}
424			if(noPadding) {
425				crtn = AddContextAttribute(pubSigHand,
426					CSSM_ATTRIBUTE_PADDING,
427					sizeof(uint32),
428					CAT_Uint32,
429					NULL,
430					CSSM_PADDING_NONE);
431				if(crtn) {
432					break;
433				}
434			}
435			if(!contextsOnly) {
436				crtn = CSSM_VerifyData(pubSigHand,
437					&randData,
438					1,
439					CSSM_ALGID_NONE,
440					&sigData);
441				if(crtn) {
442					printError("CSSM_VerifyData", crtn);
443					break;
444				}
445			}
446			crtn = CSSM_DeleteContext(pubSigHand);
447			if(crtn) {
448				printError("CSSM_DeleteContext", crtn);
449				break;
450			}
451		}
452		if(doSign & !contextsOnly) {
453			CSSM_FREE(sigData.Data);
454			sigData.Length = 0;
455			sigData.Data = NULL;
456		}
457		/* else keep it around for next verify */
458
459		if(loops && (loop == loops)) {
460			break;
461		}
462		if(pauseInterval && ((loop % pauseInterval) == 0)) {
463			char inch;
464
465			fpurge(stdin);
466			printf("Hit CR to proceed, q to quit: ");
467			inch = getchar();
468			if(inch == 'q') {
469				break;
470			}
471		}
472	}
473	if(randData.Data != NULL) {
474		CSSM_FREE(randData.Data);
475	}
476	if(CSSM_ModuleDetach(cspHand)) {
477		printError("CSSM_CSP_Detach", crtn);
478		exit(1);
479	}
480	if(crtn == CSSM_OK) {
481		if(!quiet) {
482			printf("OK\n");
483		}
484	}
485	return crtn;
486}
487