]> git.saurik.com Git - apple/security.git/blob - SecurityTests/cspxutils/ecdhTest/ecdhTest.cpp
Security-57031.10.10.tar.gz
[apple/security.git] / SecurityTests / cspxutils / ecdhTest / ecdhTest.cpp
1 /*
2 * Copyright (c) 2008 Apple Inc. All Rights Reserved.
3 *
4 * ecdhTest.cpp - Test Elliptic Curve Diffie-Hellman key exchange.
5 *
6 * Created Jan. 1 2008 by Doug Mitchell.
7 */
8
9 #include <stdlib.h>
10 #include <strings.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <Security/cssm.h>
14 #include "cspwrap.h"
15 #include "common.h"
16
17 #define LOOPS_DEF 32
18 #define KEY_SIZE_DEF 256
19
20 static void usage(char **argv)
21 {
22 printf("usage: %s [options]\n", argv[0]);
23 printf("Options:\n");
24 printf(" k=keySize (default = %d)\n", KEY_SIZE_DEF);
25 printf(" X (X9.63 key derivation)\n");
26 printf(" l=loops (0=forever)\n");
27 printf(" D (CSP/DL; default = bare CSP)\n");
28 printf(" q(uiet)\n");
29 printf(" v(erbose))\n");
30 exit(1);
31 }
32
33 #define LABEL_DEF "noLabel"
34 #define MAX_SHARED_INFO_LEN 400
35 #define MAX_DERIVED_SIZE 1024
36
37 static int doECDH(
38 CSSM_CSP_HANDLE cspHand,
39 CSSM_KEY_PTR privKey,
40 /*
41 * pubKey:
42 * Ref form - use key as pubKey as is
43 * X509 form - use as is
44 * OCTET_STRING form - use key data as Param
45 */
46 CSSM_KEY_PTR pubKey,
47 CSSM_BOOL bareCsp, // false --> derive ref key and NULL-wrap it
48 CSSM_BOOL x963KDF,
49 CSSM_DATA *sharedInfo,
50 uint32 deriveSizeInBits,
51 CSSM_BOOL quiet,
52 CSSM_BOOL verbose,
53
54 /* result RETURNED here */
55 CSSM_KEY_PTR derivedKey)
56
57 {
58 CSSM_DATA paramData = {0, NULL};
59 CSSM_KEY_PTR contextPubKey = NULL;
60 CSSM_KEYHEADER_PTR hdr = &pubKey->KeyHeader;
61
62 if((hdr->BlobType == CSSM_KEYBLOB_RAW) &&
63 (hdr->Format == CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING)) {
64 paramData = pubKey->KeyData;
65 }
66 else {
67 contextPubKey = pubKey;
68 }
69
70 /* create key derivation context */
71 CSSM_RETURN crtn;
72 CSSM_ACCESS_CREDENTIALS creds;
73 CSSM_CC_HANDLE ccHand;
74
75 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
76
77 CSSM_ALGORITHMS deriveAlg;
78 if(x963KDF) {
79 deriveAlg = CSSM_ALGID_ECDH_X963_KDF;
80 }
81 else {
82 deriveAlg = CSSM_ALGID_ECDH;
83 }
84
85 crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
86 deriveAlg,
87 CSSM_ALGID_RC4, // doesn't matter, just give us the bits
88 deriveSizeInBits,
89 &creds,
90 privKey, // BaseKey
91 0, // IterationCount
92 sharedInfo, // Salt
93 0, // Seed
94 &ccHand);
95 if(crtn) {
96 printError("CSSM_CSP_CreateDeriveKeyContext", crtn);
97 return testError(quiet);
98 }
99
100 if(contextPubKey != NULL) {
101 /* add pub key as a context attr */
102 crtn = AddContextAttribute(ccHand,
103 CSSM_ATTRIBUTE_PUBLIC_KEY,
104 sizeof(CSSM_KEY),
105 CAT_Ptr,
106 (void *)contextPubKey,
107 0);
108 if(crtn) {
109 printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY)",
110 crtn);
111 return crtn;
112 }
113 }
114
115 /* D-H derive key */
116 CSSM_DATA labelData = { strlen(LABEL_DEF), (uint8 *)LABEL_DEF };
117 CSSM_KEYATTR_FLAGS keyAttr = bareCsp ?
118 (CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE) :
119 (CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE);
120 memset(derivedKey, 0, sizeof(CSSM_KEY));
121 crtn = CSSM_DeriveKey(ccHand,
122 &paramData,
123 CSSM_KEYUSE_ANY,
124 keyAttr,
125 &labelData,
126 NULL, // cread/acl
127 derivedKey);
128 if(crtn) {
129 printError("CSSM_DeriveKey", crtn);
130 }
131 CSSM_DeleteContext(ccHand);
132 if(crtn) {
133 return testError(quiet);
134 }
135
136 if(!bareCsp) {
137 /* Got a ref key, give caller raw */
138 CSSM_KEY refKey = *derivedKey;
139 crtn = cspRefKeyToRaw(cspHand, &refKey, derivedKey);
140 cspFreeKey(cspHand, &refKey);
141 }
142 return 0;
143 }
144
145 /* define public key style */
146 typedef enum {
147 PKT_Ref, /* ref key */
148 PKT_Wrap, /* generate ref key, wrap to OCTET_STRING */
149 PKT_X509, /* raw key X509 format */
150 PKT_Octet /* generate to OCTET_STRING form */
151 } PubKeyType;
152
153 #define BoolStr(v) (v ? "true " : "false")
154
155 static const char *KeyStypeStr(
156 PubKeyType keyType)
157 {
158 switch(keyType) {
159 case PKT_Ref: return "Ref";
160 case PKT_Wrap: return "Ref->Wrap";
161 case PKT_X509: return "X509";
162 case PKT_Octet: return "X9.62";
163 default: return "BRRZAP";
164 }
165 }
166
167 static int doTest(
168 CSSM_CSP_HANDLE cspHand,
169 CSSM_BOOL ourKeysRef, /* our keys are reference */
170 CSSM_BOOL theirPrivKeyRef, /* their private key is reference */
171 PubKeyType theirPubKeyType,
172 unsigned keySizeBits,
173 CSSM_BOOL bareCsp,
174 CSSM_BOOL x963KDF,
175 CSSM_BOOL useSharedInfo, /* use the optional SharedInfo for x963KDF */
176 CSSM_BOOL verbose,
177 CSSM_BOOL quiet)
178 {
179
180 CSSM_RETURN crtn;
181 CSSM_KEY ourPriv;
182 CSSM_KEY ourPub;
183 bool ourKeysGend = false;
184 bool theirKeysGend = false;
185 bool wrappedTheirPub = false;
186 bool wrappedOurPub = false;
187 bool derivedKey1 = false;
188 bool derivedKey2 = false;
189 CSSM_DATA sharedInfo = {0, NULL};
190 uint32 deriveSizeInBits;
191
192 if(x963KDF) {
193 /* arbitrary derived size */
194 deriveSizeInBits = genRand(1, MAX_DERIVED_SIZE);
195 }
196 else {
197 deriveSizeInBits = keySizeBits;
198 }
199 if(useSharedInfo) {
200 /* length should be totally arbitrary */
201 appSetupCssmData(&sharedInfo, MAX_SHARED_INFO_LEN);
202 simpleGenData(&sharedInfo, 1, MAX_SHARED_INFO_LEN);
203 }
204
205
206 if(!quiet) {
207 if(x963KDF) {
208 printf("...sharedInfoLen %4lu deriveSize %4lu ",
209 (unsigned long)sharedInfo.Length, (unsigned long)deriveSizeInBits);
210 }
211 else {
212 printf("...");
213 }
214 printf("ourRef %s theirPrivRef %s theirPub %s\n",
215 BoolStr(ourKeysRef), BoolStr(theirPrivKeyRef),
216 KeyStypeStr(theirPubKeyType));
217 }
218
219 crtn = cspGenKeyPair(cspHand, CSSM_ALGID_ECDSA,
220 LABEL_DEF, strlen(LABEL_DEF), keySizeBits,
221 &ourPub, ourKeysRef, CSSM_KEYUSE_DERIVE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
222 &ourPriv, ourKeysRef, CSSM_KEYUSE_DERIVE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
223 CSSM_FALSE);
224 if(crtn) {
225 return testError(quiet);
226 }
227 ourKeysGend = true;
228
229 CSSM_KEY theirPriv;
230 CSSM_KEY theirPub; /* the generated one */
231 CSSM_KEY theirWrappedPub; /* optional NULL unwrap */
232 CSSM_KEY_PTR theirPubPtr;
233 CSSM_KEY ourWrappedPub; /* optional NULL unwrap */
234 CSSM_KEY_PTR ourPubPtr;
235 CSSM_KEY derived1;
236 CSSM_KEY derived2;
237 CSSM_BOOL pubIsRef = CSSM_FALSE;
238 CSSM_KEYBLOB_FORMAT blobForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
239 int ourRtn = 0;
240
241 switch(theirPubKeyType) {
242 case PKT_Ref:
243 case PKT_Wrap:
244 pubIsRef = CSSM_TRUE;
245 break;
246 case PKT_X509:
247 pubIsRef = CSSM_FALSE;
248 break;
249 case PKT_Octet:
250 pubIsRef = CSSM_FALSE;
251 blobForm = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
252 break;
253 }
254
255 crtn = cspGenKeyPair(cspHand, CSSM_ALGID_ECDSA,
256 LABEL_DEF, strlen(LABEL_DEF), keySizeBits,
257 &theirPub, pubIsRef, CSSM_KEYUSE_DERIVE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
258 &theirPriv, theirPrivKeyRef, CSSM_KEYUSE_DERIVE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
259 CSSM_FALSE);
260 if(crtn) {
261 ourRtn = testError(quiet);
262 goto errOut;
263 }
264
265 if(theirPubKeyType == PKT_Wrap) {
266 /*
267 * This test mode is here mainly to ring out the key wrap and
268 * OCTET_STRING format functionality in the CrypkitCSP, it's
269 * not really relevant to ECDH...
270 */
271 crtn = cspRefKeyToRawWithFormat(cspHand, &theirPub,
272 CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING, &theirWrappedPub);
273 if(crtn) {
274 ourRtn = testError(quiet);
275 goto errOut;
276 }
277 theirPubPtr = &theirWrappedPub;
278 wrappedTheirPub = true;
279 }
280 else {
281 theirPubPtr = &theirPub;
282 }
283
284 if(!bareCsp) {
285 /*
286 * For CSPDL, convert our pub key to OCTET_STRING format so it
287 * is sent as a Param - can't send a ref key (or any other pub
288 * key) in the context
289 */
290 crtn = cspRefKeyToRawWithFormat(cspHand, &ourPub,
291 CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING, &ourWrappedPub);
292 if(crtn) {
293 ourRtn = testError(quiet);
294 goto errOut;
295 }
296 ourPubPtr = &ourWrappedPub;
297 wrappedOurPub = true;
298 }
299 else {
300 ourPubPtr = &ourPub;
301 }
302
303 /*
304 * Here we go, do the two sides of D-H key agreement, results to
305 * to CSSM_KEYs.
306 */
307 ourRtn = doECDH(cspHand, &ourPriv, theirPubPtr, bareCsp,
308 x963KDF, useSharedInfo ? &sharedInfo : NULL,
309 deriveSizeInBits, quiet, verbose, &derived1);
310 if(ourRtn) {
311 goto errOut;
312 }
313 ourRtn = doECDH(cspHand, &theirPriv, ourPubPtr, bareCsp,
314 x963KDF, useSharedInfo ? &sharedInfo : NULL,
315 deriveSizeInBits, quiet, verbose, &derived2);
316 if(ourRtn) {
317 goto errOut;
318 }
319
320 if(!appCompareCssmData(&derived1.KeyData, &derived2.KeyData)) {
321 printf("***Data Miscompare on ECDH key derivation\n");
322 }
323 errOut:
324 if(ourKeysGend) {
325 cspFreeKey(cspHand, &ourPub);
326 cspFreeKey(cspHand, &ourPriv);
327 }
328 if(theirKeysGend) {
329 cspFreeKey(cspHand, &theirPub);
330 cspFreeKey(cspHand, &theirPriv);
331 }
332 if(wrappedTheirPub) {
333 cspFreeKey(cspHand, &theirWrappedPub);
334 }
335 if(wrappedOurPub) {
336 cspFreeKey(cspHand, &ourWrappedPub);
337 }
338 if(derivedKey1) {
339 cspFreeKey(cspHand, &derived1);
340 }
341 if(derivedKey2) {
342 cspFreeKey(cspHand, &derived2);
343 }
344 if(sharedInfo.Data != NULL) {
345 appFreeCssmData(&sharedInfo, CSSM_FALSE);
346 }
347 return ourRtn;
348 }
349
350 int main(int argc, char **argv)
351 {
352 int arg;
353 char *argp;
354 CSSM_CSP_HANDLE cspHand;
355 unsigned loop;
356 int ourRtn = 0;
357
358 unsigned keySize = KEY_SIZE_DEF;
359 unsigned loops = LOOPS_DEF;
360 CSSM_BOOL quiet = CSSM_FALSE;
361 CSSM_BOOL verbose = CSSM_FALSE;
362 CSSM_BOOL bareCsp = CSSM_TRUE;
363 CSSM_BOOL x963KDF = CSSM_FALSE;
364
365 for(arg=1; arg<argc; arg++) {
366 argp = argv[arg];
367 switch(argp[0]) {
368 case 'k':
369 keySize = atoi(&argp[2]);
370 break;
371 case 'X':
372 x963KDF = true;
373 break;
374 case 'l':
375 loops = atoi(&argp[2]);
376 break;
377 case 'D':
378 bareCsp = CSSM_FALSE;
379 break;
380 case 'q':
381 quiet = CSSM_TRUE;
382 break;
383 case 'v':
384 verbose = CSSM_TRUE;
385 break;
386 default:
387 usage(argv);
388 }
389 }
390 testStartBanner("ecdhTest", argc, argv);
391
392 cspHand = cspDlDbStartup(bareCsp, NULL);
393 if(cspHand == 0) {
394 exit(1);
395 }
396
397 for(loop=1; ; loop++) {
398 if(!quiet) {
399 printf("...Loop %d\n", loop);
400 }
401
402 /* test mode from l.s. bits of loop counter */
403
404 CSSM_BOOL ourKeysRef = (loop & 0x04) ? CSSM_TRUE : CSSM_FALSE;
405 CSSM_BOOL theirPrivKeyRef = (loop & 0x08) ? CSSM_TRUE : CSSM_FALSE;
406 PubKeyType theirPubKeyType;
407 switch(loop & 0x03) {
408 case 0:
409 theirPubKeyType = PKT_Ref;
410 break;
411 case 1:
412 theirPubKeyType = PKT_Wrap;
413 break;
414 case 2:
415 theirPubKeyType = PKT_X509;
416 break;
417 default:
418 theirPubKeyType = PKT_Octet;
419 break;
420 }
421
422 if(!bareCsp) {
423 /*
424 * Generated keys have to be reference
425 * pub keys have to be passed as Param
426 */
427 ourKeysRef = CSSM_TRUE;
428 theirPrivKeyRef = CSSM_TRUE;
429 theirPubKeyType = PKT_Wrap;
430 }
431
432 CSSM_BOOL useSharedInfo = CSSM_FALSE;
433 if(x963KDF & ((loop & 0x01) == 0)) {
434 useSharedInfo = CSSM_TRUE;
435 }
436 ourRtn = doTest(cspHand, ourKeysRef, theirPrivKeyRef, theirPubKeyType,
437 keySize, bareCsp, x963KDF, useSharedInfo, verbose, quiet);
438 if(ourRtn) {
439 break;
440 }
441 if(loops && (loop == loops)) {
442 break;
443 }
444 }
445 CSSM_ModuleDetach(cspHand);
446 if((ourRtn == 0) && !quiet) {
447 printf("OK\n");
448 }
449
450 return ourRtn;
451 }