--- /dev/null
+/*
+ * Copyright (c) 2000-2001,2011,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.
+ */
+
+#ifdef BSAFE_CSP_ENABLE
+
+
+//
+// bsafecspi - implementation layer for C++ BSafe 4 interface
+//
+#ifndef _H_BSAFECSPI
+#define _H_BSAFECSPI
+
+#include <security_cdsa_plugin/CSPsession.h>
+#include "bsobjects.h"
+#include "AppleCSPContext.h"
+#include "AppleCSPSession.h"
+#include <aglobal.h>
+#include <bsafe.h>
+
+//
+// The BSafe class is more of a namespace than anything else.
+// Just think of it as the "static binder" for BSafe's objects.
+// Note that we keep a global, static allocator. We have to; BSafe
+// doesn't have any state management at that level.
+//
+class BSafe {
+ class BSafeContext; friend class BSafeContext;
+ class BSafeFactory; friend class BSafeFactory;
+
+public:
+ static void setNormAllocator(Allocator *alloc)
+ { assert(!normAllocator); normAllocator = alloc; }
+ static void setPrivAllocator(Allocator *alloc)
+ { assert(!privAllocator); privAllocator = alloc; }
+
+ static bool setup(
+ AppleCSPSession &session,
+ CSPFullPluginSession::CSPContext * &cspCtx,
+ const Context &context);
+
+private:
+ // BSafe's memory allocators
+ static Allocator *normAllocator;
+ static Allocator *privAllocator;
+ friend POINTER T_malloc(unsigned int);
+ friend void T_free(POINTER);
+ friend POINTER T_realloc(POINTER, unsigned int);
+
+ static const B_ALGORITHM_METHOD * const bsChooser[];
+
+private:
+ // BSafe-specific BinaryKey class.
+ class BSafeBinaryKey : public BinaryKey {
+
+ public:
+ BSafeBinaryKey(
+ bool isPub,
+ uint32 alg); // CSSM_ALGID_{RSA,DSA}
+ ~BSafeBinaryKey();
+ void generateKeyBlob(
+ Allocator &allocator,
+ CssmData &blob,
+ CSSM_KEYBLOB_FORMAT &format,
+ AppleCSPSession &session,
+ const CssmKey *paramKey, /* optional, unused here */
+ CSSM_KEYATTR_FLAGS &attrFlags); /* IN/OUT */
+
+ bool isPublic() { return mIsPublic; }
+ uint32 alg() { return mAlg; }
+ B_KEY_OBJ bsKey() { return mBsKey; }
+
+ private:
+ bool mIsPublic;
+ uint32 mAlg; // CSSM_ALGID_{RSA,DSA}
+ B_KEY_OBJ mBsKey;
+ };
+
+private:
+ //
+ // The BSafeContext class is the parent of all BSafe-used CSPContext objects.
+ // It implements the CSPContext operation functions (init, update, ...) in terms
+ // of pointer-to-member fields set by its subclasses. This may not be pretty, but
+ // it avoids every subclass having to re-implement all CSPContext operations.
+ // Beyond that, we implement a raftload of utility methods for our children.
+ //
+ class BSafeContext : public AppleCSPContext {
+ friend class BSafe;
+ public:
+ BSafeContext(AppleCSPSession &session);
+ virtual ~BSafeContext();
+
+ // called by CSPFullPluginSession
+ void init(const Context &context, bool encoding = true);
+ void update(const CssmData &data);
+ void update(void *inp, size_t &inSize, void *outp, size_t &outSize);
+ void final(CssmData &out);
+ void final(const CssmData &in);
+ size_t outputSize(bool final, size_t inSize);
+
+ protected:
+ // install a BSafe algorithm into bsAlgorithm
+ void setAlgorithm(B_INFO_TYPE bAlgType, const void *info = NULL);
+
+ // safely create bsKey
+ void createBsKey();
+
+ // set bsKey. The different versions are equivalent
+ void setKeyAtom(B_INFO_TYPE bKeyInfo, const void *info);
+ void setKeyFromItem(B_INFO_TYPE bKeyInfo, const BSafeItem &item)
+ { setKeyAtom(bKeyInfo, &item); }
+ void setKeyFromCssmKey(B_INFO_TYPE bKeyInfo, const CssmKey &key)
+ { BSafeItem item(key.KeyData); setKeyAtom(bKeyInfo, &item); }
+ void setKeyFromCssmData(B_INFO_TYPE bKeyInfo, const CssmData &keyData)
+ { BSafeItem item(keyData); setKeyAtom(bKeyInfo, &item); }
+ void setKeyFromContext(const Context &context, bool required = true);
+
+ void setRefKey(CssmKey &key);
+ void setRsaOutSize(bool isPubKey);
+
+ // create mRandom to be a suitable random-generator BSafe object (if it isn't yet)
+ void setRandom();
+
+ // trackUpdate is called during crypto-output. Hook it to keep track of data flow
+ virtual void trackUpdate(size_t in, size_t out);
+
+ // destroy bsAlgorithm and bsKey so we can start over making them
+ void reset();
+
+ // clear key state
+ void destroyBsKey();
+
+ // determine if we can reuse the current bsAlgorithm
+ bool reusing(bool encode = true)
+ {
+ if (initialized && !opStarted &&
+ (encode == encoding)) return true;
+ encoding = encode;
+ return false;
+ }
+
+ public:
+ //
+ // These pointers-to-member are called by the BSafeContext operations
+ // (update, final). They must be set by a subclasses's init() method.
+ // Not all members are used by all types of operations - check the
+ // source when in doubt.
+ //
+ int (*inUpdate)(B_ALGORITHM_OBJ, POINTER, unsigned int, A_SURRENDER_CTX *);
+ int (*inOutUpdate)(B_ALGORITHM_OBJ, POINTER, unsigned int *, unsigned int,
+ POINTER, unsigned int, B_ALGORITHM_OBJ, A_SURRENDER_CTX *);
+ int (*inFinal)(B_ALGORITHM_OBJ, POINTER, unsigned int, A_SURRENDER_CTX *);
+ int (*inFinalR)(B_ALGORITHM_OBJ, POINTER, unsigned int,
+ B_ALGORITHM_OBJ, A_SURRENDER_CTX *);
+ int (*outFinalR)(B_ALGORITHM_OBJ, POINTER, unsigned int *, unsigned int,
+ B_ALGORITHM_OBJ, A_SURRENDER_CTX *);
+ int (*outFinal)(B_ALGORITHM_OBJ, POINTER, unsigned int *, unsigned int,
+ A_SURRENDER_CTX *);
+
+ protected:
+
+ // un-consted bsChooser for BSafe's consumption. BSafe's Bad
+ static B_ALGORITHM_METHOD **chooser()
+ { return const_cast<B_ALGORITHM_METHOD **>(bsChooser); }
+
+ // a placeholder for a surrender context. Not currently used
+ // @@@ should perhaps test for pthread cancel? --> thread abstraction
+ static A_SURRENDER_CTX * const bsSurrender;
+
+ protected:
+ B_ALGORITHM_OBJ bsAlgorithm; // BSafe algorithm object or NULL
+ B_ALGORITHM_OBJ bsRandom; // PRNG algorithm
+ bool encoding; // encoding direction
+ bool initialized; // method init() has completed
+ bool opStarted; // method update() has been called
+ // generally means that we can't reuse
+ // the current bsAlgorithm
+ //
+ // We have a binKey only if the caller passed in a reference
+ // key. In that case we avoid deleting bsKey - which is a copy
+ // of binKey.bsKey - because a BinaryKey is persistent
+ // relative to this context.
+ //
+ BSafeBinaryKey *bsBinKey;
+ B_KEY_OBJ bsKey; // BSafe key object or NULL
+
+ size_t mOutSize; // simple output size, if applicable
+ }; /* BSafeContext */
+
+ // contexts for BSafe digest operations
+ class DigestContext : public BSafeContext {
+ public:
+ // do all work in constructor. We have no directions; thus default init() works fine
+ DigestContext(
+ AppleCSPSession &session,
+ const Context &,
+ B_INFO_TYPE bAlgInfo,
+ size_t sz);
+ };
+
+ // common context features for BSafe cipher operations (both symmetric and asymmetric)
+ class CipherContext : public BSafeContext {
+ public:
+ CipherContext(
+ AppleCSPSession &session) :
+ BSafeContext(session),
+ pending(0) {}
+
+ protected:
+ size_t pending; // bytes not eaten still pending (staged only)
+ public:
+ void cipherInit(); // common init code (must be called from init())
+ };
+
+ // contexts for block cipher operations using symmetric algorithms
+ class BlockCipherContext : public CipherContext {
+ size_t blockSize;
+ uint32 cssmAlg;
+ uint32 cssmMode;
+ bool padEnable;
+ public:
+ BlockCipherContext(
+ AppleCSPSession &session,
+ const Context &,
+ size_t sz) :
+ CipherContext(session),
+ blockSize(sz) { }
+ void init(const Context &context, bool encrypting);
+ size_t inputSize(size_t outSize);
+ size_t outputSize(bool final, size_t inSize);
+ void minimumProgress(size_t &in, size_t &out);
+ void trackUpdate(size_t in, size_t out);
+ private:
+ // special case for RC4
+ void RC4init(const Context &context);
+ };
+
+ // context for generating public/private key pairs
+ class BSafeKeyPairGenContext : public BSafeContext,
+ private AppleKeyPairGenContext {
+ public:
+ BSafeKeyPairGenContext(
+ AppleCSPSession &session,
+ const Context &) :
+ BSafeContext(session) {}
+
+ // generate alg params, not handled by PublicKeyGenerateContext
+ // For DSA only.
+ void generate(
+ const Context &context,
+ uint32 bitSize,
+ CssmData ¶ms,
+ uint32 &attrCount,
+ Context::Attr * &attrs);
+
+ // this one is specified in CSPFullPluginSession
+ void generate(
+ const Context &context,
+ CssmKey &pubKey,
+ CssmKey &privKey);
+
+ // this one in AppleKeyPairGenContext
+ void generate(
+ const Context &context,
+ BinaryKey &pubBinKey,
+ BinaryKey &privBinKey,
+ uint32 &keySize);
+
+ private:
+ void setupAlgorithm(
+ const Context &context,
+ uint32 &keySize);
+
+ }; /* BSafeKeyPairGenContext */
+
+ // public key cipher operations
+ class PublicKeyCipherContext : public CipherContext {
+ public:
+ PublicKeyCipherContext(
+ AppleCSPSession &session,
+ const Context &) :
+ CipherContext(session) { }
+ void init(const Context &context, bool encrypting);
+ size_t inputSize(size_t outSize); // unlimited
+ };
+
+ // contexts for BSafe signing/verifying operations
+ class SigningContext : public BSafeContext {
+ B_INFO_TYPE algorithm;
+ public:
+ SigningContext(
+ AppleCSPSession &session,
+ const Context &,
+ B_INFO_TYPE bAlg,
+ size_t sz) :
+ BSafeContext(session),
+ algorithm(bAlg) { mOutSize = sz; }
+ void init(const Context &context, bool signing);
+ };
+
+ // contexts for BSafe MAC generation and verification
+ class MacContext : public BSafeContext {
+ B_INFO_TYPE algorithm;
+ public:
+ MacContext(
+ AppleCSPSession &session,
+ const Context &,
+ B_INFO_TYPE bAlg,
+ size_t sz) :
+ BSafeContext(session),
+ algorithm(bAlg) { mOutSize = sz; }
+ void init(const Context &context, bool signing);
+ void final(const CssmData &in);
+ };
+
+ // contexts for BSafe's random number generation
+ class RandomContext : public BSafeContext {
+ B_INFO_TYPE algorithm;
+ public:
+ RandomContext(
+ AppleCSPSession &session,
+ const Context &,
+ B_INFO_TYPE alg) :
+ BSafeContext(session),
+ algorithm(alg) { }
+ void init(const Context &context, bool);
+ void final(CssmData &data);
+ };
+
+ // symmetric key generation context
+ class SymmetricKeyGenContext : public BSafeContext,
+ private AppleSymmKeyGenContext {
+ public:
+ SymmetricKeyGenContext(
+ AppleCSPSession &session,
+ const Context &ctx,
+ uint32 minSizeInBits,
+ uint32 maxSizeInBits,
+ bool mustBeByteSized) :
+ BSafeContext(session),
+ AppleSymmKeyGenContext(
+ minSizeInBits,
+ maxSizeInBits,
+ mustBeByteSized) { }
+
+ void generate(
+ const Context &context,
+ CssmKey &symKey,
+ CssmKey &dummyKey);
+
+ };
+
+public:
+ /*
+ * Stateless, private function to map a CSSM alg and pub/priv state
+ * to B_INFO_TYPE and format. Returns true on success, false on
+ * "I don't understand this algorithm".
+ */
+ static bool bsafeAlgToInfoType(
+ CSSM_ALGORITHMS alg,
+ bool isPublic,
+ B_INFO_TYPE &infoType, // RETURNED
+ CSSM_KEYBLOB_FORMAT &format); // RETURNED
+
+ /* check result of a BSafe call and throw on error */
+ static void check(int status, bool isKeyOp = false);
+
+ /* moved here from BSafeContext - now works on any key */
+ template <class KI_Type>
+ static KI_Type *getKey(B_KEY_OBJ bKey, B_INFO_TYPE type)
+ {
+ POINTER p;
+ check(B_GetKeyInfo(&p, bKey, type), true);
+ return reinterpret_cast<KI_Type *>(p);
+ }
+
+
+ //
+ // The context generation table - see algmaker.cpp.
+ //
+public:
+ // Base class for Maker classes
+ class MakerBase {
+ public:
+ virtual ~MakerBase() { }
+ virtual BSafeContext *make(
+ AppleCSPSession &session,
+ const Context &context) const = 0;
+ };
+
+ // One entry in Maker table
+ struct MakerTable {
+ CSSM_ALGORITHMS algorithmId;
+ CSSM_CONTEXT_TYPE algClass;
+ const MakerBase *maker;
+ ~MakerTable() { delete maker; }
+ };
+
+private:
+ static bug_const MakerTable algorithms[];
+ static const unsigned int algorithmCount;
+
+ /*
+ * CSPKeyInfoProvider for BSafe keys
+ */
+ class BSafeKeyInfoProvider : public CSPKeyInfoProvider
+ {
+private:
+ BSafeKeyInfoProvider(
+ const CssmKey &cssmKey,
+ AppleCSPSession &session);
+ public:
+ static CSPKeyInfoProvider *provider(
+ const CssmKey &cssmKey,
+ AppleCSPSession &session);
+ ~BSafeKeyInfoProvider() { }
+ void CssmKeyToBinary(
+ CssmKey *paramKey, // optional
+ CSSM_KEYATTR_FLAGS &attrFlags, // IN/OUT
+ BinaryKey **binKey); // RETURNED
+ void QueryKeySizeInBits(
+ CSSM_KEY_SIZE &keySize); // RETURNED
+ };
+
+}; /* BSAFE namespace */
+
+/*
+ * BSAFE Key Info types.
+ */
+#define BLOB_IS_PUB_KEY_INFO 0
+
+#if BLOB_IS_PUB_KEY_INFO
+
+/* X beta values */
+#define RSA_PUB_KEYINFO_TYPE KI_RSAPublicBER
+#define RSA_PRIV_KEYINFO_TYPE KI_PKCS_RSAPrivateBER
+#define DSA_PUB_KEYINFO_TYPE KI_DSAPublicBER
+#define DSA_PRIV_KEYINFO_TYPE KI_DSAPrivateBER
+
+#else /* BLOB_IS_PUB_KEY_INFO */
+
+#define RSA_PUB_KEYINFO_TYPE KI_RSAPublic
+#define RSA_PRIV_KEYINFO_TYPE KI_PKCS_RSAPrivateBER
+#define DSA_PUB_KEYINFO_TYPE KI_DSAPublicBER
+#define DSA_PRIV_KEYINFO_TYPE KI_DSAPrivateBER
+
+#endif
+
+#endif //_H_BSAFECSP
+#endif /* BSAFE_CSP_ENABLE */