--- /dev/null
+/*
+ * Copyright (c) 2000-2004,2011-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@
+ */
+
+
+//
+// transition - transition layer for CSSM API/SPI calls.
+//
+// This file defines all functions that connect the CSSM API (CSSM_*)
+// to a plugin's SPI (CSSM_SPI_*) functions. The bulk of these functions
+// is automatically generated by the Perl script transition.pl (thanks, Larry!)
+// from the cssm*.h official header files, under control of the configuration
+// file transition.cfg. Those that need special magic are marked "custom" in
+// transition.cfg and are defined here.
+//
+// @@@ Reconsider CSP locking for context operations
+//
+#include "cssmint.h"
+#include "attachfactory.h"
+#include "manager.h"
+#include "cssmcontext.h"
+#include <Security/cssmcspi.h>
+#include <Security/cssmdli.h>
+#include <Security/cssmcli.h>
+#include <Security/cssmaci.h>
+#include <Security/cssmtpi.h>
+#include <Security/cssmkrapi.h>
+#include <Security/cssmkrspi.h>
+#include <security_cdsa_utilities/cssmbridge.h>
+
+
+//
+// Names for the standard Attachment types
+//
+typedef StandardAttachment<CSSM_SERVICE_CSP, CSSM_SPI_CSP_FUNCS> CSPAttachment;
+typedef StandardAttachment<CSSM_SERVICE_DL, CSSM_SPI_DL_FUNCS> DLAttachment;
+typedef StandardAttachment<CSSM_SERVICE_CL, CSSM_SPI_CL_FUNCS> CLAttachment;
+typedef StandardAttachment<CSSM_SERVICE_AC, CSSM_SPI_AC_FUNCS> ACAttachment;
+typedef StandardAttachment<CSSM_SERVICE_TP, CSSM_SPI_TP_FUNCS> TPAttachment;
+
+
+//
+// A conditional locking class for always-right(TM) lock management.
+//
+class TransitLock {
+public:
+ Attachment &attachment;
+
+ TransitLock(Attachment &att) : attachment(att)
+ {
+ attachment.module.safeLock();
+ }
+
+ ~TransitLock()
+ {
+ attachment.module.safeUnlock();
+ attachment.exit();
+ }
+};
+
+
+//
+// Context management functions
+//
+CSSM_RETURN CSSMAPI
+CSSM_CSP_CreateSignatureContext (CSSM_CSP_HANDLE CSPHandle,
+ CSSM_ALGORITHMS AlgorithmID,
+ const CSSM_ACCESS_CREDENTIALS *AccessCred,
+ const CSSM_KEY *Key,
+ CSSM_CC_HANDLE *NewContextHandle)
+{
+ BEGIN_API
+ HandleContext::Maker maker(CSPHandle);
+ maker.setup(AccessCred);
+ maker.setup(Key, CSSMERR_CSP_MISSING_ATTR_KEY);
+ maker.make();
+ maker.put(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS, AccessCred);
+ maker.put(CSSM_ATTRIBUTE_KEY, Key);
+ Required(NewContextHandle) = maker(CSSM_ALGCLASS_SIGNATURE, AlgorithmID);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_CSP_CreateSymmetricContext (CSSM_CSP_HANDLE CSPHandle,
+ CSSM_ALGORITHMS AlgorithmID,
+ CSSM_ENCRYPT_MODE Mode,
+ const CSSM_ACCESS_CREDENTIALS *AccessCred,
+ const CSSM_KEY *Key,
+ const CSSM_DATA *InitVector,
+ CSSM_PADDING Padding,
+ void *Reserved,
+ CSSM_CC_HANDLE *NewContextHandle)
+{
+ BEGIN_API
+ if (Reserved != NULL)
+ CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
+ HandleContext::Maker maker(CSPHandle);
+ maker.setup(Mode);
+ maker.setup(AccessCred);
+ maker.setup(Key);
+ maker.setup(InitVector);
+ maker.setup(Padding);
+ maker.make();
+ maker.put(CSSM_ATTRIBUTE_MODE, Mode);
+ maker.put(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS, AccessCred);
+ maker.put(CSSM_ATTRIBUTE_KEY, Key);
+ maker.put(CSSM_ATTRIBUTE_INIT_VECTOR, InitVector);
+ maker.put(CSSM_ATTRIBUTE_PADDING, Padding);
+ Required(NewContextHandle) = maker(CSSM_ALGCLASS_SYMMETRIC, AlgorithmID);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_CSP_CreateDigestContext (CSSM_CSP_HANDLE CSPHandle,
+ CSSM_ALGORITHMS AlgorithmID,
+ CSSM_CC_HANDLE *NewContextHandle)
+{
+ BEGIN_API
+ HandleContext::Maker maker(CSPHandle);
+ maker.make();
+ Required(NewContextHandle) = maker(CSSM_ALGCLASS_DIGEST, AlgorithmID);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_CSP_CreateMacContext (CSSM_CSP_HANDLE CSPHandle,
+ CSSM_ALGORITHMS AlgorithmID,
+ const CSSM_KEY *Key,
+ CSSM_CC_HANDLE *NewContextHandle)
+{
+ BEGIN_API
+ HandleContext::Maker maker(CSPHandle);
+ maker.setup(Key, CSSMERR_CSP_MISSING_ATTR_KEY);
+ maker.make();
+ maker.put(CSSM_ATTRIBUTE_KEY, Key);
+ Required(NewContextHandle) = maker(CSSM_ALGCLASS_MAC, AlgorithmID);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_CSP_CreateRandomGenContext (CSSM_CSP_HANDLE CSPHandle,
+ CSSM_ALGORITHMS AlgorithmID,
+ const CSSM_CRYPTO_DATA *Seed,
+ CSSM_SIZE Length,
+ CSSM_CC_HANDLE *NewContextHandle)
+{
+ BEGIN_API
+ HandleContext::Maker maker(CSPHandle);
+ maker.setup(Seed);
+ maker.setup(Length, CSSMERR_CSP_INVALID_ATTR_OUTPUT_SIZE);
+ maker.make();
+ maker.put(CSSM_ATTRIBUTE_SEED, Seed);
+ maker.put(CSSM_ATTRIBUTE_OUTPUT_SIZE, (uint32_t)Length);
+ Required(NewContextHandle) = maker(CSSM_ALGCLASS_RANDOMGEN, AlgorithmID);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_CSP_CreateAsymmetricContext (CSSM_CSP_HANDLE CSPHandle,
+ CSSM_ALGORITHMS AlgorithmID,
+ const CSSM_ACCESS_CREDENTIALS *AccessCred,
+ const CSSM_KEY *Key,
+ CSSM_PADDING Padding,
+ CSSM_CC_HANDLE *NewContextHandle)
+{
+ BEGIN_API
+ HandleContext::Maker maker(CSPHandle);
+ maker.setup(AccessCred, CSSMERR_CSP_MISSING_ATTR_ACCESS_CREDENTIALS);
+ maker.setup(Key, CSSMERR_CSP_MISSING_ATTR_KEY);
+ maker.setup(Padding);
+ maker.make();
+ maker.put(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS, AccessCred);
+ maker.put(CSSM_ATTRIBUTE_KEY, Key);
+ maker.put(CSSM_ATTRIBUTE_PADDING, Padding);
+ Required(NewContextHandle) = maker(CSSM_ALGCLASS_ASYMMETRIC, AlgorithmID);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_CSP_CreateDeriveKeyContext (CSSM_CSP_HANDLE CSPHandle,
+ CSSM_ALGORITHMS AlgorithmID,
+ CSSM_KEY_TYPE DeriveKeyType,
+ uint32 DeriveKeyLengthInBits,
+ const CSSM_ACCESS_CREDENTIALS *AccessCred,
+ const CSSM_KEY *BaseKey,
+ uint32 IterationCount,
+ const CSSM_DATA *Salt,
+ const CSSM_CRYPTO_DATA *Seed,
+ CSSM_CC_HANDLE *NewContextHandle)
+{
+ BEGIN_API
+ HandleContext::Maker maker(CSPHandle);
+ maker.setup(DeriveKeyType, CSSMERR_CSP_INVALID_ATTR_KEY_TYPE);
+ maker.setup(DeriveKeyLengthInBits, CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
+ maker.setup(AccessCred);
+ maker.setup(BaseKey);
+ maker.setup(IterationCount);
+ maker.setup(Salt);
+ maker.setup(Seed);
+ maker.make();
+ maker.put(CSSM_ATTRIBUTE_KEY_TYPE, DeriveKeyType);
+ maker.put(CSSM_ATTRIBUTE_KEY_LENGTH, DeriveKeyLengthInBits);
+ maker.put(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS, AccessCred);
+ maker.put(CSSM_ATTRIBUTE_KEY, BaseKey);
+ maker.put(CSSM_ATTRIBUTE_ITERATION_COUNT, IterationCount);
+ maker.put(CSSM_ATTRIBUTE_SALT, Salt);
+ maker.put(CSSM_ATTRIBUTE_SEED, Seed);
+ Required(NewContextHandle) = maker(CSSM_ALGCLASS_DERIVEKEY, AlgorithmID);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_CSP_CreateKeyGenContext (CSSM_CSP_HANDLE CSPHandle,
+ CSSM_ALGORITHMS AlgorithmID,
+ uint32 KeySizeInBits,
+ const CSSM_CRYPTO_DATA *Seed,
+ const CSSM_DATA *Salt,
+ const CSSM_DATE *StartDate,
+ const CSSM_DATE *EndDate,
+ const CSSM_DATA *Params,
+ CSSM_CC_HANDLE *NewContextHandle)
+{
+ BEGIN_API
+ HandleContext::Maker maker(CSPHandle);
+ maker.setup(KeySizeInBits, CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
+ maker.setup(Seed);
+ maker.setup(Salt);
+ maker.setup(StartDate);
+ maker.setup(EndDate);
+ maker.setup(Params);
+ maker.make();
+ maker.put(CSSM_ATTRIBUTE_KEY_LENGTH, KeySizeInBits);
+ maker.put(CSSM_ATTRIBUTE_SEED, Seed);
+ maker.put(CSSM_ATTRIBUTE_SALT, Salt);
+ maker.put(CSSM_ATTRIBUTE_START_DATE, StartDate);
+ maker.put(CSSM_ATTRIBUTE_END_DATE, EndDate);
+ maker.put(CSSM_ATTRIBUTE_ALG_PARAMS, Params);
+ Required(NewContextHandle) = maker(CSSM_ALGCLASS_KEYGEN, AlgorithmID);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_CSP_CreatePassThroughContext (CSSM_CSP_HANDLE CSPHandle,
+ const CSSM_KEY *Key,
+ CSSM_CC_HANDLE *NewContextHandle)
+{
+ BEGIN_API
+ HandleContext::Maker maker(CSPHandle);
+ maker.setup(Key, CSSMERR_CSP_MISSING_ATTR_KEY);
+ maker.make();
+ maker.put(CSSM_ATTRIBUTE_KEY, Key);
+ Required(NewContextHandle) = maker(CSSM_ALGCLASS_NONE, CSSM_ALGID_NONE);
+ END_API(CSSM)
+}
+
+
+//
+// CSSM_GetContext makes a deep copy of a CSP context and hands it to the
+// caller. The result is NOT a HandleContext, but a bare Context that is
+// in no dictionaries etc. User must delete it by calling CSSM_FreeContext.
+//
+CSSM_RETURN CSSMAPI
+CSSM_GetContext (CSSM_CC_HANDLE CCHandle,
+ CSSM_CONTEXT_PTR *ContextP)
+{
+ BEGIN_API
+#warning Cast from CSSM_CC_HANDLE to CSSM_HANDLE
+ HandleContext &context = HandleObject::find<HandleContext>((CSSM_HANDLE)CCHandle, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE);
+ Context *newContext = new(context.attachment) Context(context.type(), context.algorithm());
+ try {
+ newContext->CSPHandle = context.attachment.handle();
+ newContext->copyFrom(context, context.attachment);
+ Required(ContextP) = newContext;
+ } catch (...) {
+ context.attachment.free(newContext);
+ throw;
+ }
+ END_API(CSSM)
+}
+
+
+//
+// Since we allocated all the data in one fell heap, our FreeContext
+// function is disappointingly simple.
+//
+CSSM_RETURN CSSMAPI
+CSSM_FreeContext (CSSM_CONTEXT_PTR ContextP)
+{
+ BEGIN_API
+ Context *context = &Context::required(ContextP);
+ context->destroy(context, HandleObject::find<CSPAttachment>(context->CSPHandle, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE));
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_SetContext (CSSM_CC_HANDLE CCHandle,
+ const CSSM_CONTEXT *ContextP)
+{
+ BEGIN_API
+ const Context &source = Context::required(ContextP);
+#warning Cast from CSSM_CC_HANDLE to CSSM_HANDLE
+ HandleContext &context = HandleObject::find<HandleContext>((CSSM_HANDLE)CCHandle, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE);
+
+ CSSM_CONTEXT_ATTRIBUTE *oldAttributes = context.ContextAttributes;
+ uint32 oldCount = context.NumberOfAttributes;
+ CSSM_CONTEXT_TYPE oldType = context.ContextType;
+ CSSM_ALGORITHMS oldAlgorithm = context.AlgorithmType;
+
+ context.copyFrom(source, context.attachment);
+ context.ContextType = source.ContextType;
+ context.AlgorithmType = source.AlgorithmType;
+
+ if (CSSM_RETURN err = context.validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
+ context.attachment.free(context.ContextAttributes); // free rejected attribute blob
+ context.ContextAttributes = oldAttributes; // restore...
+ context.NumberOfAttributes = oldCount; // ... old
+ context.ContextType = oldType; // ... values
+ context.AlgorithmType = oldAlgorithm; // ... in context
+ CssmError::throwMe(err); // tell the caller it failed
+ }
+
+ context.attachment.free(oldAttributes);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_DeleteContext (CSSM_CC_HANDLE CCHandle)
+{
+ BEGIN_API
+ HandleContext &context = enterContext(CCHandle);
+ StLock<CountingMutex, &CountingMutex::enter, &CountingMutex::exit>
+ _(context.attachment, true);
+
+ // ignore error return from CSP event notify (can't decline deletion)
+ context.validateChange(CSSM_CONTEXT_EVENT_DELETE);
+
+ context.destroy(&context, context.attachment);
+ END_API(CSSM)
+}
+
+
+//
+// The GetContextAttribute API is fatally flawed. The standard implies a deep
+// copy of the attribute value, but no release function exists. Instead, we
+// return a shallow copy (sharing structure) which you need not release, but
+// which becomes invalid when the source Context is destroyed.
+//
+CSSM_RETURN CSSMAPI
+CSSM_GetContextAttribute (const CSSM_CONTEXT *Context,
+ uint32 AttributeType,
+ CSSM_CONTEXT_ATTRIBUTE_PTR *ContextAttribute)
+{
+ BEGIN_API
+ CSSM_ATTRIBUTE_TYPE type = CSSM_ATTRIBUTE_TYPE(AttributeType); // CDSA defect
+ Required(ContextAttribute) = Context::required(Context).find(type);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_UpdateContextAttributes (CSSM_CC_HANDLE CCHandle,
+ uint32 NumberAttributes,
+ const CSSM_CONTEXT_ATTRIBUTE *ContextAttributes)
+{
+ BEGIN_API
+#warning Cast from CSSM_CC_HANDLE to CSSM_HANDLE
+ HandleContext &context = HandleObject::find<HandleContext>((CSSM_HANDLE)CCHandle, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE);
+ context.mergeAttributes(ContextAttributes, NumberAttributes);
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_DeleteContextAttributes (CSSM_CC_HANDLE CCHandle,
+ uint32 NumberOfAttributes,
+ const CSSM_CONTEXT_ATTRIBUTE *ContextAttributes)
+{
+ BEGIN_API
+ if (NumberOfAttributes == 0)
+ return CSSM_OK; // I suppose
+ Required(ContextAttributes); // preflight
+#warning Cast from CSSM_CC_HANDLE to CSSM_HANDLE
+ HandleContext &context = HandleObject::find<HandleContext>((CSSM_HANDLE)CCHandle, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE);
+ for (uint32 n = 0; n < NumberOfAttributes; n++)
+ context.deleteAttribute(ContextAttributes[n].AttributeType);
+ END_API(CSSM)
+}
+
+
+//
+// Miscellaneous odds and ends - these functions just need a wee bit of
+// manual massaging to fit.
+//
+CSSM_RETURN CSSMAPI
+CSSM_DigestDataClone (CSSM_CC_HANDLE ccHandle,
+ CSSM_CC_HANDLE *newCCHandle)
+{
+ BEGIN_API
+#warning Cast from CSSM_CC_HANDLE to CSSM_HANDLE
+ HandleContext &context = HandleObject::findAndLock<HandleContext>((CSSM_HANDLE)ccHandle, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE);
+ TransitLock _(context.attachment);
+ HandleContext *newContext =
+ new(context.attachment) HandleContext(context.attachment, context.type(), context.algorithm());
+ try {
+ newContext->CSPHandle = context.attachment.handle();
+ newContext->copyFrom(context, context.attachment);
+ context.attachment.downcalls.DigestDataClone(context.attachment.handle(), ccHandle, newContext->handle());
+ Required(newCCHandle) = newContext->handle();
+ } catch (...) {
+ newContext->destroy(newContext, context.attachment);
+ throw;
+ }
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_QueryKeySizeInBits (CSSM_CSP_HANDLE CSPHandle,
+ CSSM_CC_HANDLE ccHandle,
+ const CSSM_KEY *key,
+ CSSM_KEY_SIZE_PTR keySize)
+{
+ //@@@ could afford not to lock attachment in have-CC case
+ BEGIN_API
+ Required(keySize);
+ Context *context;
+ CSPAttachment *attachment;
+ if (ccHandle == (CSSM_CC_HANDLE) HandleObject::invalidHandle) {
+ // key specified by CSPHandle and Key
+ attachment = &enterAttachment<CSPAttachment>(CSPHandle);
+ context = NULL;
+ } else {
+ // key specified by ccHandle
+ HandleContext *ctx = &enterContext(ccHandle);
+ try {
+ attachment = &ctx->attachment;
+ context = ctx;
+ CSPHandle = context->CSPHandle;
+ key = &context->get<CssmKey>(CSSM_ATTRIBUTE_KEY,
+ CSSMERR_CSP_INVALID_KEY);
+ } catch (...) {
+ attachment->exit();
+ throw;
+ }
+ }
+ TransitLock _(*attachment);
+ CSSM_RETURN result = attachment->downcalls.QueryKeySizeInBits(CSPHandle,
+ ccHandle, context, key, keySize);
+ return result;
+ END_API(CSSM)
+}
+
+
+CSSM_RETURN CSSMAPI
+CSSM_GenerateAlgorithmParams (CSSM_CC_HANDLE CCHandle,
+ uint32 ParamBits,
+ CSSM_DATA_PTR Param)
+{
+ BEGIN_API
+ // this function has more subtle locking than usual. Pay attention:
+
+ // (1) Resolve context and ensure attachment exit
+ HandleContext &context = enterContext(CCHandle);
+ StLock<CountingMutex, &CountingMutex::enter, &CountingMutex::exit> _(context.attachment, true);
+
+ // (2) Call CSP, acquiring module safe-lock for a moment (only)
+ CSSM_CONTEXT_ATTRIBUTE_PTR attributes;
+ uint32 count;
+ {
+ StLock<Module, &Module::safeLock, &Module::safeUnlock> _(context.attachment.module);
+ if (CSSM_RETURN err =
+ context.attachment.downcalls.GenerateAlgorithmParams(context.attachment.handle(),
+ CCHandle, &context,
+ ParamBits, Param,
+ &count, &attributes))
+ CssmError::throwMe(err);
+ }
+
+ // (3) Merge the attributes returned into the context, which will (again) acquire the module safe-lock internally
+ if (count)
+ context.mergeAttributes(attributes, count);
+ // the memory at (attributes, count) belongs to the CSP; don't free it here
+ END_API(CSSM)
+}
+
+
+//
+// Include the auto-generated functions
+//
+#include <derived_src/transition.gen>