1/*
2 * Copyright (c) 2000-2001,2011,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18#ifdef	BSAFE_CSP_ENABLE
19
20
21//
22// bsafecspi - implementation layer for C++ BSafe 4 interface
23//
24#ifndef _H_BSAFECSPI
25#define _H_BSAFECSPI
26
27#include <security_cdsa_plugin/CSPsession.h>
28#include "bsobjects.h"
29#include "AppleCSPContext.h"
30#include "AppleCSPSession.h"
31#include <aglobal.h>
32#include <bsafe.h>
33
34//
35// The BSafe class is more of a namespace than anything else.
36// Just think of it as the "static binder" for BSafe's objects.
37// Note that we keep a global, static allocator. We have to; BSafe
38// doesn't have any state management at that level.
39//
40class BSafe {
41    class BSafeContext; friend class BSafeContext;
42	class BSafeFactory; friend class BSafeFactory;
43
44public:
45    static void setNormAllocator(Allocator *alloc)
46    { assert(!normAllocator); normAllocator = alloc; }
47    static void setPrivAllocator(Allocator *alloc)
48    { assert(!privAllocator); privAllocator = alloc; }
49
50	static bool setup(
51		AppleCSPSession &session,
52		CSPFullPluginSession::CSPContext * &cspCtx,
53		const Context &context);
54
55private:
56    // BSafe's memory allocators
57    static Allocator *normAllocator;
58    static Allocator *privAllocator;
59    friend POINTER T_malloc(unsigned int);
60    friend void T_free(POINTER);
61    friend POINTER T_realloc(POINTER, unsigned int);
62
63    static const B_ALGORITHM_METHOD * const bsChooser[];
64
65private:
66	// BSafe-specific BinaryKey class.
67	class BSafeBinaryKey : public BinaryKey {
68
69	public:
70		BSafeBinaryKey(
71			bool 			isPub,
72			uint32			alg);	// CSSM_ALGID_{RSA,DSA}
73		~BSafeBinaryKey();
74		void generateKeyBlob(
75			Allocator 		&allocator,
76			CssmData			&blob,
77			CSSM_KEYBLOB_FORMAT	&format,
78			AppleCSPSession		&session,
79			const CssmKey		*paramKey,		/* optional, unused here */
80			CSSM_KEYATTR_FLAGS 	&attrFlags);	/* IN/OUT */
81
82		bool			isPublic() 	{ return mIsPublic; }
83		uint32			alg()		{ return mAlg; }
84		B_KEY_OBJ		bsKey()		{ return mBsKey; }
85
86	private:
87		bool			mIsPublic;
88		uint32			mAlg;		// CSSM_ALGID_{RSA,DSA}
89		B_KEY_OBJ		mBsKey;
90	};
91
92private:
93	//
94	// The BSafeContext class is the parent of all BSafe-used CSPContext objects.
95	// It implements the CSPContext operation functions (init, update, ...) in terms
96	// of pointer-to-member fields set by its subclasses. This may not be pretty, but
97	// it avoids every subclass having to re-implement all CSPContext operations.
98	// Beyond that, we implement a raftload of utility methods for our children.
99	//
100    class BSafeContext : public AppleCSPContext {
101        friend class BSafe;
102    public:
103        BSafeContext(AppleCSPSession &session);
104        virtual ~BSafeContext();
105
106		// called by CSPFullPluginSession
107        void init(const Context &context, bool encoding = true);
108        void update(const CssmData &data);
109        void update(void *inp, size_t &inSize, void *outp, size_t &outSize);
110        void final(CssmData &out);
111        void final(const CssmData &in);
112        size_t outputSize(bool final, size_t inSize);
113
114    protected:
115		// install a BSafe algorithm into bsAlgorithm
116        void setAlgorithm(B_INFO_TYPE bAlgType, const void *info = NULL);
117
118		// safely create bsKey
119		void createBsKey();
120
121		// set bsKey. The different versions are equivalent
122        void setKeyAtom(B_INFO_TYPE bKeyInfo, const void *info);
123        void setKeyFromItem(B_INFO_TYPE bKeyInfo, const BSafeItem &item)
124			{ setKeyAtom(bKeyInfo, &item); }
125        void setKeyFromCssmKey(B_INFO_TYPE bKeyInfo, const CssmKey &key)
126			{ BSafeItem item(key.KeyData); setKeyAtom(bKeyInfo, &item); }
127        void setKeyFromCssmData(B_INFO_TYPE bKeyInfo, const CssmData &keyData)
128			{ BSafeItem item(keyData); setKeyAtom(bKeyInfo, &item); }
129        void setKeyFromContext(const Context &context, bool required = true);
130
131		void setRefKey(CssmKey &key);
132		void setRsaOutSize(bool isPubKey);
133
134		// create mRandom to be a suitable random-generator BSafe object (if it isn't yet)
135        void setRandom();
136
137		// trackUpdate is called during crypto-output. Hook it to keep track of data flow
138        virtual void trackUpdate(size_t in, size_t out);
139
140		// destroy bsAlgorithm and bsKey so we can start over making them
141        void reset();
142
143		// clear key state
144		void destroyBsKey();
145
146		// determine if we can reuse the current bsAlgorithm
147        bool reusing(bool encode = true)
148        {
149            if (initialized && !opStarted &&
150				(encode == encoding)) return true;
151            encoding = encode;
152            return false;
153        }
154
155    public:
156		//
157		// These pointers-to-member are called by the BSafeContext operations
158		// (update, final). They must be set by a subclasses's init() method.
159		// Not all members are used by all types of operations - check the
160		// source when in doubt.
161		//
162        int (*inUpdate)(B_ALGORITHM_OBJ, POINTER, unsigned int, A_SURRENDER_CTX *);
163        int (*inOutUpdate)(B_ALGORITHM_OBJ, POINTER, unsigned int *, unsigned int,
164                            POINTER, unsigned int, B_ALGORITHM_OBJ, A_SURRENDER_CTX *);
165        int (*inFinal)(B_ALGORITHM_OBJ, POINTER, unsigned int, A_SURRENDER_CTX *);
166        int (*inFinalR)(B_ALGORITHM_OBJ, POINTER, unsigned int,
167                        B_ALGORITHM_OBJ, A_SURRENDER_CTX *);
168        int (*outFinalR)(B_ALGORITHM_OBJ, POINTER, unsigned int *, unsigned int,
169                        B_ALGORITHM_OBJ, A_SURRENDER_CTX *);
170        int (*outFinal)(B_ALGORITHM_OBJ, POINTER, unsigned int *, unsigned int,
171                        A_SURRENDER_CTX *);
172
173    protected:
174
175        // un-consted bsChooser for BSafe's consumption. BSafe's Bad
176        static B_ALGORITHM_METHOD **chooser()
177        { return const_cast<B_ALGORITHM_METHOD **>(bsChooser); }
178
179		// a placeholder for a surrender context. Not currently used
180		// @@@ should perhaps test for pthread cancel? --> thread abstraction
181        static A_SURRENDER_CTX * const bsSurrender;
182
183    protected:
184        B_ALGORITHM_OBJ bsAlgorithm; // BSafe algorithm object or NULL
185        B_ALGORITHM_OBJ bsRandom;	// PRNG algorithm
186        bool encoding;				// encoding direction
187        bool initialized;			// method init() has completed
188		bool opStarted;				// method update() has been called
189									// generally means that we can't reuse
190									// the current bsAlgorithm
191		//
192		// We have a binKey only if the caller passed in a reference
193		// key. In that case we avoid deleting bsKey - which is a copy
194		// of binKey.bsKey - because a BinaryKey is persistent
195		// relative to this context.
196		//
197		BSafeBinaryKey	*bsBinKey;
198        B_KEY_OBJ 		bsKey;		// BSafe key object or NULL
199
200        size_t 			mOutSize; 	// simple output size, if applicable
201    };	/* BSafeContext */
202
203	// contexts for BSafe digest operations
204    class DigestContext : public BSafeContext {
205    public:
206		// do all work in constructor. We have no directions; thus default init() works fine
207        DigestContext(
208			AppleCSPSession &session,
209			const Context &,
210			B_INFO_TYPE bAlgInfo,
211			size_t sz);
212    };
213
214	// common context features for BSafe cipher operations (both symmetric and asymmetric)
215    class CipherContext : public BSafeContext {
216	public:
217		CipherContext(
218			AppleCSPSession &session) :
219				BSafeContext(session),
220				pending(0) {}
221
222	protected:
223        size_t pending;				// bytes not eaten still pending (staged only)
224    public:
225        void cipherInit();			// common init code (must be called from init())
226    };
227
228	// contexts for block cipher operations using symmetric algorithms
229    class BlockCipherContext : public CipherContext {
230        size_t blockSize;
231		uint32 cssmAlg;
232		uint32 cssmMode;
233		bool padEnable;
234    public:
235        BlockCipherContext(
236			AppleCSPSession &session,
237			const Context &,
238			size_t sz) :
239				CipherContext(session),
240			 	blockSize(sz) { }
241        void init(const Context &context, bool encrypting);
242        size_t inputSize(size_t outSize);
243        size_t outputSize(bool final, size_t inSize);
244        void minimumProgress(size_t &in, size_t &out);
245        void trackUpdate(size_t in, size_t out);
246	private:
247		// special case for RC4
248		void RC4init(const Context &context);
249    };
250
251	// context for generating public/private key pairs
252    class BSafeKeyPairGenContext : public BSafeContext,
253					 private AppleKeyPairGenContext  {
254	public:
255		BSafeKeyPairGenContext(
256			AppleCSPSession &session,
257			const Context &) :
258				BSafeContext(session) {}
259
260		// generate alg params, not handled by PublicKeyGenerateContext
261		// For DSA only.
262        void generate(
263			const Context 			&context,
264			uint32 					bitSize,
265			CssmData 				&params,
266			uint32 					&attrCount,
267			Context::Attr * 		&attrs);
268
269		// this one is specified in CSPFullPluginSession
270		void generate(
271			const Context 	&context,
272			CssmKey 		&pubKey,
273			CssmKey 		&privKey);
274
275		// this one in AppleKeyPairGenContext
276		void generate(
277			const Context 	&context,
278			BinaryKey		&pubBinKey,
279			BinaryKey		&privBinKey,
280			uint32			&keySize);
281
282	private:
283		void setupAlgorithm(
284			const Context 	&context,
285			uint32			&keySize);
286
287    };	/* BSafeKeyPairGenContext */
288
289	// public key cipher operations
290    class PublicKeyCipherContext : public CipherContext {
291    public:
292		PublicKeyCipherContext(
293			AppleCSPSession &session,
294			const Context &) :
295				CipherContext(session) { }
296        void init(const Context &context, bool encrypting);
297        size_t inputSize(size_t outSize);	// unlimited
298    };
299
300	// contexts for BSafe signing/verifying operations
301    class SigningContext : public BSafeContext {
302        B_INFO_TYPE algorithm;
303    public:
304        SigningContext(
305			AppleCSPSession &session,
306			const Context &,
307			B_INFO_TYPE bAlg,
308			size_t sz) :
309				BSafeContext(session),
310				algorithm(bAlg) { mOutSize = sz; }
311        void init(const Context &context, bool signing);
312    };
313
314	// contexts for BSafe MAC generation and verification
315    class MacContext : public BSafeContext {
316        B_INFO_TYPE algorithm;
317    public:
318        MacContext(
319			AppleCSPSession &session,
320			const Context &,
321            B_INFO_TYPE bAlg,
322			size_t sz) :
323				BSafeContext(session),
324				algorithm(bAlg) { mOutSize = sz; }
325        void init(const Context &context, bool signing);
326        void final(const CssmData &in);
327    };
328
329	// contexts for BSafe's random number generation
330	class RandomContext : public BSafeContext {
331		B_INFO_TYPE algorithm;
332	public:
333		RandomContext(
334			AppleCSPSession &session,
335			const Context &,
336			B_INFO_TYPE alg) :
337				BSafeContext(session),
338				algorithm(alg) { }
339		void init(const Context &context, bool);
340		void final(CssmData &data);
341	};
342
343	// symmetric key generation context
344	class SymmetricKeyGenContext : public BSafeContext,
345		private AppleSymmKeyGenContext {
346    public:
347		SymmetricKeyGenContext(
348			AppleCSPSession &session,
349			const Context 	&ctx,
350			uint32			minSizeInBits,
351			uint32			maxSizeInBits,
352			bool			mustBeByteSized) :
353				BSafeContext(session),
354				AppleSymmKeyGenContext(
355					minSizeInBits,
356					maxSizeInBits,
357					mustBeByteSized) { }
358
359		void generate(
360			const Context 	&context,
361			CssmKey 		&symKey,
362			CssmKey 		&dummyKey);
363
364    };
365
366public:
367	/*
368	 * Stateless, private function to map a CSSM alg and pub/priv state
369	 * to B_INFO_TYPE and format. Returns true on success, false on
370	 * "I don't understand this algorithm".
371	 */
372	static bool bsafeAlgToInfoType(
373		CSSM_ALGORITHMS		alg,
374		bool				isPublic,
375		B_INFO_TYPE			&infoType,	// RETURNED
376		CSSM_KEYBLOB_FORMAT	&format);	// RETURNED
377
378	/* check result of a BSafe call and throw on error */
379	static void check(int status, bool isKeyOp = false);
380
381	/* moved here from BSafeContext - now works on any key */
382	template <class KI_Type>
383	static KI_Type *getKey(B_KEY_OBJ bKey, B_INFO_TYPE type)
384	{
385		POINTER p;
386		check(B_GetKeyInfo(&p, bKey, type), true);
387		return reinterpret_cast<KI_Type *>(p);
388	}
389
390
391    //
392    // The context generation table - see algmaker.cpp.
393    //
394public:
395	// Base class for Maker classes
396	class MakerBase {
397	public:
398		virtual ~MakerBase() { }
399		virtual BSafeContext *make(
400			AppleCSPSession &session,
401			const Context &context) const = 0;
402	};
403
404	// One entry in Maker table
405	struct MakerTable {
406		CSSM_ALGORITHMS 	algorithmId;
407		CSSM_CONTEXT_TYPE	algClass;
408		const MakerBase 	*maker;
409		~MakerTable() { delete maker; }
410	};
411
412private:
413	static bug_const MakerTable algorithms[];
414	static const unsigned int algorithmCount;
415
416	/*
417	 * CSPKeyInfoProvider for BSafe keys
418	 */
419	class BSafeKeyInfoProvider : public CSPKeyInfoProvider
420	{
421private:
422		BSafeKeyInfoProvider(
423			const CssmKey		&cssmKey,
424			AppleCSPSession		&session);
425	public:
426		static CSPKeyInfoProvider *provider(
427		const CssmKey 			&cssmKey,
428		AppleCSPSession			&session);
429		~BSafeKeyInfoProvider() { }
430		void CssmKeyToBinary(
431			CssmKey				*paramKey,	// optional
432			CSSM_KEYATTR_FLAGS	&attrFlags,	// IN/OUT
433			BinaryKey			**binKey);	// RETURNED
434		void QueryKeySizeInBits(
435			CSSM_KEY_SIZE		&keySize);	// RETURNED
436	};
437
438}; /* BSAFE namespace */
439
440/*
441 * BSAFE Key Info types.
442 */
443#define BLOB_IS_PUB_KEY_INFO	0
444
445#if		BLOB_IS_PUB_KEY_INFO
446
447/* X beta values */
448#define RSA_PUB_KEYINFO_TYPE		KI_RSAPublicBER
449#define RSA_PRIV_KEYINFO_TYPE		KI_PKCS_RSAPrivateBER
450#define DSA_PUB_KEYINFO_TYPE		KI_DSAPublicBER
451#define DSA_PRIV_KEYINFO_TYPE		KI_DSAPrivateBER
452
453#else	/* BLOB_IS_PUB_KEY_INFO */
454
455#define RSA_PUB_KEYINFO_TYPE		KI_RSAPublic
456#define RSA_PRIV_KEYINFO_TYPE		KI_PKCS_RSAPrivateBER
457#define DSA_PUB_KEYINFO_TYPE		KI_DSAPublicBER
458#define DSA_PRIV_KEYINFO_TYPE		KI_DSAPrivateBER
459
460#endif
461
462#endif //_H_BSAFECSP
463#endif	/* BSAFE_CSP_ENABLE */
464