]> git.saurik.com Git - apple/security.git/blob - SecurityTests/cspxutils/dhTest/dhTest.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / dhTest / dhTest.cpp
1 /*
2 * dhTest - simple Diffie-Hellman exerciser.
3 */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <Security/cssm.h>
7 #include "cspwrap.h"
8 #include "common.h"
9 #include <security_cdsa_utils/cuFileIo.h>
10 #include <strings.h>
11
12 #define USAGE_DEF "noUsage"
13 #define LOOPS_DEF 10
14 #define KEY_SIZE_DEF 512
15 #define DERIVE_KEY_SIZE 128
16 #define DERIVE_KEY_ALG CSSM_ALGID_AES
17
18 static void usage(char **argv)
19 {
20 printf("usage: %s [options]\n", argv[0]);
21 printf("Options:\n");
22 printf(" k=keySize (default = %d)\n", KEY_SIZE_DEF);
23 printf(" l=loops (0=forever)\n");
24 printf(" p=pauseInterval (default=0, no pause)\n");
25 printf(" D (CSP/DL; default = bare CSP)\n");
26 printf(" o=fileName (dump key and param blobs to filename)\n");
27 printf(" i=filename (obtain param blobs from filename)\n");
28 printf(" 8 (private key in PKCS8 format, default is PKCS3)\n");
29 printf(" x (public key in X509 format, default is PKCS3)\n");
30 printf(" f (public key is ref form; default is raw)\n");
31 printf(" q(uiet)\n");
32 printf(" v(erbose))\n");
33 exit(1);
34 }
35
36 /*
37 * Generate a Diffie-Hellman key pair. Optionally allows specification of
38 * algorithm parameters, and optionally returns algorithm parameters if
39 * we generate them.
40 */
41 static int dhKeyGen(
42 CSSM_CSP_HANDLE cspHand,
43 CSSM_KEY_PTR pubKey,
44 CSSM_KEY_PTR privKey,
45 const CSSM_DATA *inParams, // optional
46 CSSM_DATA_PTR outParams, // optional, we malloc
47 uint32 keySizeInBits,
48 CSSM_KEYBLOB_FORMAT privForm,
49 CSSM_KEYBLOB_FORMAT pubForm,
50 CSSM_BOOL pubIsRef,
51 CSSM_BOOL quiet)
52 {
53 CSSM_RETURN crtn;
54 CSSM_CC_HANDLE ccHand;
55 CSSM_DATA labelData = { strlen(USAGE_DEF), (uint8 *)USAGE_DEF };
56
57 if(inParams && outParams) {
58 printf("***dhKeyGen: inParams and outParams are mutually "
59 "exclusive.\n");
60 return -1;
61 }
62 memset(pubKey, 0, sizeof(CSSM_KEY));
63 memset(privKey, 0, sizeof(CSSM_KEY));
64
65 crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
66 CSSM_ALGID_DH,
67 keySizeInBits,
68 NULL, // Seed
69 NULL, // Salt
70 NULL, // StartDate
71 NULL, // EndDate
72 inParams, // Params, may be NULL
73 &ccHand);
74 if(crtn) {
75 printError("CSSM_CSP_CreateKeyGenContext", crtn);
76 return testError(quiet);
77 }
78
79 if((inParams == NULL) && (outParams != NULL)) {
80 /* explicitly generate params and return them to caller */
81 outParams->Data = NULL;
82 outParams->Length = 0;
83 crtn = CSSM_GenerateAlgorithmParams(ccHand,
84 keySizeInBits, outParams);
85 if(crtn) {
86 printError("CSSM_GenerateAlgorithmParams", crtn);
87 return testError(quiet);
88 }
89 }
90
91 uint32 privAttr = CSSM_KEYATTR_RETURN_REF;
92 uint32 pubAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
93 if(privForm != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
94 crtn = AddContextAttribute(ccHand,
95 CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
96 sizeof(uint32),
97 CAT_Uint32,
98 NULL,
99 privForm);
100 if(crtn) {
101 printError("AddContextAttribute(CSSM_ATTRIBUTE_PRIVATE_KEY"
102 "_FORMAT)", crtn);
103 return crtn;
104 }
105 privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
106 }
107 if(pubIsRef) {
108 pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
109 }
110 else if(pubForm != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
111 crtn = AddContextAttribute(ccHand,
112 CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
113 sizeof(uint32),
114 CAT_Uint32,
115 NULL,
116 pubForm);
117 if(crtn) {
118 printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY"
119 "_FORMAT)", crtn);
120 return crtn;
121 }
122 }
123 crtn = CSSM_GenerateKeyPair(ccHand,
124 CSSM_KEYUSE_DERIVE, // only legal use of a Diffie-Hellman key
125 pubAttr,
126 &labelData,
127 pubKey,
128 /* private key specification */
129 CSSM_KEYUSE_DERIVE,
130 privAttr,
131 &labelData, // same labels
132 NULL, // CredAndAclEntry
133 privKey);
134 if(crtn) {
135 printError("CSSM_GenerateKeyPair", crtn);
136 return testError(quiet);
137 }
138
139 CSSM_DeleteContext(ccHand);
140 return crtn;
141 }
142
143 /*
144 * Perform Diffie-Hellman key exchange.
145 * Given "our" private key (in the form of a CSSM_KEY) and "their" public
146 * key (in the form of a raw blob of bytes), cook up a symmetric key.
147 */
148 static int dhKeyExchange(
149 CSSM_CSP_HANDLE cspHand,
150 CSSM_KEY_PTR myPrivKey,
151 CSSM_KEY_PTR theirPubKey,
152 CSSM_KEY_PTR derivedKey, // RETURNED
153 uint32 deriveKeySizeInBits,
154 CSSM_ALGORITHMS derivedKeyAlg,
155 uint32 derivedKeyUsage,
156 uint32 derivedKeyAttr,
157 CSSM_BOOL quiet)
158 {
159 CSSM_RETURN crtn;
160 CSSM_ACCESS_CREDENTIALS creds;
161 CSSM_CC_HANDLE ccHand;
162 CSSM_DATA labelData = { strlen(USAGE_DEF), (uint8 *)USAGE_DEF };
163
164 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
165 memset(derivedKey, 0, sizeof(CSSM_KEY));
166
167 crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
168 CSSM_ALGID_DH,
169 derivedKeyAlg,
170 deriveKeySizeInBits,
171 &creds,
172 myPrivKey, // BaseKey
173 0, // IterationCount
174 0, // Salt
175 0, // Seed
176 &ccHand);
177 if(crtn) {
178 printError("CSSM_CSP_CreateDeriveKeyContext", crtn);
179 return testError(quiet);
180 }
181
182 /*
183 * Public key passed in as CSSM_DATA *Param - only if
184 * the pub key is in raw PKCS3 form
185 */
186 CSSM_DATA nullParam = {0, NULL};
187 CSSM_DATA_PTR paramPtr;
188 CSSM_KEYHEADER &hdr = theirPubKey->KeyHeader;
189 if((hdr.BlobType == CSSM_KEYBLOB_RAW) &&
190 (hdr.Format == CSSM_KEYBLOB_RAW_FORMAT_PKCS3)) {
191 /* simple case */
192 paramPtr = &theirPubKey->KeyData;
193 }
194 else {
195 /* add this pub key as a context attr */
196 crtn = AddContextAttribute(ccHand,
197 CSSM_ATTRIBUTE_PUBLIC_KEY,
198 sizeof(CSSM_KEY),
199 CAT_Ptr,
200 (void *)theirPubKey,
201 0);
202 if(crtn) {
203 printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY)",
204 crtn);
205 return crtn;
206 }
207 paramPtr = &nullParam;
208 }
209 crtn = CSSM_DeriveKey(ccHand,
210 paramPtr,
211 derivedKeyUsage,
212 derivedKeyAttr,
213 &labelData,
214 NULL, // cread/acl
215 derivedKey);
216 if(crtn) {
217 printError("CSSM_DeriveKey", crtn);
218 }
219 CSSM_DeleteContext(ccHand);
220 return crtn;
221 }
222
223 int doTest(
224 CSSM_CSP_HANDLE cspHand,
225 const CSSM_DATA *inParams, // optional
226 CSSM_DATA_PTR outParams, // optional
227 uint32 keySizeInBits,
228 CSSM_KEYBLOB_FORMAT privForm,
229 CSSM_KEYBLOB_FORMAT pubForm,
230 CSSM_BOOL pubIsRef,
231 CSSM_BOOL quiet)
232 {
233 CSSM_KEY myPriv;
234 CSSM_KEY myPub;
235 CSSM_KEY theirPriv;
236 CSSM_KEY theirPub;
237 int rtn = 0;
238
239 /* generate two key pairs */
240 if(dhKeyGen(cspHand,
241 &myPub,
242 &myPriv,
243 inParams,
244 outParams,
245 keySizeInBits,
246 privForm,
247 pubForm,
248 pubIsRef,
249 quiet)) {
250 return 1;
251 }
252
253 /* note this MUST match the params either specified or generated in previous
254 * call */
255 if((inParams == NULL) && (outParams == NULL)) {
256 printf("***BRRZAP! Must provide a way to match D-H parameters!\n");
257 exit(1);
258 }
259 const CSSM_DATA *theParams = inParams;
260 if(theParams == NULL) {
261 theParams = outParams;
262 }
263 if(dhKeyGen(cspHand,
264 &theirPub,
265 &theirPriv,
266 theParams,
267 NULL, // outParams
268 keySizeInBits,
269 privForm,
270 pubForm,
271 pubIsRef,
272 quiet)) {
273 return 1;
274 }
275
276 /* derive two keys, ensure they match */
277 CSSM_KEY myDerive;
278 CSSM_KEY theirDerive;
279 if(dhKeyExchange(cspHand,
280 &myPriv,
281 &theirPub,
282 &myDerive,
283 DERIVE_KEY_SIZE,
284 DERIVE_KEY_ALG,
285 CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
286 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
287 quiet)) {
288 return testError(quiet);
289 }
290 if(dhKeyExchange(cspHand,
291 &theirPriv,
292 &myPub,
293 &theirDerive,
294 DERIVE_KEY_SIZE,
295 DERIVE_KEY_ALG,
296 CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
297 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
298 quiet)) {
299 return testError(quiet);
300 }
301
302 if(!appCompareCssmData(&myDerive.KeyData, &theirDerive.KeyData)) {
303 printf("***Key Exchange data miscompare***\n");
304 rtn = testError(quiet);
305 }
306 cspFreeKey(cspHand, &myPub);
307 cspFreeKey(cspHand, &myPriv);
308 cspFreeKey(cspHand, &theirPub);
309 cspFreeKey(cspHand, &theirPriv);
310 cspFreeKey(cspHand, &myDerive);
311 cspFreeKey(cspHand, &theirDerive);
312 return rtn;
313 }
314
315 int main(int argc, char **argv)
316 {
317 int arg;
318 char *argp;
319 CSSM_CSP_HANDLE cspHand;
320 unsigned loop;
321 int i;
322 CSSM_DATA inParams = {0, NULL};
323 CSSM_DATA outParams = {0, NULL};
324 CSSM_DATA_PTR inParamPtr = NULL;
325 CSSM_DATA_PTR outParamPtr = NULL;
326
327 /* user-spec'd parameters */
328 unsigned keySize = KEY_SIZE_DEF;
329 unsigned pauseInterval = 0;
330 unsigned loops = LOOPS_DEF;
331 CSSM_BOOL quiet = CSSM_FALSE;
332 CSSM_BOOL verbose = CSSM_FALSE;
333 CSSM_BOOL bareCsp = CSSM_TRUE;
334 char *inFileName = NULL;
335 char *outFileName = NULL;
336 /* default: "use default blob form", i.e., PKCS3 */
337 CSSM_KEYBLOB_FORMAT privForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
338 CSSM_KEYBLOB_FORMAT pubForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
339 CSSM_BOOL pubIsRef = CSSM_FALSE;
340
341 for(arg=1; arg<argc; arg++) {
342 argp = argv[arg];
343 switch(argp[0]) {
344 case 'k':
345 keySize = atoi(&argp[2]);
346 break;
347 case 'l':
348 loops = atoi(&argp[2]);
349 break;
350 case 'p':
351 pauseInterval = atoi(&argp[2]);
352 break;
353 case 'i':
354 inFileName = &argp[2];
355 break;
356 case 'o':
357 outFileName = &argp[2];
358 break;
359 case 'D':
360 bareCsp = CSSM_FALSE;
361 break;
362 case '8':
363 privForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
364 break;
365 case 'x':
366 pubForm = CSSM_KEYBLOB_RAW_FORMAT_X509;
367 break;
368 case 'f':
369 pubIsRef = CSSM_TRUE;
370 break;
371 case 'q':
372 quiet = CSSM_TRUE;
373 break;
374 case 'v':
375 verbose = CSSM_TRUE;
376 break;
377 default:
378 usage(argv);
379 }
380 }
381
382 /* Actually this test does NOT run with CSPDL */
383 if(!bareCsp) {
384 printf("***%s does not run with CSPDL; aborting.\n", argv[0]);
385 exit(1);
386 }
387
388 cspHand = cspDlDbStartup(bareCsp, NULL);
389 if(cspHand == 0) {
390 exit(1);
391 }
392
393 /* optionally fetch algorithm parameters from a file */
394 if(inFileName) {
395 unsigned len;
396 int r = readFile(inFileName, &inParams.Data, &len);
397 if(r) {
398 printf("***Can't read parameters from %s; aborting.\n",
399 inFileName);
400 exit(1);
401 }
402 inParams.Length = len;
403 /* constant from now on */
404 inParamPtr = &inParams;
405 }
406 else {
407 /* first time thru, no user-supplied parameters; generate them and
408 * save in outParams */
409 outParamPtr = &outParams;
410 }
411 printf("Starting dhTest; args: ");
412 for(i=1; i<argc; i++) {
413 printf("%s ", argv[i]);
414 }
415 printf("\n");
416 for(loop=1; ; loop++) {
417 if(!quiet) {
418 printf("...Loop %d\n", loop);
419 }
420 i = doTest(cspHand, inParamPtr, outParamPtr, keySize, privForm,
421 pubForm, pubIsRef, quiet);
422 if(i) {
423 break;
424 }
425 if(loop == 1) {
426 /* first time thru */
427 if(outFileName) {
428 /* save parameters for another run */
429 i = writeFile(outFileName, outParams.Data,
430 outParams.Length);
431 if(i) {
432 printf("***Error writing params to %s; continuing.\n",
433 outFileName);
434 }
435 else {
436 if(!quiet) {
437 printf("...wrote %lu bytes to %s\n",
438 outParams.Length, outFileName);
439 }
440 }
441 }
442 if(!inFileName) {
443 /* from now on, use the parameters we just generated */
444 inParamPtr = &outParams;
445 }
446 /* and in any case don't fetch any more params */
447 outParamPtr = NULL;
448 }
449 if(loops && (loop == loops)) {
450 break;
451 }
452 if(pauseInterval && ((loop % pauseInterval) == 0)) {
453 char inch;
454
455 fpurge(stdin);
456 printf("Hit CR to proceed, q to quit: ");
457 inch = getchar();
458 if(inch == 'q') {
459 break;
460 }
461 }
462 }
463 CSSM_ModuleDetach(cspHand);
464 if(!quiet) {
465 printf("OK\n");
466 }
467 return 0;
468 }