2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
18 #ifdef BSAFE_CSP_ENABLE
22 // bsafeContext.cpp - implementation of class BSafe::BSafeContext
23 // and some of its subclasses
26 #include "bsafecspi.h"
27 #include "bsafePKCS1.h"
31 #include "cspdebugging.h"
33 #define DATA(cData) POINTER(cData.data()), cData.length()
35 A_SURRENDER_CTX
* const BSafe::BSafeContext::bsSurrender
= NULL
;
39 // Construct an algorithm object
41 BSafe::BSafeContext::BSafeContext(AppleCSPSession
&session
)
42 : AppleCSPContext(session
)
59 BSafe::BSafeContext::~BSafeContext()
64 void BSafe::BSafeContext::reset()
66 B_DestroyAlgorithmObject(&bsAlgorithm
);
67 B_DestroyAlgorithmObject(&bsRandom
);
72 * Clear key state. We only destroy bsKey if we don't have a
75 void BSafe::BSafeContext::destroyBsKey()
77 if(bsBinKey
== NULL
) {
78 B_DestroyKeyObject(&bsKey
);
81 // bsKey gets destroyed when bsBinKey gets deleted
87 void BSafe::check(int status
, bool isKeyOp
)
92 dprintf1("BSAFE Error %d\n", status
);
95 throw std::bad_alloc();
97 CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED
);
99 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
);
101 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR
);
102 case BE_EXPONENT_EVEN
:
103 case BE_EXPONENT_LEN
:
104 case BE_EXPONENT_ONE
:
105 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
109 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
112 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA
);
120 //@@@ translate BSafe errors intelligently
121 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
126 void BSafe::BSafeContext::setAlgorithm(
127 B_INFO_TYPE bAlgType
,
130 B_DestroyAlgorithmObject(&bsAlgorithm
); // clear any old BSafe algorithm
131 check(B_CreateAlgorithmObject(&bsAlgorithm
));
132 check(B_SetAlgorithmInfo(bsAlgorithm
, bAlgType
, POINTER(info
)));
135 /* safely create bsKey */
136 void BSafe::BSafeContext::createBsKey()
138 /* reset to initial key state - some keys can't be reused */
140 check(B_CreateKeyObject(&bsKey
));
143 /* form of *info varies per bKeyInfo */
144 void BSafe::BSafeContext::setKeyAtom(
145 B_INFO_TYPE bKeyInfo
,
149 if((bKeyInfo
== KI_RSAPublicBER
) || (bKeyInfo
== KI_RSAPublic
)) {
150 printf("Aargh! Unhandled KI_RSAPublic!\n");
151 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
153 assert(bKeyInfo
!= KI_RSAPublicBER
); // handled elsewhere for now
154 assert(bKeyInfo
!= KI_RSAPublic
); // handled elsewhere for now
156 check(B_SetKeyInfo(bsKey
, bKeyInfo
, POINTER(info
)), true);
160 // Set outSize for RSA keys.
162 void BSafe::BSafeContext::setRsaOutSize(
165 assert(bsKey
!= NULL
);
169 keyInfo
= getKey
<A_RSA_KEY
>(bsKey
, KI_RSAPublic
);
172 keyInfo
= getKey
<A_RSA_KEY
>(bsKey
, KI_RSAPrivate
);
174 mOutSize
= (B_IntegerBits(keyInfo
->modulus
.data
,
175 keyInfo
->modulus
.len
) + 7) / 8;
179 // Handle various forms of reference key. Symmetric
180 // keys are stored as SymmetricBinaryKey, with raw key bytes
181 // in keyData. Our asymmetric keys are stored as BSafeBinaryKeys,
182 // with an embedded ready-to-use B_KEY_OBJ.
184 void BSafe::BSafeContext::setRefKey(CssmKey
&key
)
186 bool isPubKey
= false;
188 switch(key
.keyClass()) {
189 case CSSM_KEYCLASS_SESSION_KEY
:
191 assert(key
.blobFormat() ==
192 CSSM_KEYBLOB_REF_FORMAT_INTEGER
);
194 BinaryKey
&binKey
= session().lookupRefKey(key
);
195 // fails if this is not a SymmetricBinaryKey
196 SymmetricBinaryKey
*symBinKey
=
197 dynamic_cast<SymmetricBinaryKey
*>(&binKey
);
198 if(symBinKey
== NULL
) {
199 errorLog0("BSafe::setRefKey(1): wrong BinaryKey subclass\n");
200 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
202 setKeyFromCssmData(KI_Item
, symBinKey
->mKeyData
);
205 case CSSM_KEYCLASS_PUBLIC_KEY
:
206 isPubKey
= true; // and fall thru
207 case CSSM_KEYCLASS_PRIVATE_KEY
:
209 BinaryKey
&binKey
= session().lookupRefKey(key
);
211 bsBinKey
= dynamic_cast<BSafeBinaryKey
*>(&binKey
);
212 /* this cast failing means that this is some other
213 * kind of binary key */
214 if(bsBinKey
== NULL
) {
215 errorLog0("BSafe::setRefKey(2): wrong BinaryKey subclass\n");
216 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
218 assert(bsBinKey
->bsKey() != NULL
);
219 bsKey
= bsBinKey
->bsKey();
220 if(key
.algorithm() == CSSM_ALGID_RSA
) {
221 setRsaOutSize(isPubKey
);
226 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
230 void BSafe::BSafeContext::setKeyFromContext(
231 const Context
&context
,
235 context
.get
<CssmKey
>(CSSM_ATTRIBUTE_KEY
, CSSMERR_CSP_MISSING_ATTR_KEY
);
237 switch(key
.blobType()) {
238 case CSSM_KEYBLOB_REFERENCE
:
241 case CSSM_KEYBLOB_RAW
:
242 break; // to main routine
244 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT
);
248 switch (key
.keyClass()) {
249 case CSSM_KEYCLASS_SESSION_KEY
:
250 /* symmetric, one format supported for all algs */
251 switch (key
.blobFormat()) {
252 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
:
253 setKeyFromCssmKey(KI_Item
, key
);
256 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
258 case CSSM_KEYCLASS_PUBLIC_KEY
:
261 case CSSM_KEYCLASS_PRIVATE_KEY
:
265 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
268 /* We know it's an asymmetric key; get some info */
269 B_INFO_TYPE infoType
;
270 CSSM_KEYBLOB_FORMAT expectedFormat
;
272 if(!bsafeAlgToInfoType(key
.algorithm(),
277 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
282 * NOTE: if we end up supporting multiple incoming key formats, they'll
283 * have to be handled here.
285 if(expectedFormat
!= key
.blobFormat()) {
286 errorLog1("setKeyFromContext: invalid blob format (%d)\n",
287 (int)key
.blobFormat());
288 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
292 * Most formats can be handled directly by BSAFE. Handle the special cases
293 * requiring additional processing here.
295 switch(expectedFormat
) {
296 case CSSM_KEYBLOB_RAW_FORMAT_PKCS1
:
297 /* RSA public keys */
299 BS_setKeyPkcs1(CssmData::overlay(key
.KeyData
), bsKey
);
302 setKeyFromCssmKey(infoType
, key
);
307 * One more thing - set mOutSize for RSA keys
309 if(key
.algorithm() == CSSM_ALGID_RSA
) {
310 setRsaOutSize(isPubKey
);
314 #define BSAFE_RANDSIZE 32
316 void BSafe::BSafeContext::setRandom()
318 if (bsRandom
== NULL
) {
319 check(B_CreateAlgorithmObject(&bsRandom
));
320 check(B_SetAlgorithmInfo(bsRandom
, AI_X962Random_V0
, NULL_PTR
));
321 check(B_RandomInit(bsRandom
, chooser(), bsSurrender
));
322 uint8 seed
[BSAFE_RANDSIZE
];
323 session().getRandomBytes(BSAFE_RANDSIZE
, seed
);
324 check(B_RandomUpdate(bsRandom
, seed
, sizeof(seed
), bsSurrender
));
330 // Operational methods of BSafeContext
332 void BSafe::BSafeContext::init(const Context
&, bool)
334 // some algorithms don't need init(), because all is done in the context constructor
337 // update for input-only block/stream algorithms
338 void BSafe::BSafeContext::update(const CssmData
&data
)
341 check(inUpdate(bsAlgorithm
, POINTER(data
.data()), data
.length(), bsSurrender
));
344 // update for input/output block/stream algorithms
345 void BSafe::BSafeContext::update(void *inp
, size_t &inSize
, void *outp
, size_t &outSize
)
349 check(inOutUpdate(bsAlgorithm
, POINTER(outp
), &length
, outSize
,
350 POINTER(inp
), inSize
, bsRandom
, bsSurrender
));
351 // always eat all input (inSize unchanged)
354 // let the algorithm manager track I/O sizes, if needed
355 trackUpdate(inSize
, outSize
);
358 // output-generating final call
359 void BSafe::BSafeContext::final(CssmData
&out
)
363 check(outFinal(bsAlgorithm
,
370 check(outFinalR(bsAlgorithm
,
381 // verifying final call (takes additional input)
382 void BSafe::BSafeContext::final(const CssmData
&in
)
386 /* note sig verify errors can show up as lots of BSAFE statuses;
387 * munge them all into the appropriate error */
389 status
= inFinal(bsAlgorithm
,
395 status
= inFinalR(bsAlgorithm
,
402 if((mType
== CSSM_ALGCLASS_SIGNATURE
) && (mDirection
== false)) {
403 /* yep, sig verify error */
404 CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED
);
406 /* other error, use standard trap */
412 size_t BSafe::BSafeContext::outputSize(bool final
, size_t inSize
)
414 // this default implementation only makes sense for single-output end-loaded algorithms
415 return final
? mOutSize
: 0;
418 void BSafe::BSafeContext::trackUpdate(size_t, size_t)
422 // Common features of CipherContexts.
424 void BSafe::CipherContext::cipherInit()
428 inOutUpdate
= B_EncryptUpdate
;
429 outFinalR
= B_EncryptFinal
;
431 inOutUpdate
= B_DecryptUpdate
;
432 outFinalR
= B_DecryptFinal
;
436 // init the algorithm
437 check((encoding
? B_EncryptInit
: B_DecryptInit
)
438 (bsAlgorithm
, bsKey
, chooser(), bsSurrender
));
440 // buffers start empty
443 // state is now valid
447 #endif /* BSAFE_CSP_ENABLE */