--- /dev/null
+/*
+ * Copyright (c) 2000-2001,2011-2012,2014 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.
+ */
+
+
+//
+// CSPsession.h - Framework for CSP plugin modules
+//
+#ifndef _H_CSPSESSION
+#define _H_CSPSESSION
+
+#include <security_cdsa_plugin/CSPabstractsession.h>
+#include <map>
+
+
+namespace Security {
+
+//
+// The CSPPluginSession provides a general bed for CSP plugin session objects.
+// Derive from this if you want to write your CSP, effectively, from scratch.
+// We still provide a framework for managing local cryptographic contexts and
+// (module) logins.
+//
+class CSPPluginSession : public PluginSession, public CSPAbstractPluginSession {
+public:
+ CSPPluginSession(CSSM_MODULE_HANDLE theHandle,
+ CssmPlugin &plug,
+ const CSSM_VERSION &version,
+ uint32 subserviceId,
+ CSSM_SERVICE_TYPE subserviceType,
+ CSSM_ATTACH_FLAGS attachFlags,
+ const CSSM_UPCALLS &upcalls)
+ : PluginSession(theHandle, plug, version, subserviceId, subserviceType, attachFlags, upcalls) { }
+
+ // methods implemented here that you should not override in a subclass
+ void EventNotify(CSSM_CONTEXT_EVENT e,
+ CSSM_CC_HANDLE ccHandle, const Context &context);
+ CSSM_MODULE_FUNCS_PTR construct();
+
+public:
+ class PluginContext {
+ public:
+ virtual bool changed(const Context &context);
+ virtual ~PluginContext();
+ };
+
+public:
+ bool loggedIn() const { return mLoggedIn; }
+ bool loggedIn(bool li) { bool old = mLoggedIn; mLoggedIn = li; return old; }
+
+ template <class Ctx> Ctx *getContext(CSSM_CC_HANDLE handle)
+ { StLock<Mutex> _(contextMapLock); return safe_cast<Ctx *>(contextMap[handle]); }
+
+ void setContext(CSSM_CC_HANDLE handle, PluginContext *ctx)
+ { StLock<Mutex> _(contextMapLock); contextMap[handle] = ctx; }
+
+public:
+ // context management methods - override as needed
+ virtual PluginContext *contextCreate(CSSM_CC_HANDLE handle, const Context &context);
+ virtual void contextUpdate(CSSM_CC_HANDLE handle,
+ const Context &context, PluginContext * &ctx);
+ virtual void contextDelete(CSSM_CC_HANDLE handle, const Context &context, PluginContext *ctx);
+
+private:
+ bool mLoggedIn;
+
+ map<CSSM_CC_HANDLE, PluginContext *> contextMap;
+ Mutex contextMapLock;
+};
+
+
+//
+// On the other hand, for most CSP modules, this subclass of CSPPluginSession provides
+// much more convenient embedding facilities. The theory of operation is too complicated
+// to explain here; refer to the accompanying documentation.
+//
+class CSPFullPluginSession : public CSPPluginSession {
+public:
+ class CSPContext;
+ class AlgorithmFactory;
+
+ CSPFullPluginSession(CSSM_MODULE_HANDLE theHandle,
+ CssmPlugin &plug,
+ const CSSM_VERSION &version,
+ uint32 subserviceId,
+ CSSM_SERVICE_TYPE subserviceType,
+ CSSM_ATTACH_FLAGS attachFlags,
+ const CSSM_UPCALLS &upcalls)
+ : CSPPluginSession(theHandle, plug, version,
+ subserviceId, subserviceType, attachFlags, upcalls) { }
+
+ // final context preparation (called by secondary transition layer)
+ CSPContext *init(CSSM_CC_HANDLE ccHandle, CSSM_CONTEXT_TYPE type,
+ const Context &context, bool encoding = true);
+
+ // verify proper state on continuation (update/final) calls
+ CSPContext *getStagedContext(CSSM_CC_HANDLE ccHandle,
+ CSSM_CONTEXT_TYPE type, bool encoding = true);
+
+ static const uint32 CSSM_ALGCLASS_CRYPT = 1001; // internally added to CONTEXT_TYPE
+
+protected:
+ // validate operation type against context class
+ void checkOperation(CSSM_CONTEXT_TYPE ctxType, CSSM_CONTEXT_TYPE opType);
+
+protected:
+ //
+ // The Writer class encapsulates staged-output destinations with optional overflow
+ //
+ class Writer {
+ public:
+ Writer(CssmData *v, uint32 n, CssmData *rem = NULL);
+
+ // can this buffer be extended?
+ bool isExtensible() const
+ { return !*vec || (remData && !*remData); }
+
+ // increase size if necessary (and possible)
+ void allocate(size_t needed, Allocator &alloc);
+
+ // straight-forward buffer writing
+ void put(void *addr, size_t size);
+
+ // locate-mode output (deliver buffer mode)
+ void nextBlock(void * &p, size_t &sz);
+ void use(size_t sz);
+
+ // wrap up and return total number of bytes written
+ size_t close();
+
+ private:
+ CssmData *vec; // current buffer descriptor (the one in use)
+ CssmData *firstVec; // first buffer descriptor
+ CssmData *lastVec; // last buffer descriptor (NOT one past it)
+ CssmData *remData; // overflow buffer, if any
+
+ void *currentBuffer; // next free byte in vec
+ size_t currentSize; // free bytes in vec
+
+ size_t written; // bytes written
+
+ void useData(CssmData *data)
+ { currentBuffer = data->data(); currentSize = data->length(); }
+ };
+
+public:
+ // internal utilities (used by our own subclasses)
+ static CssmData makeBuffer(size_t size, Allocator &alloc);
+ static size_t totalBufferSize(const CssmData *data, uint32 count);
+ void setKey(CssmKey &key,
+ const Context &context, CSSM_KEYCLASS keyClass,
+ CSSM_KEYATTR_FLAGS attrs, CSSM_KEYUSE use);
+
+public:
+ //
+ // All contexts from CSPFullPluginSession's subclasses must derive from CSPContext.
+ // CSPFullPluginSession reformulates CSSM operations in terms of virtual methods of
+ // the context class.
+ //
+ class CSPContext : public PluginContext {
+ friend class CSPFullPluginSession;
+ public:
+ CSSM_CONTEXT_TYPE type() const { return mType; }
+ bool encoding() const { return mDirection; }
+
+ // init() is called for all algorithms
+ virtual void init(const Context &context, bool encoding = true);
+
+ // the following methods will be called for some but not all algorithms
+ virtual void update(const CssmData &data); // all block-input algorithms
+ virtual void update(void *inp, size_t &inSize, void *outp, size_t &outSize); // cryption algs
+ virtual void final(CssmData &out); // output-data producing algorithms
+ virtual void final(const CssmData &in); // verifying algorithms
+ virtual void generate(const Context &context, CssmKey &pubKey, CssmKey &privKey);
+ virtual void generate(const Context &context, uint32,
+ CssmData ¶ms, uint32 &attrCount, Context::Attr * &attrs);
+ virtual CSPContext *clone(Allocator &); // clone internal state
+ virtual void setDigestAlgorithm(CSSM_ALGORITHMS digestAlg);
+
+ virtual size_t inputSize(size_t outSize); // input for given output size
+ virtual size_t outputSize(bool final = false, size_t inSize = 0); // output for given input size
+ virtual void minimumProgress(size_t &in, size_t &out); // minimum progress chunks
+
+ protected:
+ // convenience forms of the above
+ void update(const CssmData *in, uint32 inCount, Writer &writer);
+ void final(CssmData &out, Allocator &alloc);
+ void final(Writer &writer, Allocator &alloc);
+
+ void update(const CssmData *in, uint32 inCount)
+ { for (uint32 n = 0; n < inCount; n++) update(in[n]); }
+
+ void checkOperation(CSSM_CONTEXT_TYPE type);
+ void checkOperation(CSSM_CONTEXT_TYPE type, bool encode);
+
+ CSSM_CONTEXT_TYPE mType; // CSSM context type
+ bool mDirection; // operation direction (true if irrelevant)
+ };
+
+protected:
+ virtual void setupContext(CSPContext * &ctx, const Context &context, bool encoding) = 0;
+
+ virtual void getKeySize(const CssmKey &key, CSSM_KEY_SIZE &size);
+
+public:
+ // an algorithm factory. This is an optional feature
+ class AlgorithmFactory {
+ public:
+ virtual ~AlgorithmFactory();
+
+ // set ctx and return true if you can handle this
+ virtual bool setup(CSPContext * &ctx, const Context &context) = 0;
+ };
+
+public:
+ void EncryptData(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ const CssmData ClearBufs[],
+ uint32 ClearBufCount,
+ CssmData CipherBufs[],
+ uint32 CipherBufCount,
+ CSSM_SIZE &bytesEncrypted,
+ CssmData &RemData,
+ CSSM_PRIVILEGE Privilege);
+ void EncryptDataInit(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ CSSM_PRIVILEGE Privilege);
+ void EncryptDataUpdate(CSSM_CC_HANDLE CCHandle,
+ const CssmData ClearBufs[],
+ uint32 ClearBufCount,
+ CssmData CipherBufs[],
+ uint32 CipherBufCount,
+ CSSM_SIZE &bytesEncrypted);
+ void EncryptDataFinal(CSSM_CC_HANDLE CCHandle,
+ CssmData &RemData);
+
+ void DecryptData(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ const CssmData CipherBufs[],
+ uint32 CipherBufCount,
+ CssmData ClearBufs[],
+ uint32 ClearBufCount,
+ CSSM_SIZE &bytesDecrypted,
+ CssmData &RemData,
+ CSSM_PRIVILEGE Privilege);
+ void DecryptDataInit(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ CSSM_PRIVILEGE Privilege);
+ void DecryptDataUpdate(CSSM_CC_HANDLE CCHandle,
+ const CssmData CipherBufs[],
+ uint32 CipherBufCount,
+ CssmData ClearBufs[],
+ uint32 ClearBufCount,
+ CSSM_SIZE &bytesDecrypted);
+ void DecryptDataFinal(CSSM_CC_HANDLE CCHandle,
+ CssmData &RemData);
+
+ void QuerySize(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ CSSM_BOOL Encrypt,
+ uint32 QuerySizeCount,
+ QuerySizeData *DataBlock);
+
+ void WrapKey(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ const AccessCredentials &AccessCred,
+ const CssmKey &Key,
+ const CssmData *DescriptiveData,
+ CssmKey &WrappedKey,
+ CSSM_PRIVILEGE Privilege);
+ void UnwrapKey(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ const CssmKey *PublicKey,
+ const CssmKey &WrappedKey,
+ uint32 KeyUsage,
+ uint32 KeyAttr,
+ const CssmData *KeyLabel,
+ const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
+ CssmKey &UnwrappedKey,
+ CssmData &DescriptiveData,
+ CSSM_PRIVILEGE Privilege);
+ void DeriveKey(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ CssmData &Param,
+ uint32 KeyUsage,
+ uint32 KeyAttr,
+ const CssmData *KeyLabel,
+ const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
+ CssmKey &DerivedKey);
+
+ void GenerateMac(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ const CssmData DataBufs[],
+ uint32 DataBufCount,
+ CssmData &Mac);
+ void GenerateMacInit(CSSM_CC_HANDLE CCHandle,
+ const Context &Context);
+ void GenerateMacUpdate(CSSM_CC_HANDLE CCHandle,
+ const CssmData DataBufs[],
+ uint32 DataBufCount);
+ void GenerateMacFinal(CSSM_CC_HANDLE CCHandle,
+ CssmData &Mac);
+
+ void VerifyMac(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ const CssmData DataBufs[],
+ uint32 DataBufCount,
+ const CssmData &Mac);
+ virtual void VerifyMacInit(CSSM_CC_HANDLE CCHandle,
+ const Context &Context);
+ virtual void VerifyMacUpdate(CSSM_CC_HANDLE CCHandle,
+ const CssmData DataBufs[],
+ uint32 DataBufCount);
+ virtual void VerifyMacFinal(CSSM_CC_HANDLE CCHandle,
+ const CssmData &Mac);
+
+ void SignData(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ const CssmData DataBufs[],
+ uint32 DataBufCount,
+ CSSM_ALGORITHMS DigestAlgorithm,
+ CssmData &Signature);
+ void SignDataInit(CSSM_CC_HANDLE CCHandle,
+ const Context &Context);
+ void SignDataUpdate(CSSM_CC_HANDLE CCHandle,
+ const CssmData DataBufs[],
+ uint32 DataBufCount);
+ void SignDataFinal(CSSM_CC_HANDLE CCHandle,
+ CssmData &Signature);
+
+ void VerifyData(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ const CssmData DataBufs[],
+ uint32 DataBufCount,
+ CSSM_ALGORITHMS DigestAlgorithm,
+ const CssmData &Signature);
+ virtual void VerifyDataInit(CSSM_CC_HANDLE CCHandle,
+ const Context &Context);
+ virtual void VerifyDataUpdate(CSSM_CC_HANDLE CCHandle,
+ const CssmData DataBufs[],
+ uint32 DataBufCount);
+ virtual void VerifyDataFinal(CSSM_CC_HANDLE CCHandle,
+ const CssmData &Signature);
+
+ void DigestData(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ const CssmData DataBufs[],
+ uint32 DataBufCount,
+ CssmData &Digest);
+ void DigestDataInit(CSSM_CC_HANDLE CCHandle,
+ const Context &Context);
+ void DigestDataUpdate(CSSM_CC_HANDLE CCHandle,
+ const CssmData DataBufs[],
+ uint32 DataBufCount);
+ void DigestDataFinal(CSSM_CC_HANDLE CCHandle,
+ CssmData &Digest);
+ void DigestDataClone(CSSM_CC_HANDLE CCHandle,
+ CSSM_CC_HANDLE ClonedCCHandle);
+
+ void GenerateKey(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ uint32 KeyUsage,
+ uint32 KeyAttr,
+ const CssmData *KeyLabel,
+ const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
+ CssmKey &Key,
+ CSSM_PRIVILEGE Privilege);
+ void GenerateKeyPair(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ uint32 PublicKeyUsage,
+ uint32 PublicKeyAttr,
+ const CssmData *PublicKeyLabel,
+ CssmKey &PublicKey,
+ uint32 PrivateKeyUsage,
+ uint32 PrivateKeyAttr,
+ const CssmData *PrivateKeyLabel,
+ const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
+ CssmKey &PrivateKey,
+ CSSM_PRIVILEGE Privilege);
+
+ void ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey,
+ CssmKey &PrivateKey);
+ void QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle,
+ const Context *Context,
+ const CssmKey *Key,
+ CSSM_KEY_SIZE &KeySize);
+
+ void FreeKey(const AccessCredentials *AccessCred,
+ CssmKey &KeyPtr,
+ CSSM_BOOL Delete);
+
+ void GenerateRandom(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ CssmData &RandomNumber);
+ void GenerateAlgorithmParams(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ uint32 ParamBits,
+ CssmData &Param,
+ uint32 &NumberOfUpdatedAttibutes,
+ CSSM_CONTEXT_ATTRIBUTE_PTR &UpdatedAttributes);
+
+ void Login(const AccessCredentials &AccessCred,
+ const CssmData *LoginName,
+ const void *Reserved);
+ void Logout();
+ void VerifyDevice(const CssmData &DeviceCert);
+ void GetOperationalStatistics(CSPOperationalStatistics &Statistics);
+
+ void RetrieveCounter(CssmData &Counter);
+ void RetrieveUniqueId(CssmData &UniqueID);
+ void GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData);
+
+ void GetKeyOwner(const CssmKey &Key,
+ CSSM_ACL_OWNER_PROTOTYPE &Owner);
+ void ChangeKeyOwner(const AccessCredentials &AccessCred,
+ const CssmKey &Key,
+ const CSSM_ACL_OWNER_PROTOTYPE &NewOwner);
+ void GetKeyAcl(const CssmKey &Key,
+ const CSSM_STRING *SelectionTag,
+ uint32 &NumberOfAclInfos,
+ CSSM_ACL_ENTRY_INFO_PTR &AclInfos);
+ void ChangeKeyAcl(const AccessCredentials &AccessCred,
+ const CSSM_ACL_EDIT &AclEdit,
+ const CssmKey &Key);
+
+ void GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner);
+ void ChangeLoginOwner(const AccessCredentials &AccessCred,
+ const CSSM_ACL_OWNER_PROTOTYPE &NewOwner);
+ void GetLoginAcl(const CSSM_STRING *SelectionTag,
+ uint32 &NumberOfAclInfos,
+ CSSM_ACL_ENTRY_INFO_PTR &AclInfos);
+ void ChangeLoginAcl(const AccessCredentials &AccessCred,
+ const CSSM_ACL_EDIT &AclEdit);
+
+ void PassThrough(CSSM_CC_HANDLE CCHandle,
+ const Context &Context,
+ uint32 PassThroughId,
+ const void *InData,
+ void **OutData);
+};
+
+
+//
+// Classes for dealing with reference keys.
+//
+
+// Forward declaration.
+class KeyPool;
+
+//
+// A ReferencedKey -- The private (to the CSP) part of a Reference Key.
+//
+class ReferencedKey
+{
+ friend class KeyPool; // So it can call deactivate()
+public:
+ // What we use to reference a ReferencedKey.
+ typedef CSSM_INTPTR KeyReference;
+ ReferencedKey(KeyPool &session); // Calls KeyPool::add()
+ virtual ~ReferencedKey(); // Calls KeyPool::erase()
+
+ KeyReference keyReference();
+ bool isActive() { return mKeyPool != NULL; }
+
+ template <class SubPool>
+ SubPool &keyPool() { assert(mKeyPool); return safer_cast<SubPool &>(*mKeyPool); }
+public:
+ // Making, retrieving and freeing CSSM_KEYBLOB_REF_FORMAT_INTEGER CSSM_KEY type reference keys
+ // NOTE: that none of these functions affect mKeyMap.
+ static void makeReferenceKey(Allocator &allocator, KeyReference keyReference, CSSM_KEY &ioKey);
+ static KeyReference keyReference(const CSSM_KEY &key);
+ static KeyReference freeReferenceKey(Allocator &allocator, CSSM_KEY &ioKey);
+
+private:
+ void deactivate() { mKeyPool = NULL; }
+
+ // Will be NULL iff this key is not active
+ KeyPool *mKeyPool;
+};
+
+
+//
+// KeyPool -- a mixin class to manage a pool of ReferencedKeys
+//
+class KeyPool
+{
+public:
+ friend class ReferencedKey; // So it can call add() and erase()
+public:
+ KeyPool();
+ virtual ~KeyPool();
+
+ // Type safe ReferencedKey subclass lookup
+ template <class Subclass>
+ Subclass &find(const CSSM_KEY &key) const;
+
+ // Free the ioKey, erase keyReference from mKeyMap, and delete the ReferencedKey
+ void freeKey(Allocator &allocator, CSSM_KEY &key);
+
+protected:
+ // Called by the constructor of ReferencedKey -- add referencedKey to mKeyMap
+ void add(ReferencedKey &referencedKey);
+
+ ReferencedKey &findKey(const CSSM_KEY &key) const;
+ ReferencedKey &findKeyReference(ReferencedKey::KeyReference keyReference) const;
+
+ // Called by the destructor of ReferencedKey -- erase keyReference from mKeyMap
+ void erase(ReferencedKey &referencedKey);
+
+ // Erase keyReference from mKeyMap, and return it (for deletion)
+ ReferencedKey &erase(ReferencedKey::KeyReference keyReference);
+
+protected:
+ typedef map<ReferencedKey::KeyReference, ReferencedKey *> KeyMap;
+ KeyMap mKeyMap;
+ mutable Mutex mKeyMapLock;
+};
+
+// Implementation of type safe ReferencedKey subclass lookup.
+template <class Subclass>
+Subclass &
+KeyPool::find(const CSSM_KEY &key) const
+{
+ Subclass *sub;
+ if (!(sub = dynamic_cast<Subclass *>(&findKey(key))))
+ CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
+ return *sub;
+}
+
+} // end namespace Security
+
+#endif //_H_CSPSESSION