2 * dhFullTest - Diffie-Hellman exerciser.
6 #include <Security/cssm.h>
9 #include <security_cdsa_utils/cuFileIo.h>
11 #include "cspdlTesting.h"
13 #define USAGE_DEF "noUsage"
15 #define KEY_SIZE_DEF 512
16 #define DERIVE_KEY_SIZE 128
17 #define DERIVE_KEY_ALG CSSM_ALGID_AES
18 #define ENCR_ALG CSSM_ALGID_AES
19 #define ENCR_MODE CSSM_ALGMODE_CBCPadIV8
20 #define ENCR_PADDING CSSM_PADDING_PKCS7
21 #define MAX_PTEXT_SIZE 1024
23 static void usage(char **argv
)
25 printf("usage: %s [options]\n", argv
[0]);
27 printf(" k=keySize (default = %d)\n", KEY_SIZE_DEF
);
28 printf(" l=loops (0=forever)\n");
29 printf(" p=pauseInterval (default=0, no pause)\n");
30 printf(" D (CSP/DL; default = bare CSP)\n");
31 printf(" o=fileName (dump key and param blobs to filename)\n");
32 printf(" i=filename (obtain param blobs from filename\n");
34 printf(" v(erbose))\n");
39 * Translate blob format to strings.
42 CSSM_KEYBLOB_FORMAT form
;
46 static const BlobDesc BlobDescs
[] = {
47 { CSSM_KEYBLOB_RAW_FORMAT_NONE
, "NONE" },
48 { CSSM_KEYBLOB_RAW_FORMAT_PKCS3
, "PKCS3" },
49 { CSSM_KEYBLOB_RAW_FORMAT_PKCS8
, "PKCS8" },
50 { CSSM_KEYBLOB_RAW_FORMAT_X509
, "X509" },
52 #define NUM_BLOB_DESCS (sizeof(BlobDescs) / sizeof(BlobDesc))
54 static const char *blobFormStr(
55 CSSM_KEYBLOB_FORMAT form
)
57 for(unsigned i
=0; i
<NUM_BLOB_DESCS
; i
++) {
58 const BlobDesc
*bdp
= &BlobDescs
[i
];
59 if(bdp
->form
== form
) {
63 return "***UNKNOWN BLOB FORM""";
67 * Generate a Diffie-Hellman key pair. Optionally allows specification of
68 * algorithm parameters, and optionally returns algorithm parameters if
72 CSSM_CSP_HANDLE cspHand
,
75 CSSM_KEYBLOB_FORMAT pubForm
, // NONE, PKCS3, X509
76 CSSM_KEYBLOB_FORMAT expectPubForm
, // PKCS3, X509
79 CSSM_KEYBLOB_FORMAT privForm
, // NONE, PKCS3, PKCS8
80 CSSM_KEYBLOB_FORMAT expectPrivForm
, // PKCS3, PKCS8
81 const CSSM_DATA
*inParams
, // optional
82 CSSM_DATA_PTR outParams
, // optional, we malloc
87 CSSM_CC_HANDLE ccHand
;
88 CSSM_DATA labelData
= { strlen(USAGE_DEF
), (uint8
*)USAGE_DEF
};
90 if(inParams
&& outParams
) {
91 printf("***dhKeyGen: inParams and outParams are mutually "
95 memset(pubKey
, 0, sizeof(CSSM_KEY
));
96 memset(privKey
, 0, sizeof(CSSM_KEY
));
98 crtn
= CSSM_CSP_CreateKeyGenContext(cspHand
,
105 inParams
, // Params, may be NULL
108 printError("CSSM_CSP_CreateKeyGenContext", crtn
);
109 return testError(quiet
);
112 if((inParams
== NULL
) && (outParams
!= NULL
)) {
113 /* explicitly generate params and return them to caller */
114 outParams
->Data
= NULL
;
115 outParams
->Length
= 0;
116 crtn
= CSSM_GenerateAlgorithmParams(ccHand
,
117 keySizeInBits
, outParams
);
119 printError("CSSM_GenerateAlgorithmParams", crtn
);
120 return testError(quiet
);
124 if((privForm
!= CSSM_KEYBLOB_RAW_FORMAT_NONE
) && !privIsRef
) {
125 crtn
= AddContextAttribute(ccHand
,
126 CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT
,
132 printError("AddContextAttribute(CSSM_ATTRIBUTE_PRIVATE_KEY_"
137 if((pubForm
!= CSSM_KEYBLOB_RAW_FORMAT_NONE
) && !pubIsRef
) {
138 crtn
= AddContextAttribute(ccHand
,
139 CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT
,
145 printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_"
152 uint32 pubAttr
= CSSM_KEYATTR_EXTRACTABLE
;
154 pubAttr
|= CSSM_KEYATTR_RETURN_REF
;
157 pubAttr
|= CSSM_KEYATTR_RETURN_DATA
;
160 privAttr
= CSSM_KEYATTR_RETURN_REF
;
163 privAttr
= CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
;
165 crtn
= CSSM_GenerateKeyPair(ccHand
,
167 * Public key specification. We specify raw key format
168 * here since we have to have access to the raw public key
169 * bits in order to perform D-H key exchange.
171 CSSM_KEYUSE_DERIVE
, // only legal use of a Diffie-Hellman key
175 /* private key specification */
178 &labelData
, // same labels
179 NULL
, // CredAndAclEntry
182 printError("CSSM_GenerateKeyPair", crtn
);
183 return testError(quiet
);
185 if(!privIsRef
&& (privKey
->KeyHeader
.Format
!= expectPrivForm
)) {
186 printf("***Expected priv format %s got %s\n",
187 blobFormStr(expectPrivForm
),
188 blobFormStr(privKey
->KeyHeader
.Format
));
189 return testError(quiet
);
191 if(!pubIsRef
&& (pubKey
->KeyHeader
.Format
!= expectPubForm
)) {
192 printf("***Expected pub format %s got %s\n",
193 blobFormStr(expectPubForm
),
194 blobFormStr(pubKey
->KeyHeader
.Format
));
195 return testError(quiet
);
197 CSSM_DeleteContext(ccHand
);
202 * Perform Diffie-Hellman key exchange.
203 * Given "our" private key (in the form of a CSSM_KEY) and "their" public
204 * key (in the form of a raw blob of bytes), cook up a symmetric key.
206 static int dhKeyExchange(
207 CSSM_CSP_HANDLE cspHand
,
208 CSSM_KEY_PTR myPrivKey
,
209 CSSM_KEY_PTR theirPubKey
,
210 CSSM_KEY_PTR derivedKey
, // RETURNED
211 uint32 deriveKeySizeInBits
,
212 CSSM_ALGORITHMS derivedKeyAlg
,
213 uint32 derivedKeyUsage
,
214 uint32 derivedKeyAttr
,
218 CSSM_ACCESS_CREDENTIALS creds
;
219 CSSM_CC_HANDLE ccHand
;
220 CSSM_DATA labelData
=
221 { strlen(USAGE_DEF
), (uint8
*)USAGE_DEF
};
223 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
224 memset(derivedKey
, 0, sizeof(CSSM_KEY
));
226 crtn
= CSSM_CSP_CreateDeriveKeyContext(cspHand
,
231 myPrivKey
, // BaseKey
237 printError("CSSM_CSP_CreateDeriveKeyContext", crtn
);
238 return testError(quiet
);
242 * Public key passed in as CSSM_DATA *Param - only if
243 * the pub key is in raw PKCS3 form
245 CSSM_DATA nullParam
= {0, NULL
};
246 CSSM_DATA_PTR paramPtr
;
247 CSSM_KEYHEADER
&hdr
= theirPubKey
->KeyHeader
;
248 if((hdr
.BlobType
== CSSM_KEYBLOB_RAW
) &&
249 (hdr
.Format
== CSSM_KEYBLOB_RAW_FORMAT_PKCS3
)) {
251 paramPtr
= &theirPubKey
->KeyData
;
254 /* add this pub key as a context attr */
255 crtn
= AddContextAttribute(ccHand
,
256 CSSM_ATTRIBUTE_PUBLIC_KEY
,
262 printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY)",
266 paramPtr
= &nullParam
;
269 crtn
= CSSM_DeriveKey(ccHand
,
277 printError("CSSM_DeriveKey", crtn
);
279 CSSM_DeleteContext(ccHand
);
283 static CSSM_DATA someIv
= {16, (uint8
*)"Some enchanted init vector" };
286 * Encrypt ptext with myDeriveKey ==> ctext
287 * decrypt ctext with theirDeriveKey ==> rptext
288 * ensure ptext == rptext
290 static int doEncryptTest(
291 CSSM_CSP_HANDLE cspHand
,
292 const CSSM_DATA
*ptext
,
293 CSSM_KEY_PTR myDeriveKey
,
294 CSSM_KEY_PTR theirDeriveKey
,
295 CSSM_ALGORITHMS encrAlg
,
297 CSSM_PADDING encrPadding
,
300 CSSM_DATA ctext
= {0, NULL
};
301 CSSM_DATA rptext
= {0, NULL
};
304 crtn
= cspEncrypt(cspHand
,
310 0, // effective key size
315 CSSM_FALSE
); // mallocCtext
317 return testError(quiet
);
319 crtn
= cspDecrypt(cspHand
,
325 0, // effective key size
330 CSSM_FALSE
); // mallocCtext
332 return testError(quiet
);
334 if(!appCompareCssmData(ptext
, &rptext
)) {
335 printf("***DATA MISCOMPARE***\n");
336 return testError(quiet
);
338 appFree(ctext
.Data
, NULL
);
339 appFree(rptext
.Data
, NULL
);
344 CSSM_CSP_HANDLE cspHand
,
345 const CSSM_DATA
*ptext
,
347 CSSM_KEYBLOB_FORMAT pubForm
, // NONE, PKCS3, X509
348 CSSM_KEYBLOB_FORMAT expectPubForm
, // PKCS3, X509
350 CSSM_KEYBLOB_FORMAT privForm
, // NONE, PKCS3, PKCS8
351 CSSM_KEYBLOB_FORMAT expectPrivForm
, // PKCS3, PKCS8
354 const CSSM_DATA
*inParams
, // optional
355 CSSM_DATA_PTR outParams
, // optional
356 uint32 keySizeInBits
,
365 /* generate two key pairs */
382 /* note this MUST match the params either specified or generated
383 * in previous call */
384 if((inParams
== NULL
) && (outParams
== NULL
)) {
385 printf("***BRRZAP! Must provide a way to match D-H parameters!\n");
388 const CSSM_DATA
*theParams
= inParams
;
389 if(theParams
== NULL
) {
390 theParams
= outParams
;
395 /* let's always use default for this pair */
396 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
397 CSSM_KEYBLOB_RAW_FORMAT_PKCS3
, // we know this is the default
400 /* let's always use default for this pair */
401 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
402 CSSM_KEYBLOB_RAW_FORMAT_PKCS3
, // we know this is the default
410 /* derive two keys, ensure they match */
412 CSSM_KEY theirDerive
;
414 uint32 theirDeriveAttr
;
416 myDeriveAttr
= CSSM_KEYATTR_RETURN_REF
;
420 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
;
423 theirDeriveAttr
= CSSM_KEYATTR_RETURN_REF
;
427 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
;
429 if(dhKeyExchange(cspHand
,
438 return testError(quiet
);
440 if(dhKeyExchange(cspHand
,
449 return testError(quiet
);
452 if(doEncryptTest(cspHand
,
463 cspFreeKey(cspHand
, &myPub
);
464 cspFreeKey(cspHand
, &myPriv
);
465 cspFreeKey(cspHand
, &theirPub
);
466 cspFreeKey(cspHand
, &theirPriv
);
467 cspFreeKey(cspHand
, &myDerive
);
468 cspFreeKey(cspHand
, &theirDerive
);
472 int main(int argc
, char **argv
)
476 CSSM_CSP_HANDLE cspHand
;
479 CSSM_DATA inParams
= {0, NULL
};
480 CSSM_DATA outParams
= {0, NULL
};
481 CSSM_DATA_PTR inParamPtr
= NULL
;
482 CSSM_DATA_PTR outParamPtr
= NULL
;
488 CSSM_KEYBLOB_FORMAT pubForm
; // NONE, PKCS3, X509
489 CSSM_KEYBLOB_FORMAT expectPubForm
; // PKCS3, X509
490 CSSM_KEYBLOB_FORMAT privForm
; // NONE, PKCS3, PKCS8
491 CSSM_KEYBLOB_FORMAT expectPrivForm
; // PKCS3, PKCS8
493 /* user-spec'd parameters */
494 unsigned keySize
= KEY_SIZE_DEF
;
495 unsigned pauseInterval
= 0;
496 unsigned loops
= LOOPS_DEF
;
497 CSSM_BOOL quiet
= CSSM_FALSE
;
498 CSSM_BOOL verbose
= CSSM_FALSE
;
499 CSSM_BOOL bareCsp
= CSSM_TRUE
;
500 char *inFileName
= NULL
;
501 char *outFileName
= NULL
;
503 for(arg
=1; arg
<argc
; arg
++) {
507 keySize
= atoi(&argp
[2]);
510 loops
= atoi(&argp
[2]);
513 pauseInterval
= atoi(&argp
[2]);
516 inFileName
= &argp
[2];
519 outFileName
= &argp
[2];
522 bareCsp
= CSSM_FALSE
;
535 cspHand
= cspDlDbStartup(bareCsp
, NULL
);
541 !CSPDL_DSA_GEN_PARAMS
&&
542 (inFileName
== NULL
)) {
544 * For now, CSPDL can not do gen parameters. This only
545 * works if we're supplied params externally (which most
546 * likely were generated from the bare CSP).
548 printf("*** %s can't run with CSPDL unless you supply DH "
549 "parameters.\n", argv
[0]);
553 /* optionally fetch algorithm parameters from a file */
556 int r
= readFile(inFileName
, &inParams
.Data
, &len
);
558 printf("***Can't read parameters from %s; aborting.\n",
562 inParams
.Length
= len
;
563 /* constant from now on */
564 inParamPtr
= &inParams
;
567 /* first time thru, no user-supplied parameters; generate them and
568 * save in outParams */
569 outParamPtr
= &outParams
;
572 ptext
.Data
= (uint8
*)appMalloc(MAX_PTEXT_SIZE
, NULL
);
573 /* ptext length set in test loop */
575 printf("Starting %s; args: ", argv
[0]);
576 for(i
=1; i
<argc
; i
++) {
577 printf("%s ", argv
[i
]);
580 for(loop
=1; ; loop
++) {
582 printf("...Loop %d\n", loop
);
584 simpleGenData(&ptext
, 10, MAX_PTEXT_SIZE
);
586 /* mix up raw and ref keys, except for CSPDL which
587 * requires all ref keys */
589 pubIsRef
= (loop
& 1) ? CSSM_TRUE
: CSSM_FALSE
;
590 privIsRef
= (loop
& 2) ? CSSM_TRUE
: CSSM_FALSE
;
591 sym1IsRef
= (loop
& 4) ? CSSM_TRUE
: CSSM_FALSE
;
592 sym2IsRef
= (loop
& 8) ? CSSM_TRUE
: CSSM_FALSE
;
595 pubIsRef
= privIsRef
= sym1IsRef
= sym2IsRef
= CSSM_TRUE
;
598 int die
= genRand(1,3);
601 privForm
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
602 expectPrivForm
= CSSM_KEYBLOB_RAW_FORMAT_PKCS3
;
605 privForm
= expectPrivForm
=
606 CSSM_KEYBLOB_RAW_FORMAT_PKCS3
;
609 privForm
= expectPrivForm
=
610 CSSM_KEYBLOB_RAW_FORMAT_PKCS8
;
614 printf("...privIsRef false; form %s, expectForm %s\n",
615 blobFormStr(privForm
), blobFormStr(expectPrivForm
));
619 privForm
= expectPrivForm
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
621 printf("...privIsRef true\n");
625 int die
= genRand(1,3);
628 pubForm
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
629 expectPubForm
= CSSM_KEYBLOB_RAW_FORMAT_PKCS3
;
632 pubForm
= expectPubForm
=
633 CSSM_KEYBLOB_RAW_FORMAT_PKCS3
;
636 pubForm
= expectPubForm
=
637 CSSM_KEYBLOB_RAW_FORMAT_X509
;
641 printf("...pubIsRef false; form %s, expectForm %s\n",
642 blobFormStr(pubForm
), blobFormStr(expectPubForm
));
646 pubForm
= expectPubForm
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
648 printf("...pubIsRef true\n");
669 /* first time thru */
671 /* save parameters for another run */
672 i
= writeFile(outFileName
, outParams
.Data
, outParams
.Length
);
674 printf("***Error writing params to %s; continuing.\n",
679 printf("...wrote %lu bytes to %s\n",
680 outParams
.Length
, outFileName
);
685 /* from now on, use the parameters we just generated */
686 inParamPtr
= &outParams
;
688 /* and in any case don't fetch any more params */
691 if(loops
&& (loop
== loops
)) {
694 if(pauseInterval
&& ((loop
% pauseInterval
) == 0)) {
698 printf("Hit CR to proceed, q to quit: ");
705 appFree(ptext
.Data
, NULL
);
706 CSSM_ModuleDetach(cspHand
);