]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTool/macOS/srCdsaUtils.cpp
Security-59306.11.20.tar.gz
[apple/security.git] / SecurityTool / macOS / srCdsaUtils.cpp
diff --git a/SecurityTool/macOS/srCdsaUtils.cpp b/SecurityTool/macOS/srCdsaUtils.cpp
new file mode 100644 (file)
index 0000000..59a98ae
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * Copyright (c) 2001,2003-2012,2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * srCdsaUtils.cpp -- common CDSA access utilities
+ */
+
+#include "srCdsaUtils.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <Security/SecCertificate.h>
+#include <Security/cssmapple.h>                                /* for cssmPerror() */
+#include <Security/oidsalg.h>                          /* for cssmPerror() */
+#include <strings.h>
+
+static CSSM_VERSION vers = {2, 0};
+static const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
+
+/*
+ * Standard app-level memory functions required by CDSA.
+ */
+void * srAppMalloc (CSSM_SIZE size, void *allocRef) {
+       return( malloc(size) );
+}
+
+void srAppFree (void *mem_ptr, void *allocRef) {
+       free(mem_ptr);
+       return;
+}
+
+void * srAppRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
+       return( realloc( ptr, size ) );
+}
+
+void * srAppCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
+       return( calloc( num, size ) );
+}
+
+static CSSM_API_MEMORY_FUNCS memFuncs = {
+       srAppMalloc,
+       srAppFree,
+       srAppRealloc,
+       srAppCalloc,
+       NULL
+ };
+
+CSSM_BOOL srCompareCssmData(const CSSM_DATA *d1,
+       const CSSM_DATA *d2)
+{
+       if(d1->Length != d2->Length) {
+               return CSSM_FALSE;
+       }
+       if(memcmp(d1->Data, d2->Data, d1->Length)) {
+               return CSSM_FALSE;
+       }
+       return CSSM_TRUE;
+}
+
+/*
+ * Init CSSM; returns CSSM_FALSE on error. Reusable.
+ */
+static CSSM_BOOL cssmInitd = CSSM_FALSE;
+
+CSSM_BOOL srCssmStartup()
+{
+       CSSM_RETURN  crtn;
+    CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
+
+       if(cssmInitd) {
+               return CSSM_TRUE;
+       }
+       crtn = CSSM_Init (&vers,
+               CSSM_PRIVILEGE_SCOPE_NONE,
+               &testGuid,
+               CSSM_KEY_HIERARCHY_NONE,
+               &pvcPolicy,
+               NULL /* reserved */);
+       if(crtn != CSSM_OK)
+       {
+               srPrintError("CSSM_Init", crtn);
+               return CSSM_FALSE;
+       }
+       else {
+               cssmInitd = CSSM_TRUE;
+               return CSSM_TRUE;
+       }
+}
+
+/*
+ * Attach to CSP. Returns zero on error.
+ */
+CSSM_CSP_HANDLE srCspStartup(
+       CSSM_BOOL bareCsp)              // true ==> CSP, false ==> CSP/DL
+{
+       CSSM_CSP_HANDLE cspHand;
+       CSSM_RETURN             crtn;
+       const CSSM_GUID *guid;
+
+       /* common CSSM init */
+       if(srCssmStartup() == CSSM_FALSE) {
+               return 0;
+       }
+       if(bareCsp) {
+               guid = &gGuidAppleCSP;
+       }
+       else {
+               guid = &gGuidAppleCSPDL;
+       }
+       crtn = CSSM_ModuleLoad(guid,
+               CSSM_KEY_HIERARCHY_NONE,
+               NULL,                   // eventHandler
+               NULL);                  // AppNotifyCallbackCtx
+       if(crtn) {
+               srPrintError("CSSM_ModuleLoad()", crtn);
+               return 0;
+       }
+       crtn = CSSM_ModuleAttach (guid,
+               &vers,
+               &memFuncs,                      // memFuncs
+               0,                                      // SubserviceID
+               CSSM_SERVICE_CSP,
+               0,                                      // AttachFlags
+               CSSM_KEY_HIERARCHY_NONE,
+               NULL,                           // FunctionTable
+               0,                                      // NumFuncTable
+               NULL,                           // reserved
+               &cspHand);
+       if(crtn) {
+               srPrintError("CSSM_ModuleAttach()", crtn);
+               return 0;
+       }
+       return cspHand;
+}
+
+/* Attach to DL side of CSPDL */
+CSSM_DL_HANDLE srDlStartup()
+{
+       CSSM_DL_HANDLE  dlHand = 0;
+       CSSM_RETURN             crtn;
+
+       if(srCssmStartup() == CSSM_FALSE) {
+               return 0;
+       }
+       crtn = CSSM_ModuleLoad(&gGuidAppleCSPDL,
+               CSSM_KEY_HIERARCHY_NONE,
+               NULL,                   // eventHandler
+               NULL);                  // AppNotifyCallbackCtx
+       if(crtn) {
+               srPrintError("CSSM_ModuleLoad(Apple CSPDL)", crtn);
+               return 0;
+       }
+       crtn = CSSM_ModuleAttach (&gGuidAppleCSPDL,
+               &vers,
+               &memFuncs,                      // memFuncs
+               0,                                      // SubserviceID
+               CSSM_SERVICE_DL,
+               0,                                      // AttachFlags
+               CSSM_KEY_HIERARCHY_NONE,
+               NULL,                           // FunctionTable
+               0,                                      // NumFuncTable
+               NULL,                           // reserved
+               &dlHand);
+       if(crtn) {
+               srPrintError("CSSM_ModuleAttach(Apple CSPDL)", crtn);
+               return 0;
+       }
+       return dlHand;
+}
+
+CSSM_CL_HANDLE srClStartup()
+{
+       CSSM_CL_HANDLE clHand;
+       CSSM_RETURN crtn;
+
+       if(srCssmStartup() == CSSM_FALSE) {
+               return 0;
+       }
+       crtn = CSSM_ModuleLoad(&gGuidAppleX509CL,
+               CSSM_KEY_HIERARCHY_NONE,
+               NULL,                   // eventHandler
+               NULL);                  // AppNotifyCallbackCtx
+       if(crtn) {
+               srPrintError("CSSM_ModuleLoad(AppleCL)", crtn);
+               return 0;
+       }
+       crtn = CSSM_ModuleAttach (&gGuidAppleX509CL,
+               &vers,
+               &memFuncs,                              // memFuncs
+               0,                                              // SubserviceID
+               CSSM_SERVICE_CL,                // SubserviceFlags - Where is this used?
+               0,                                              // AttachFlags
+               CSSM_KEY_HIERARCHY_NONE,
+               NULL,                                   // FunctionTable
+               0,                                              // NumFuncTable
+               NULL,                                   // reserved
+               &clHand);
+       if(crtn) {
+               srPrintError("CSSM_ModuleAttach(AppleCL)", crtn);
+               return 0;
+       }
+       else {
+               return clHand;
+       }
+}
+
+CSSM_TP_HANDLE srTpStartup()
+{
+       CSSM_TP_HANDLE tpHand;
+       CSSM_RETURN crtn;
+
+       if(srCssmStartup() == CSSM_FALSE) {
+               return 0;
+       }
+       crtn = CSSM_ModuleLoad(&gGuidAppleX509TP,
+               CSSM_KEY_HIERARCHY_NONE,
+               NULL,                   // eventHandler
+               NULL);                  // AppNotifyCallbackCtx
+       if(crtn) {
+               srPrintError("CSSM_ModuleLoad(AppleTP)", crtn);
+               return 0;
+       }
+       crtn = CSSM_ModuleAttach (&gGuidAppleX509TP,
+               &vers,
+               &memFuncs,                              // memFuncs
+               0,                                              // SubserviceID
+               CSSM_SERVICE_TP,                // SubserviceFlags
+               0,                                              // AttachFlags
+               CSSM_KEY_HIERARCHY_NONE,
+               NULL,                                   // FunctionTable
+               0,                                              // NumFuncTable
+               NULL,                                   // reserved
+               &tpHand);
+       if(crtn) {
+               srPrintError("CSSM_ModuleAttach(AppleTP)", crtn);
+               return 0;
+       }
+       else {
+               return tpHand;
+       }
+}
+
+/*
+ * Given a context specified via a CSSM_CC_HANDLE, add a new
+ * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
+ * AttributeLength, and an untyped pointer.
+ */
+static CSSM_RETURN srAddContextAttribute(CSSM_CC_HANDLE CCHandle,
+       uint32 AttributeType,
+       uint32 AttributeLength,
+       const void *AttributePtr)
+{
+       CSSM_CONTEXT_ATTRIBUTE          newAttr;
+       CSSM_RETURN                                     crtn;
+
+       newAttr.AttributeType     = AttributeType;
+       newAttr.AttributeLength   = AttributeLength;
+       newAttr.Attribute.Data    = (CSSM_DATA_PTR)AttributePtr;
+       crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
+       if(crtn) {
+               srPrintError("CSSM_UpdateContextAttributes", crtn);
+       }
+       return crtn;
+}
+
+
+/*
+ * Derive symmetric key.
+ * Note in the X CSP, we never return an IV.
+ */
+CSSM_RETURN srCspDeriveKey(CSSM_CSP_HANDLE cspHand,
+               uint32                          keyAlg,                 // CSSM_ALGID_RC5, etc.
+               const char                      *keyLabel,
+               unsigned                        keyLabelLen,
+               uint32                          keyUsage,               // CSSM_KEYUSE_ENCRYPT, etc.
+               uint32                          keySizeInBits,
+               CSSM_DATA_PTR           password,               // in PKCS-5 lingo
+               CSSM_DATA_PTR           salt,                   // ditto
+               uint32                          iterationCnt,   // ditto
+               CSSM_KEY_PTR            key)
+{
+       CSSM_RETURN                                     crtn;
+       CSSM_CC_HANDLE                          ccHand;
+       uint32                                          keyAttr;
+       CSSM_DATA                                       dummyLabel;
+       CSSM_PKCS5_PBKDF2_PARAMS        pbeParams;
+       CSSM_DATA                                       pbeData;
+       CSSM_ACCESS_CREDENTIALS         creds;
+
+       memset(key, 0, sizeof(CSSM_KEY));
+       memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+       crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
+               CSSM_ALGID_PKCS5_PBKDF2,
+               keyAlg,
+               keySizeInBits,
+               &creds,
+               NULL,                   // BaseKey
+               iterationCnt,
+               salt,
+               NULL,                   // seed
+               &ccHand);
+       if(crtn) {
+               srPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn);
+               return crtn;
+       }
+       keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF |
+                         CSSM_KEYATTR_SENSITIVE;
+       dummyLabel.Length = keyLabelLen;
+       dummyLabel.Data = (uint8 *)keyLabel;
+
+       /* passing in password is pretty strange....*/
+       pbeParams.Passphrase = *password;
+       pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
+       pbeData.Data = (uint8 *)&pbeParams;
+       pbeData.Length = sizeof(pbeParams);
+       crtn = CSSM_DeriveKey(ccHand,
+               &pbeData,
+               keyUsage,
+               keyAttr,
+               &dummyLabel,
+               NULL,                   // cred and acl
+               key);
+       if(crtn) {
+               srPrintError("CSSM_DeriveKey", crtn);
+               return crtn;
+       }
+       crtn = CSSM_DeleteContext(ccHand);
+       if(crtn) {
+               srPrintError("CSSM_DeleteContext", crtn);
+       }
+       return crtn;
+}
+
+/*
+ * Generate key pair of arbitrary algorithm.
+ */
+
+/* CSP DL currently does not perform DSA generate params; let CSP do it implicitly */
+#define DO_DSA_GEN_PARAMS              0
+
+CSSM_RETURN srCspGenKeyPair(CSSM_CSP_HANDLE cspHand,
+       CSSM_DL_DB_HANDLE *dlDbHand,    // optional
+       uint32 algorithm,
+       const char *keyLabel,
+       unsigned keyLabelLen,
+       uint32 keySize,                                 // in bits
+       CSSM_KEY_PTR pubKey,                    // mallocd by caller
+       CSSM_KEYUSE pubKeyUsage,                // CSSM_KEYUSE_ENCRYPT, etc.
+       CSSM_KEYATTR_FLAGS pubAttrs,    // CSSM_KEYATTR_EXTRACTABLE, etc.
+       CSSM_KEY_PTR privKey,                   // mallocd by caller
+       CSSM_KEYUSE privKeyUsage,               // CSSM_KEYUSE_DECRYPT, etc.
+       CSSM_KEYATTR_FLAGS privAttrs)   // CSSM_KEYATTR_EXTRACTABLE, etc.
+{
+       CSSM_RETURN                             crtn;
+       CSSM_RETURN                             ocrtn;
+       CSSM_CC_HANDLE                  ccHand;
+       CSSM_DATA                               keyLabelData;
+
+       keyLabelData.Data        = (uint8 *)keyLabel;
+       keyLabelData.Length      = keyLabelLen;
+       memset(pubKey, 0, sizeof(CSSM_KEY));
+       memset(privKey, 0, sizeof(CSSM_KEY));
+
+       crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
+               algorithm,
+               keySize,
+               NULL,                                   // Seed
+               NULL,                                   // Salt
+               NULL,                                   // StartDate
+               NULL,                                   // EndDate
+               NULL,                                   // Params
+               &ccHand);
+       if(crtn) {
+               srPrintError("CSSM_CSP_CreateKeyGenContext", crtn);
+               return crtn;
+       }
+
+       /* post-context-create algorithm-specific stuff */
+       switch(algorithm) {
+               #if DO_DSA_GEN_PARAMS
+               case CSSM_ALGID_DSA:
+                       /*
+                        * extra step - generate params - this just adds some
+                        * info to the context
+                        */
+                       {
+                               CSSM_DATA dummy = {0, NULL};
+                               crtn = CSSM_GenerateAlgorithmParams(ccHand,
+                                       keySize, &dummy);
+                               if(crtn) {
+                                       srPrintError("CSSM_GenerateAlgorithmParams", crtn);
+                                       CSSM_DeleteContext(ccHand);
+                                       return crtn;
+                               }
+                               srAppFree(dummy.Data, NULL);
+                       }
+                       break;
+               #endif  /* DO_DSA_GEN_PARAMS */
+               default:
+                       break;
+       }
+
+       /* optionally specify DL/DB storage location */
+       if(dlDbHand) {
+               crtn = srAddContextAttribute(ccHand,
+                       CSSM_ATTRIBUTE_DL_DB_HANDLE,
+                       sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
+                       dlDbHand);
+               if(crtn) {
+                       CSSM_DeleteContext(ccHand);
+                       return crtn;
+               }
+       }
+       ocrtn = CSSM_GenerateKeyPair(ccHand,
+               pubKeyUsage,
+               pubAttrs,
+               &keyLabelData,
+               pubKey,
+               privKeyUsage,
+               privAttrs,
+               &keyLabelData,                  // same labels
+               NULL,                                   // CredAndAclEntry
+               privKey);
+       if(ocrtn) {
+               srPrintError("CSSM_GenerateKeyPair", ocrtn);
+       }
+       crtn = CSSM_DeleteContext(ccHand);
+       if(crtn) {
+               srPrintError("CSSM_DeleteContext", crtn);
+               if(ocrtn == CSSM_OK) {
+                       /* error on CSSM_GenerateKeyPair takes precedence */
+                       ocrtn = crtn;
+               }
+       }
+       return ocrtn;
+}
+
+
+/*
+ * Add a certificate to an open Keychain.
+ */
+CSSM_RETURN srAddCertToKC(
+       SecKeychainRef          keychain,
+       const CSSM_DATA         *cert,
+       CSSM_CERT_TYPE          certType,
+       CSSM_CERT_ENCODING      certEncoding,
+       const char                      *printName,             // C string
+       const CSSM_DATA         *keyLabel)              // ??
+{
+       SecCertificateRef certificate;
+
+       OSStatus rslt = SecCertificateCreateFromData(cert, certType, certEncoding, &certificate);
+       if (!rslt)
+       {
+               rslt = SecCertificateAddToKeychain(certificate, keychain);
+               CFRelease(certificate);
+       }
+
+       return rslt;
+}
+
+/*
+ * Convert a CSSM_DATA_PTR, referring to a DER-encoded int, to an
+ * unsigned.
+ */
+unsigned srDER_ToInt(const CSSM_DATA *DER_Data)
+{
+       uint32          rtn = 0;
+       unsigned        i = 0;
+
+       while(i < DER_Data->Length) {
+               rtn |= DER_Data->Data[i];
+               if(++i == DER_Data->Length) {
+                       break;
+               }
+               rtn <<= 8;
+       }
+       return rtn;
+}
+
+/*
+ * Log CSSM error.
+ */
+void srPrintError(const char *op, CSSM_RETURN err)
+{
+       cssmPerror(op, err);
+}
+
+/*
+ * Convert a CFString into a C string as safely as we can. Caller must
+ * free the result.
+ */
+char *srCfStrToCString(
+       CFStringRef cfStr)
+{
+       CFIndex len = CFStringGetLength(cfStr) + 1;
+       char *cstr = (char *)malloc(len);
+       if(cstr == NULL) {
+               return NULL;
+       }
+       if(!CFStringGetCString(cfStr, cstr, len, kCFStringEncodingASCII)) {
+               printf("***CFStringGetCString error\n");
+               free(cstr);
+               return NULL;
+       }
+       return cstr;
+}
+