2 * Copyright (c) 2008 Apple Inc. All Rights Reserved.
4 * ecdhTest.cpp - Test Elliptic Curve Diffie-Hellman key exchange.
6 * Created Jan. 1 2008 by Doug Mitchell.
13 #include <Security/cssm.h>
18 #define KEY_SIZE_DEF 256
20 static void usage(char **argv
)
22 printf("usage: %s [options]\n", argv
[0]);
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");
29 printf(" v(erbose))\n");
33 #define LABEL_DEF "noLabel"
34 #define MAX_SHARED_INFO_LEN 400
35 #define MAX_DERIVED_SIZE 1024
38 CSSM_CSP_HANDLE cspHand
,
42 * Ref form - use key as pubKey as is
43 * X509 form - use as is
44 * OCTET_STRING form - use key data as Param
47 CSSM_BOOL bareCsp
, // false --> derive ref key and NULL-wrap it
49 CSSM_DATA
*sharedInfo
,
50 uint32 deriveSizeInBits
,
54 /* result RETURNED here */
55 CSSM_KEY_PTR derivedKey
)
58 CSSM_DATA paramData
= {0, NULL
};
59 CSSM_KEY_PTR contextPubKey
= NULL
;
60 CSSM_KEYHEADER_PTR hdr
= &pubKey
->KeyHeader
;
62 if((hdr
->BlobType
== CSSM_KEYBLOB_RAW
) &&
63 (hdr
->Format
== CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
)) {
64 paramData
= pubKey
->KeyData
;
67 contextPubKey
= pubKey
;
70 /* create key derivation context */
72 CSSM_ACCESS_CREDENTIALS creds
;
73 CSSM_CC_HANDLE ccHand
;
75 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
77 CSSM_ALGORITHMS deriveAlg
;
79 deriveAlg
= CSSM_ALGID_ECDH_X963_KDF
;
82 deriveAlg
= CSSM_ALGID_ECDH
;
85 crtn
= CSSM_CSP_CreateDeriveKeyContext(cspHand
,
87 CSSM_ALGID_RC4
, // doesn't matter, just give us the bits
96 printError("CSSM_CSP_CreateDeriveKeyContext", crtn
);
97 return testError(quiet
);
100 if(contextPubKey
!= NULL
) {
101 /* add pub key as a context attr */
102 crtn
= AddContextAttribute(ccHand
,
103 CSSM_ATTRIBUTE_PUBLIC_KEY
,
106 (void *)contextPubKey
,
109 printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_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
,
129 printError("CSSM_DeriveKey", crtn
);
131 CSSM_DeleteContext(ccHand
);
133 return testError(quiet
);
137 /* Got a ref key, give caller raw */
138 CSSM_KEY refKey
= *derivedKey
;
139 crtn
= cspRefKeyToRaw(cspHand
, &refKey
, derivedKey
);
140 cspFreeKey(cspHand
, &refKey
);
145 /* define public key style */
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 */
153 #define BoolStr(v) (v ? "true " : "false")
155 static const char *KeyStypeStr(
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";
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
,
175 CSSM_BOOL useSharedInfo
, /* use the optional SharedInfo for x963KDF */
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
;
193 /* arbitrary derived size */
194 deriveSizeInBits
= genRand(1, MAX_DERIVED_SIZE
);
197 deriveSizeInBits
= keySizeBits
;
200 /* length should be totally arbitrary */
201 appSetupCssmData(&sharedInfo
, MAX_SHARED_INFO_LEN
);
202 simpleGenData(&sharedInfo
, 1, MAX_SHARED_INFO_LEN
);
208 printf("...sharedInfoLen %4lu deriveSize %4lu ",
209 (unsigned long)sharedInfo
.Length
, (unsigned long)deriveSizeInBits
);
214 printf("ourRef %s theirPrivRef %s theirPub %s\n",
215 BoolStr(ourKeysRef
), BoolStr(theirPrivKeyRef
),
216 KeyStypeStr(theirPubKeyType
));
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
,
225 return testError(quiet
);
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
;
237 CSSM_BOOL pubIsRef
= CSSM_FALSE
;
238 CSSM_KEYBLOB_FORMAT blobForm
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
241 switch(theirPubKeyType
) {
244 pubIsRef
= CSSM_TRUE
;
247 pubIsRef
= CSSM_FALSE
;
250 pubIsRef
= CSSM_FALSE
;
251 blobForm
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;
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
,
261 ourRtn
= testError(quiet
);
265 if(theirPubKeyType
== PKT_Wrap
) {
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...
271 crtn
= cspRefKeyToRawWithFormat(cspHand
, &theirPub
,
272 CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
, &theirWrappedPub
);
274 ourRtn
= testError(quiet
);
277 theirPubPtr
= &theirWrappedPub
;
278 wrappedTheirPub
= true;
281 theirPubPtr
= &theirPub
;
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
290 crtn
= cspRefKeyToRawWithFormat(cspHand
, &ourPub
,
291 CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
, &ourWrappedPub
);
293 ourRtn
= testError(quiet
);
296 ourPubPtr
= &ourWrappedPub
;
297 wrappedOurPub
= true;
304 * Here we go, do the two sides of D-H key agreement, results to
307 ourRtn
= doECDH(cspHand
, &ourPriv
, theirPubPtr
, bareCsp
,
308 x963KDF
, useSharedInfo
? &sharedInfo
: NULL
,
309 deriveSizeInBits
, quiet
, verbose
, &derived1
);
313 ourRtn
= doECDH(cspHand
, &theirPriv
, ourPubPtr
, bareCsp
,
314 x963KDF
, useSharedInfo
? &sharedInfo
: NULL
,
315 deriveSizeInBits
, quiet
, verbose
, &derived2
);
320 if(!appCompareCssmData(&derived1
.KeyData
, &derived2
.KeyData
)) {
321 printf("***Data Miscompare on ECDH key derivation\n");
325 cspFreeKey(cspHand
, &ourPub
);
326 cspFreeKey(cspHand
, &ourPriv
);
329 cspFreeKey(cspHand
, &theirPub
);
330 cspFreeKey(cspHand
, &theirPriv
);
332 if(wrappedTheirPub
) {
333 cspFreeKey(cspHand
, &theirWrappedPub
);
336 cspFreeKey(cspHand
, &ourWrappedPub
);
339 cspFreeKey(cspHand
, &derived1
);
342 cspFreeKey(cspHand
, &derived2
);
344 if(sharedInfo
.Data
!= NULL
) {
345 appFreeCssmData(&sharedInfo
, CSSM_FALSE
);
350 int main(int argc
, char **argv
)
354 CSSM_CSP_HANDLE cspHand
;
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
;
365 for(arg
=1; arg
<argc
; arg
++) {
369 keySize
= atoi(&argp
[2]);
375 loops
= atoi(&argp
[2]);
378 bareCsp
= CSSM_FALSE
;
390 testStartBanner("ecdhTest", argc
, argv
);
392 cspHand
= cspDlDbStartup(bareCsp
, NULL
);
397 for(loop
=1; ; loop
++) {
399 printf("...Loop %d\n", loop
);
402 /* test mode from l.s. bits of loop counter */
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) {
409 theirPubKeyType
= PKT_Ref
;
412 theirPubKeyType
= PKT_Wrap
;
415 theirPubKeyType
= PKT_X509
;
418 theirPubKeyType
= PKT_Octet
;
424 * Generated keys have to be reference
425 * pub keys have to be passed as Param
427 ourKeysRef
= CSSM_TRUE
;
428 theirPrivKeyRef
= CSSM_TRUE
;
429 theirPubKeyType
= PKT_Wrap
;
432 CSSM_BOOL useSharedInfo
= CSSM_FALSE
;
433 if(x963KDF
& ((loop
& 0x01) == 0)) {
434 useSharedInfo
= CSSM_TRUE
;
436 ourRtn
= doTest(cspHand
, ourKeysRef
, theirPrivKeyRef
, theirPubKeyType
,
437 keySize
, bareCsp
, x963KDF
, useSharedInfo
, verbose
, quiet
);
441 if(loops
&& (loop
== loops
)) {
445 CSSM_ModuleDetach(cspHand
);
446 if((ourRtn
== 0) && !quiet
) {