]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/cspxutils/ecdhTest/ecdhTest.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / ecdhTest / ecdhTest.cpp
diff --git a/SecurityTests/cspxutils/ecdhTest/ecdhTest.cpp b/SecurityTests/cspxutils/ecdhTest/ecdhTest.cpp
new file mode 100644 (file)
index 0000000..3c694e1
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All Rights Reserved.
+ * 
+ * ecdhTest.cpp - Test Elliptic Curve Diffie-Hellman key exchange.
+ *
+ * Created Jan. 1 2008 by Doug Mitchell. 
+ */
+#include <stdlib.h>
+#include <strings.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <Security/cssm.h>
+#include "cspwrap.h"
+#include "common.h"
+
+#define LOOPS_DEF                      32
+#define KEY_SIZE_DEF           256
+
+static void usage(char **argv)
+{
+       printf("usage: %s [options]\n", argv[0]);
+       printf("Options:\n");
+       printf("  k=keySize (default = %d)\n", KEY_SIZE_DEF);
+       printf("  X (X9.63 key derivation)\n");
+       printf("  l=loops (0=forever)\n");
+       printf("  D (CSP/DL; default = bare CSP)\n");
+       printf("  q(uiet)\n");
+       printf("  v(erbose))\n");
+       exit(1);
+}
+
+#define LABEL_DEF                              "noLabel"
+#define MAX_SHARED_INFO_LEN            400
+#define MAX_DERIVED_SIZE               1024
+
+static int doECDH(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_KEY_PTR    privKey,
+       /* 
+        * pubKey:
+        *   Ref form - use key as pubKey as is
+        *   X509 form - use as is
+        *   OCTET_STRING form - use key data as Param
+        */
+       CSSM_KEY_PTR    pubKey,
+       CSSM_BOOL               bareCsp,        // false --> derive ref key and NULL-wrap it
+       CSSM_BOOL               x963KDF,
+       CSSM_DATA               *sharedInfo,
+       uint32                  deriveSizeInBits,
+       CSSM_BOOL               quiet,
+       CSSM_BOOL               verbose,
+       
+       /* result RETURNED here */
+       CSSM_KEY_PTR    derivedKey)
+       
+{
+       CSSM_DATA paramData = {0, NULL};
+       CSSM_KEY_PTR contextPubKey = NULL;
+       CSSM_KEYHEADER_PTR hdr = &pubKey->KeyHeader;
+       
+       if((hdr->BlobType == CSSM_KEYBLOB_RAW) && 
+          (hdr->Format == CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING)) {
+               paramData = pubKey->KeyData;
+       }
+       else {
+               contextPubKey = pubKey;
+       }
+       
+       /* create key derivation context */
+       CSSM_RETURN                     crtn;
+       CSSM_ACCESS_CREDENTIALS creds;
+       CSSM_CC_HANDLE                  ccHand;
+       
+       memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+       
+       CSSM_ALGORITHMS deriveAlg;
+       if(x963KDF) {
+               deriveAlg = CSSM_ALGID_ECDH_X963_KDF;
+       }
+       else {
+               deriveAlg = CSSM_ALGID_ECDH;
+       }
+       
+       crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
+               deriveAlg,
+               CSSM_ALGID_RC4, // doesn't matter, just give us the bits
+               deriveSizeInBits,
+               &creds,
+               privKey,                // BaseKey
+               0,                              // IterationCount
+               sharedInfo,             // Salt
+               0,                              // Seed
+               &ccHand);
+       if(crtn) {
+               printError("CSSM_CSP_CreateDeriveKeyContext", crtn);
+               return testError(quiet);
+       }
+       
+       if(contextPubKey != NULL) {
+               /* add pub key as a context attr */
+               crtn = AddContextAttribute(ccHand,
+                       CSSM_ATTRIBUTE_PUBLIC_KEY,
+                       sizeof(CSSM_KEY),       
+                       CAT_Ptr,
+                       (void *)contextPubKey,
+                       0);
+               if(crtn) {
+                       printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY)",
+                               crtn);
+                       return crtn;
+               }
+       }
+       
+       /* D-H derive key */
+       CSSM_DATA       labelData = { strlen(LABEL_DEF), (uint8 *)LABEL_DEF };
+       CSSM_KEYATTR_FLAGS keyAttr = bareCsp ? 
+               (CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE) :
+               (CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE);
+       memset(derivedKey, 0, sizeof(CSSM_KEY));
+       crtn = CSSM_DeriveKey(ccHand,
+               &paramData,
+               CSSM_KEYUSE_ANY,
+               keyAttr,
+               &labelData,
+               NULL,                           // cread/acl
+               derivedKey);
+       if(crtn) {
+               printError("CSSM_DeriveKey", crtn);
+       }
+       CSSM_DeleteContext(ccHand);
+       if(crtn) {
+               return testError(quiet);
+       }
+       
+       if(!bareCsp) {
+               /* Got a ref key, give caller raw */
+               CSSM_KEY refKey = *derivedKey;
+               crtn = cspRefKeyToRaw(cspHand, &refKey, derivedKey);
+               cspFreeKey(cspHand, &refKey);
+       }
+       return 0;
+}
+
+/* define public key style */
+typedef enum {
+       PKT_Ref,                /* ref key */
+       PKT_Wrap,               /* generate ref key, wrap to OCTET_STRING */
+       PKT_X509,               /* raw key X509 format */
+       PKT_Octet               /* generate to OCTET_STRING form */
+} PubKeyType;
+
+#define BoolStr(v)     (v ? "true " : "false")
+
+static const char *KeyStypeStr(
+       PubKeyType keyType)
+{
+       switch(keyType) {
+               case PKT_Ref:   return "Ref";
+               case PKT_Wrap:  return "Ref->Wrap";
+               case PKT_X509:  return "X509";
+               case PKT_Octet: return "X9.62";
+               default:                return "BRRZAP";
+       }
+}
+
+static int doTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_BOOL               ourKeysRef,                     /* our keys are reference */
+       CSSM_BOOL               theirPrivKeyRef,        /* their private key is reference */
+       PubKeyType              theirPubKeyType,
+       unsigned                keySizeBits,
+       CSSM_BOOL               bareCsp,
+       CSSM_BOOL               x963KDF,
+       CSSM_BOOL               useSharedInfo,          /* use the optional SharedInfo for x963KDF */
+       CSSM_BOOL               verbose,
+       CSSM_BOOL               quiet)
+{
+       
+       CSSM_RETURN crtn;
+       CSSM_KEY ourPriv;
+       CSSM_KEY ourPub;
+       bool ourKeysGend = false;
+       bool theirKeysGend = false;
+       bool wrappedTheirPub = false;
+       bool wrappedOurPub = false;
+       bool derivedKey1 = false;
+       bool derivedKey2 = false;
+       CSSM_DATA sharedInfo = {0, NULL};
+       uint32 deriveSizeInBits;
+
+       if(x963KDF) {
+               /* arbitrary derived size */
+               deriveSizeInBits = genRand(1, MAX_DERIVED_SIZE);
+       }
+       else {
+               deriveSizeInBits = keySizeBits;
+       }
+       if(useSharedInfo) {
+               /* length should be totally arbitrary */
+               appSetupCssmData(&sharedInfo, MAX_SHARED_INFO_LEN);
+               simpleGenData(&sharedInfo, 1, MAX_SHARED_INFO_LEN);
+       }
+       
+       
+       if(!quiet) {
+               if(x963KDF) {
+                       printf("...sharedInfoLen %4lu deriveSize %4lu ",
+                               (unsigned long)sharedInfo.Length, (unsigned long)deriveSizeInBits);
+               }
+               else {
+                       printf("...");
+               }
+               printf("ourRef %s theirPrivRef %s theirPub %s\n",
+                       BoolStr(ourKeysRef), BoolStr(theirPrivKeyRef), 
+                       KeyStypeStr(theirPubKeyType));
+       }
+       
+       crtn = cspGenKeyPair(cspHand, CSSM_ALGID_ECDSA, 
+               LABEL_DEF, strlen(LABEL_DEF), keySizeBits, 
+               &ourPub, ourKeysRef, CSSM_KEYUSE_DERIVE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
+               &ourPriv, ourKeysRef, CSSM_KEYUSE_DERIVE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
+               CSSM_FALSE);
+       if(crtn) {
+               return testError(quiet);
+       }
+       ourKeysGend = true;
+       
+       CSSM_KEY theirPriv;
+       CSSM_KEY theirPub;                      /* the generated one */
+       CSSM_KEY theirWrappedPub;       /* optional NULL unwrap */
+       CSSM_KEY_PTR theirPubPtr;
+       CSSM_KEY ourWrappedPub; /* optional NULL unwrap */
+       CSSM_KEY_PTR ourPubPtr;
+       CSSM_KEY derived1;
+       CSSM_KEY derived2;
+       CSSM_BOOL pubIsRef = CSSM_FALSE;
+       CSSM_KEYBLOB_FORMAT blobForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
+       int ourRtn = 0;
+       
+       switch(theirPubKeyType) {
+               case PKT_Ref:
+               case PKT_Wrap:
+                       pubIsRef = CSSM_TRUE;
+                       break;
+               case PKT_X509:
+                       pubIsRef = CSSM_FALSE;
+                       break;
+               case PKT_Octet:
+                       pubIsRef = CSSM_FALSE;
+                       blobForm = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
+                       break;
+       }
+       
+       crtn = cspGenKeyPair(cspHand, CSSM_ALGID_ECDSA, 
+               LABEL_DEF, strlen(LABEL_DEF), keySizeBits, 
+               &theirPub, pubIsRef, CSSM_KEYUSE_DERIVE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
+               &theirPriv, theirPrivKeyRef, CSSM_KEYUSE_DERIVE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
+               CSSM_FALSE);
+       if(crtn) {
+               ourRtn = testError(quiet);
+               goto errOut;
+       }
+
+       if(theirPubKeyType == PKT_Wrap) {
+               /* 
+                * This test mode is here mainly to ring out the key wrap and 
+                * OCTET_STRING format functionality in the CrypkitCSP, it's
+                * not really relevant to ECDH...
+                */
+               crtn = cspRefKeyToRawWithFormat(cspHand, &theirPub,
+                       CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING, &theirWrappedPub);
+               if(crtn) {
+                       ourRtn = testError(quiet);
+                       goto errOut;
+               }
+               theirPubPtr = &theirWrappedPub;
+               wrappedTheirPub = true;
+       }
+       else {
+               theirPubPtr = &theirPub;
+       }
+       
+       if(!bareCsp) {
+               /*
+                * For CSPDL, convert our pub key to OCTET_STRING format so it
+                * is sent as a Param - can't send a ref key (or any other pub 
+                * key) in the context
+                */
+               crtn = cspRefKeyToRawWithFormat(cspHand, &ourPub,
+                       CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING, &ourWrappedPub);
+               if(crtn) {
+                       ourRtn = testError(quiet);
+                       goto errOut;
+               }
+               ourPubPtr = &ourWrappedPub;
+               wrappedOurPub = true;
+       }
+       else {
+               ourPubPtr = &ourPub;
+       }
+
+       /* 
+        * Here we go, do the two sides of D-H key agreement, results to 
+        * to CSSM_KEYs.
+        */
+       ourRtn = doECDH(cspHand, &ourPriv, theirPubPtr, bareCsp, 
+               x963KDF, useSharedInfo ? &sharedInfo : NULL,
+               deriveSizeInBits, quiet, verbose, &derived1);
+       if(ourRtn) {
+               goto errOut;
+       }
+       ourRtn = doECDH(cspHand, &theirPriv, ourPubPtr, bareCsp, 
+               x963KDF, useSharedInfo ? &sharedInfo : NULL,    
+               deriveSizeInBits, quiet, verbose, &derived2);
+       if(ourRtn) {
+               goto errOut;
+       }
+
+       if(!appCompareCssmData(&derived1.KeyData, &derived2.KeyData)) {
+               printf("***Data Miscompare on ECDH key derivation\n");
+       }
+errOut:
+       if(ourKeysGend) {
+               cspFreeKey(cspHand, &ourPub);
+               cspFreeKey(cspHand, &ourPriv);
+       }
+       if(theirKeysGend) {
+               cspFreeKey(cspHand, &theirPub);
+               cspFreeKey(cspHand, &theirPriv);
+       }
+       if(wrappedTheirPub) {
+               cspFreeKey(cspHand, &theirWrappedPub);
+       }
+       if(wrappedOurPub) {
+               cspFreeKey(cspHand, &ourWrappedPub);
+       }
+       if(derivedKey1) {
+               cspFreeKey(cspHand, &derived1);
+       }
+       if(derivedKey2) {
+               cspFreeKey(cspHand, &derived2);
+       }
+       if(sharedInfo.Data != NULL) {
+               appFreeCssmData(&sharedInfo, CSSM_FALSE);
+       }
+       return ourRtn;
+}
+
+int main(int argc, char **argv)
+{
+       int                             arg;
+       char                    *argp;
+       CSSM_CSP_HANDLE cspHand;
+       unsigned                loop;
+       int                             ourRtn = 0;
+       
+       unsigned        keySize = KEY_SIZE_DEF;
+       unsigned        loops = LOOPS_DEF;
+       CSSM_BOOL       quiet = CSSM_FALSE;
+       CSSM_BOOL       verbose = CSSM_FALSE;
+       CSSM_BOOL       bareCsp = CSSM_TRUE;
+       CSSM_BOOL       x963KDF = CSSM_FALSE;
+       
+       for(arg=1; arg<argc; arg++) { 
+               argp = argv[arg];
+           switch(argp[0]) {
+                       case 'k':
+                               keySize = atoi(&argp[2]);
+                               break;
+                       case 'X':
+                               x963KDF = true;
+                               break;
+                   case 'l':
+                               loops = atoi(&argp[2]);
+                               break;
+                       case 'D':
+                               bareCsp = CSSM_FALSE;
+                               break;
+                       case 'q':
+                               quiet = CSSM_TRUE;
+                               break;
+                   case 'v':
+                       verbose = CSSM_TRUE;
+                               break;
+                       default:
+                               usage(argv);
+               }
+       }
+       testStartBanner("ecdhTest", argc, argv);        
+
+       cspHand = cspDlDbStartup(bareCsp, NULL);
+       if(cspHand == 0) {
+               exit(1);
+       }
+       
+       for(loop=1; ; loop++) {
+               if(!quiet) {
+                       printf("...Loop %d\n", loop);
+               }
+               
+               /* test mode from l.s. bits of loop counter */
+
+               CSSM_BOOL ourKeysRef = (loop & 0x04) ? CSSM_TRUE : CSSM_FALSE;
+               CSSM_BOOL theirPrivKeyRef = (loop & 0x08) ? CSSM_TRUE : CSSM_FALSE;
+               PubKeyType theirPubKeyType;
+               switch(loop & 0x03) {
+                       case 0:
+                               theirPubKeyType = PKT_Ref;
+                               break;
+                       case 1:
+                               theirPubKeyType = PKT_Wrap;
+                               break;
+                       case 2:
+                               theirPubKeyType = PKT_X509;
+                               break;
+                       default:
+                               theirPubKeyType = PKT_Octet;
+                               break;
+               }
+               
+               if(!bareCsp) {
+                       /* 
+                        * Generated keys have to be reference
+                        * pub keys have to be passed as Param
+                        */
+                       ourKeysRef = CSSM_TRUE;
+                       theirPrivKeyRef = CSSM_TRUE;
+                       theirPubKeyType = PKT_Wrap;
+               }
+               
+               CSSM_BOOL useSharedInfo = CSSM_FALSE;
+               if(x963KDF & ((loop & 0x01) == 0)) {
+                       useSharedInfo = CSSM_TRUE;
+               }
+               ourRtn = doTest(cspHand, ourKeysRef, theirPrivKeyRef, theirPubKeyType,
+                       keySize, bareCsp, x963KDF, useSharedInfo, verbose, quiet);
+               if(ourRtn) {
+                       break;
+               }
+               if(loops && (loop == loops)) {
+                       break;
+               }
+       }
+       CSSM_ModuleDetach(cspHand);
+       if((ourRtn == 0) && !quiet) {
+               printf("OK\n");
+       }
+
+       return ourRtn;
+}