+++ /dev/null
-/*
- * Copyright (c) 2003-2005,2008 Apple Inc. All Rights Reserved.
- *
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please
- * obtain a copy of the License at http://www.apple.com/publicsource and
- * read it before using this file.
- *
- * This 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.
- */
-
-/*
- * dbCert.cpp - import a possibly bad cert along with its private key
- */
-
-#include "dbCert.h"
-#include <Security/Security.h>
-#include <security_cdsa_utils/cuFileIo.h>
-#include <security_cdsa_utils/cuDbUtils.h>
-#include <security_cdsa_utils/cuCdsaUtils.h>
-#include <security_cdsa_utils/cuPem.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-/* Copied from clxutils/clAppUtils/tpUtils */
-/* defined in SecKeychainAPIPriv.h */
-static const int kSecAliasItemAttr = 'alis';
-
-/* Macro to declare a CSSM_DB_SCHEMA_ATTRIBUTE_INFO */
-#define SCHEMA_ATTR_INFO(id, name, type) \
- { id, (char *)name, {0, NULL}, CSSM_DB_ATTRIBUTE_FORMAT_ ## type }
-
-/* Too bad we can't get this from inside of the Security framework. */
-static CSSM_DB_SCHEMA_ATTRIBUTE_INFO certSchemaAttrInfo[] =
-{
- SCHEMA_ATTR_INFO(kSecCertTypeItemAttr, "CertType", UINT32),
- SCHEMA_ATTR_INFO(kSecCertEncodingItemAttr, "CertEncoding", UINT32),
- SCHEMA_ATTR_INFO(kSecLabelItemAttr, "PrintName", BLOB),
- SCHEMA_ATTR_INFO(kSecAliasItemAttr, "Alias", BLOB),
- SCHEMA_ATTR_INFO(kSecSubjectItemAttr, "Subject", BLOB),
- SCHEMA_ATTR_INFO(kSecIssuerItemAttr, "Issuer", BLOB),
- SCHEMA_ATTR_INFO(kSecSerialNumberItemAttr, "SerialNumber", BLOB),
- SCHEMA_ATTR_INFO(kSecSubjectKeyIdentifierItemAttr, "SubjectKeyIdentifier", BLOB),
- SCHEMA_ATTR_INFO(kSecPublicKeyHashItemAttr, "PublicKeyHash", BLOB)
-};
-#define NUM_CERT_SCHEMA_ATTRS \
- (sizeof(certSchemaAttrInfo) / sizeof(CSSM_DB_SCHEMA_ATTRIBUTE_INFO))
-
-/* Macro to declare a CSSM_DB_SCHEMA_INDEX_INFO */
-#define SCHEMA_INDEX_INFO(id, indexNum, indexType) \
- { id, CSSM_DB_INDEX_ ## indexType, CSSM_DB_INDEX_ON_ATTRIBUTE }
-
-
-static CSSM_DB_SCHEMA_INDEX_INFO certSchemaIndices[] =
-{
- SCHEMA_INDEX_INFO(kSecCertTypeItemAttr, 0, UNIQUE),
- SCHEMA_INDEX_INFO(kSecIssuerItemAttr, 0, UNIQUE),
- SCHEMA_INDEX_INFO(kSecSerialNumberItemAttr, 0, UNIQUE),
- SCHEMA_INDEX_INFO(kSecCertTypeItemAttr, 1, NONUNIQUE),
- SCHEMA_INDEX_INFO(kSecSubjectItemAttr, 2, NONUNIQUE),
- SCHEMA_INDEX_INFO(kSecIssuerItemAttr, 3, NONUNIQUE),
- SCHEMA_INDEX_INFO(kSecSerialNumberItemAttr, 4, NONUNIQUE),
- SCHEMA_INDEX_INFO(kSecSubjectKeyIdentifierItemAttr, 5, NONUNIQUE),
- SCHEMA_INDEX_INFO(kSecPublicKeyHashItemAttr, 6, NONUNIQUE)
-};
-#define NUM_CERT_INDICES \
- (sizeof(certSchemaIndices) / sizeof(CSSM_DB_SCHEMA_INDEX_INFO))
-
-
-CSSM_RETURN tpAddCertSchema(
- CSSM_DL_DB_HANDLE dlDbHand)
-{
- return CSSM_DL_CreateRelation(dlDbHand,
- CSSM_DL_DB_RECORD_X509_CERTIFICATE,
- "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
- NUM_CERT_SCHEMA_ATTRS,
- certSchemaAttrInfo,
- NUM_CERT_INDICES,
- certSchemaIndices);
-}
-
-
-/* copied verbatim from certTool */
-
-/*
- * Find private key by label, modify its Label attr to be the
- * hash of the associated public key.
- */
-static CSSM_RETURN setPubKeyHash(
- CSSM_CSP_HANDLE cspHand,
- CSSM_DL_DB_HANDLE dlDbHand,
- const char *keyLabel, // look up by this
- CSSM_DATA *rtnKeyDigest) // optionally RETURNED, if so,
- // caller owns and must cuAppFree
-{
- CSSM_QUERY query;
- CSSM_SELECTION_PREDICATE predicate;
- CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
- CSSM_RETURN crtn;
- CSSM_DATA labelData;
- CSSM_HANDLE resultHand;
-
- labelData.Data = (uint8 *)keyLabel;
- labelData.Length = strlen(keyLabel) + 1; // incl. NULL
- query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
- query.Conjunctive = CSSM_DB_NONE;
- query.NumSelectionPredicates = 1;
- predicate.DbOperator = CSSM_DB_EQUAL;
-
- predicate.Attribute.Info.AttributeNameFormat =
- CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
- predicate.Attribute.Info.Label.AttributeName = (char *)"Label";
- predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
- /* hope this cast is OK */
- predicate.Attribute.Value = &labelData;
- query.SelectionPredicate = &predicate;
-
- query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
- query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
- query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA; // FIXME - used?
-
- /* build Record attribute with one attr */
- CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
- CSSM_DB_ATTRIBUTE_DATA attr;
- attr.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
- attr.Info.Label.AttributeName = (char *)"Label";
- attr.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
-
- recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
- recordAttrs.NumberOfAttributes = 1;
- recordAttrs.AttributeData = &attr;
-
- CSSM_DATA recordData = {0, NULL};
- crtn = CSSM_DL_DataGetFirst(dlDbHand,
- &query,
- &resultHand,
- &recordAttrs,
- &recordData,
- &record);
- /* abort only on success */
- if(crtn != CSSM_OK) {
- cuPrintError("CSSM_DL_DataGetFirst", crtn);
- return crtn;
- }
-
- CSSM_KEY_PTR keyToDigest = (CSSM_KEY_PTR)recordData.Data;
- CSSM_DATA_PTR keyDigest = NULL;
- CSSM_CC_HANDLE ccHand;
- crtn = CSSM_CSP_CreatePassThroughContext(cspHand,
- keyToDigest,
- &ccHand);
- if(crtn) {
- cuPrintError("CSSM_CSP_CreatePassThroughContext", crtn);
- return crtn;
- }
- crtn = CSSM_CSP_PassThrough(ccHand,
- CSSM_APPLECSP_KEYDIGEST,
- NULL,
- (void **)&keyDigest);
- if(crtn) {
- cuPrintError("CSSM_CSP_PassThrough(PUBKEYHASH)", crtn);
- return -1;
- }
- CSSM_FreeKey(cspHand, NULL, keyToDigest, CSSM_FALSE);
- CSSM_DeleteContext(ccHand);
-
- /*
- * Replace Label attr data with hash.
- * NOTE: the module which allocated this attribute data - a DL -
- * was loaded and attached by the Sec layer, not by us. Thus
- * we can't use the memory allocator functions *we* used when
- * attaching to the CSPDL - we have to use the ones
- * which the Sec layer registered with the DL.
- */
- CSSM_API_MEMORY_FUNCS memFuncs;
- crtn = CSSM_GetAPIMemoryFunctions(dlDbHand.DLHandle, &memFuncs);
- if(crtn) {
- cuPrintError("CSSM_GetAPIMemoryFunctions(DLHandle)", crtn);
- /* oh well, leak and continue */
- }
- else {
- memFuncs.free_func(attr.Value->Data, memFuncs.AllocRef);
- memFuncs.free_func(attr.Value, memFuncs.AllocRef);
- }
- attr.Value = keyDigest;
-
- /* modify key attributes */
- crtn = CSSM_DL_DataModify(dlDbHand,
- CSSM_DL_DB_RECORD_PRIVATE_KEY,
- record,
- &recordAttrs,
- NULL, // DataToBeModified
- CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
- if(crtn) {
- cuPrintError("CSSM_DL_DataModify(PUBKEYHASH)", crtn);
- return crtn;
- }
- crtn = CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
- if(crtn) {
- cuPrintError("CSSM_DL_DataAbortQuery", crtn);
- /* let's keep going in this case */
- }
- crtn = CSSM_DL_FreeUniqueRecord(dlDbHand, record);
- if(crtn) {
- cuPrintError("CSSM_DL_FreeUniqueRecord", crtn);
- /* let's keep going in this case */
- crtn = CSSM_OK;
- }
-
- /* free resources */
- if(rtnKeyDigest) {
- *rtnKeyDigest = *keyDigest;
- }
- else {
- cuAppFree(keyDigest->Data, NULL);
- /* FIXME - don't we have to free keyDigest itself? */
- }
- return CSSM_OK;
-}
-
-static CSSM_RETURN importPrivateKey(
- CSSM_DL_DB_HANDLE dlDbHand,
- CSSM_CSP_HANDLE cspHand,
- const char *privKeyFileName,
- CSSM_ALGORITHMS keyAlg,
- CSSM_BOOL pemFormat, // of the file
- CSSM_KEYBLOB_FORMAT keyFormat, // of the key blob itself, NONE means
- // use default
- CSSM_DATA *keyHash) // OPTIONALLY RETURNED - if so, caller
- // owns and must cuAppFree()
-{
- unsigned char *derKey = NULL;
- unsigned derKeyLen;
- unsigned char *pemKey = NULL;
- unsigned pemKeyLen;
- CSSM_KEY wrappedKey;
- CSSM_KEY unwrappedKey;
- CSSM_ACCESS_CREDENTIALS creds;
- CSSM_CC_HANDLE ccHand = 0;
- CSSM_RETURN crtn;
- CSSM_DATA labelData;
- CSSM_KEYHEADER_PTR hdr = &wrappedKey.KeyHeader;
- CSSM_DATA descData = {0, NULL};
- CSSM_CSP_HANDLE rawCspHand = 0;
- const char *privKeyLabel = NULL;
-
- /*
- * Validate specified format for clarity
- */
- switch(keyAlg) {
- case CSSM_ALGID_RSA:
- switch(keyFormat) {
- case CSSM_KEYBLOB_RAW_FORMAT_NONE:
- keyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; // default
- break;
- case CSSM_KEYBLOB_RAW_FORMAT_PKCS1:
- case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
- break;
- default:
- printf("***RSA Private key must be in PKCS1 or PKCS8 "
- "format\n");
- return CSSMERR_CSSM_INTERNAL_ERROR;
- }
- privKeyLabel = "Imported RSA key";
- break;
- case CSSM_ALGID_DSA:
- switch(keyFormat) {
- case CSSM_KEYBLOB_RAW_FORMAT_NONE:
- keyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
- // default
- break;
- case CSSM_KEYBLOB_RAW_FORMAT_FIPS186:
- case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL:
- case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
- break;
- default:
- printf("***DSA Private key must be in openssl, FIPS186, "
- "or PKCS8 format\n");
- return CSSMERR_CSSM_INTERNAL_ERROR;
- }
- privKeyLabel = "Imported DSA key";
- break;
- case CSSM_ALGID_DH:
- switch(keyFormat) {
- case CSSM_KEYBLOB_RAW_FORMAT_NONE:
- keyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; // default
- break;
- case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
- break;
- default:
- printf("***Diffie-Hellman Private key must be in"
- "PKCS8 format.\n");
- return CSSMERR_CSSM_INTERNAL_ERROR;
- }
- privKeyLabel = "Imported Diffie-Hellman key";
- break;
- }
- if(readFile(privKeyFileName, &pemKey, &pemKeyLen)) {
- printf("***Error reading private key from file %s. Aborting.\n",
- privKeyFileName);
- return CSSMERR_CSSM_INTERNAL_ERROR;
- }
- /* subsequent errors to done: */
- if(pemFormat) {
- int rtn = pemDecode(pemKey, pemKeyLen, &derKey, &derKeyLen);
- if(rtn) {
- printf("***%s: Bad PEM formatting. Aborting.\n",
- privKeyFileName);
- crtn = CSSMERR_CSP_INVALID_KEY;
- goto done;
- }
- }
- else {
- derKey = pemKey;
- derKeyLen = pemKeyLen;
- }
-
- /* importing a raw key into the CSPDL involves a NULL unwrap */
- memset(&unwrappedKey, 0, sizeof(CSSM_KEY));
- memset(&wrappedKey, 0, sizeof(CSSM_KEY));
-
- /* set up the imported key to look like a CSSM_KEY */
- hdr->HeaderVersion = CSSM_KEYHEADER_VERSION;
- hdr->BlobType = CSSM_KEYBLOB_RAW;
- hdr->AlgorithmId = keyAlg;
- hdr->KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
- hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
- hdr->KeyUsage = CSSM_KEYUSE_ANY;
- hdr->Format = keyFormat;
- wrappedKey.KeyData.Data = derKey;
- wrappedKey.KeyData.Length = derKeyLen;
-
- /* get key size in bits from raw CSP */
- rawCspHand = cuCspStartup(CSSM_TRUE);
- if(rawCspHand == 0) {
- printf("***Error attaching to CSP. Aborting.\n");
- crtn = CSSMERR_CSSM_INTERNAL_ERROR;
- goto done;
- }
- CSSM_KEY_SIZE keySize;
- crtn = CSSM_QueryKeySizeInBits(rawCspHand, CSSM_INVALID_HANDLE, &wrappedKey, &keySize);
- if(crtn) {
- cuPrintError("CSSM_QueryKeySizeInBits",crtn);
- goto done;
- }
- hdr->LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
-
- memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
- crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
- CSSM_ALGID_NONE, // unwrapAlg
- CSSM_ALGMODE_NONE, // unwrapMode
- &creds,
- NULL, // unwrappingKey
- NULL, // initVector
- CSSM_PADDING_NONE, // unwrapPad
- 0, // Params
- &ccHand);
- if(crtn) {
- cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn);
- goto done;
- }
-
- /* add DL/DB to context */
- CSSM_CONTEXT_ATTRIBUTE newAttr;
- newAttr.AttributeType = CSSM_ATTRIBUTE_DL_DB_HANDLE;
- newAttr.AttributeLength = sizeof(CSSM_DL_DB_HANDLE);
- newAttr.Attribute.Data = (CSSM_DATA_PTR)&dlDbHand;
- crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr);
- if(crtn) {
- cuPrintError("CSSM_UpdateContextAttributes", crtn);
- goto done;
- }
-
- /* do the NULL unwrap */
- labelData.Data = (uint8 *)privKeyLabel;
- labelData.Length = strlen(privKeyLabel) + 1;
- crtn = CSSM_UnwrapKey(ccHand,
- NULL, // PublicKey
- &wrappedKey,
- CSSM_KEYUSE_ANY,
- CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT |
- CSSM_KEYATTR_SENSITIVE |CSSM_KEYATTR_EXTRACTABLE,
- &labelData,
- NULL, // CredAndAclEntry
- &unwrappedKey,
- &descData); // required
- if(crtn != CSSM_OK) {
- cuPrintError("CSSM_UnwrapKey", crtn);
- goto done;
- }
-
- /* one more thing: bind this private key to its public key */
- crtn = setPubKeyHash(cspHand, dlDbHand, privKeyLabel, keyHash);
-
- /* We don't need the unwrapped key any more */
- CSSM_FreeKey(cspHand,
- NULL, // access cred
- &unwrappedKey,
- CSSM_FALSE); // delete
-
-done:
- if(ccHand) {
- CSSM_DeleteContext(ccHand);
- }
- if(derKey) {
- free(derKey); // mallocd by readFile() */
- }
- if(pemFormat && pemKey) {
- free(pemKey);
- }
- if(rawCspHand) {
- CSSM_ModuleDetach(rawCspHand);
- }
- return crtn;
-}
-
-
-CSSM_RETURN importBadCert(
- CSSM_DL_HANDLE dlHand,
- const char *dbFileName,
- const char *certFile,
- const char *keyFile,
- CSSM_ALGORITHMS keyAlg,
- CSSM_BOOL pemFormat, // of the file
- CSSM_KEYBLOB_FORMAT keyFormat, // of the key blob itself, NONE means
- // use default
- CSSM_BOOL verbose)
-{
- CSSM_DL_DB_HANDLE dlDbHand = {dlHand, 0};
- CSSM_RETURN crtn;
- CSSM_DATA keyDigest = {0, NULL};
- CSSM_DATA certData = {0, NULL};
- unsigned len;
-
- CSSM_CSP_HANDLE cspHand = cuCspStartup(CSSM_FALSE);
- if(cspHand == 0) {
- printf("***Error attaching to CSPDL. Aborting.\n");
- return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
- }
-
- /*
- * 1. Open the (already existing) DB.
- */
- dlDbHand.DBHandle = cuDbStartupByName(dlHand,
- (char *)dbFileName, // bogus non-const prototype
- CSSM_FALSE, // do NOT create it
- CSSM_FALSE); // quiet
- if(dlDbHand.DBHandle == 0) {
- printf("Error opening %s. Aborting.\n", dbFileName);
- return CSSMERR_DL_DATASTORE_DOESNOT_EXIST;
- }
-
- /*
- * Import key to DB, snagging its key digest along the way.
- */
- crtn = importPrivateKey(dlDbHand, cspHand,
- keyFile, keyAlg, pemFormat, keyFormat,
- &keyDigest);
- if(crtn) {
- printf("***Error importing key %s. Aborting.\n", keyFile);
- goto errOut;
- }
-
- /*
- * Now the cert.
- */
- if(readFile(certFile, &certData.Data, &len)) {
- printf("***Error reading cert from %s. Aborting.\n", certFile);
- goto errOut;
- }
- certData.Length = len;
- crtn = cuAddCertToDb(dlDbHand, &certData,
- CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
- certFile, // printName
- &keyDigest);
- if(crtn == CSSMERR_DL_INVALID_RECORDTYPE) {
- /* virgin DB, no cert schema: add schema and retry */
- crtn = tpAddCertSchema(dlDbHand);
- if(crtn == CSSM_OK) {
- crtn = cuAddCertToDb(dlDbHand, &certData,
- CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
- certFile, // printName
- &keyDigest);
- }
- }
- if(crtn) {
- printf("***Error importing cert %s. Aborting.\n", certFile);
- }
-errOut:
- if(keyDigest.Data) {
- cuAppFree(keyDigest.Data, NULL);
- }
- if(dlDbHand.DBHandle) {
- CSSM_DL_DbClose(dlDbHand);
- }
- if(certData.Data) {
- free(certData.Data);
- }
- return crtn;
-}