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.
20 // AppleCSPUtils.cpp - CSP-wide utility functions
23 #include "AppleCSPUtils.h"
24 #include <Security/cssmerr.h>
25 #include <Security/utilities.h>
26 #include <Security/cssmalloc.h>
28 #include <CryptKitCSP/FEECSPUtils.h>
29 #include <MiscCSPAlgs/SHA1_MD5_Object.h>
32 * Validate key attribute bits per specified key type.
34 * Used to check requested key attributes for new keys and for validating
35 * incoming existing keys. For checking key attributes for new keys,
36 * assumes that KEYATTR_RETURN_xxx bits have been checked elsewhere
37 * and stripped off before coming here.
39 void cspValidateKeyAttr(
43 uint32 sensitiveBit
= (keyAttr
& CSSM_KEYATTR_SENSITIVE
) ? 1 : 0;
44 uint32 extractBit
= (keyAttr
& CSSM_KEYATTR_EXTRACTABLE
) ? 1 : 0;
46 /* first general CSP-wide checks */
47 if(keyAttr
& KEY_ATTR_RETURN_MASK
) {
48 //errorLog0(" KEY_ATTR_RETURN bits set\n");
49 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
51 if(keyAttr
& CSSM_KEYATTR_PERMANENT
) {
52 //errorLog0(" PERMANENT bit not supported\n");
53 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
);
55 if(keyAttr
& CSSM_KEYATTR_PRIVATE
) {
56 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
);
60 /* now check per keyType */
66 if(sensitiveBit
|| !extractBit
) {
67 //errorLog0("Public keys must be extractable in the clear\n");
68 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
74 // errorLog0("Private keys must have KEYATTR_SENSITIVE\n");
75 // CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
79 * One more restriction - EXTRACTABLE - caller must check since
80 * that involves KEYUSE bits.
84 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
90 * Perform sanity check of incoming key attribute bits for a given
91 * key type, and return a cspKeyStorage value.
93 * Called from any routine which generates a new key. This specifically
96 cspKeyStorage
cspParseKeyAttr(
100 uint32 sensitiveBit
= (keyAttr
& CSSM_KEYATTR_SENSITIVE
) ? 1 : 0;
101 uint32 rtnDataBit
= (keyAttr
& CSSM_KEYATTR_RETURN_DATA
) ? 1 : 0;
102 uint32 rtnRefBit
= (keyAttr
& CSSM_KEYATTR_RETURN_REF
) ? 1 : 0;
103 uint32 extractBit
= (keyAttr
& CSSM_KEYATTR_EXTRACTABLE
) ? 1 : 0;
107 /* first general CDSA-wide checks */
108 if(keyAttr
& (CSSM_KEYATTR_ALWAYS_SENSITIVE
|
109 CSSM_KEYATTR_NEVER_EXTRACTABLE
)) {
110 //errorLog0("ALWAYS_SENSITIVE, NEVER_EXTRACTABLE illegal at SPI\n");
111 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
113 switch(keyAttr
& KEY_ATTR_RETURN_MASK
) {
114 /* ensure only one bit is set */
115 case CSSM_KEYATTR_RETURN_DATA
:
118 case CSSM_KEYATTR_RETURN_REF
:
121 case CSSM_KEYATTR_RETURN_NONE
:
124 case CSSM_KEYATTR_RETURN_DEFAULT
:
130 //errorLog0("Multiple KEYATTR_RETURN bits set\n");
131 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
134 /* now CSP-wide checks for all key types */
135 if(keyType
!= CKT_Session
) {
136 /* session keys modifiable, no others are */
137 if(keyAttr
& CSSM_KEYATTR_MODIFIABLE
) {
138 //errorLog0("CSSM_KEYATTR_MODIFIABLE not supported\n");
139 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
144 //errorLog0("RETURN_DATA and !EXTRACTABLE not supported\n");
145 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
148 //errorLog0("RETURN_DATA and SENSITIVE not supported\n");
149 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
153 /* now check per keyType. We're ust checking for things specific
154 * to KEYATTR_RETURN_xxx; cspValidateKeyAttr will check other fields. */
166 errorLog0("Private keys must be generated by ref\n");
170 * One more restriction - EXTRACTABLE - caller must check since
171 * that involves KEYUSE bits.
175 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
179 /* validate other common static attributes */
180 cspValidateKeyAttr(keyType
, (keyAttr
& ~KEY_ATTR_RETURN_MASK
));
185 /* used in cspValidateKeyUsageBits() */
187 * This is a vestige from OS9/ASA. In the real world there are in fact certs with
188 * keyUsage extensions which specify, e.g., verify and wrap. I think we'll just
189 * have to ignore the old exclusivity rules.
191 #define IGNORE_KEYUSE_EXCLUSIVITY 1
192 #if IGNORE_KEYUSE_EXCLUSIVITY
193 #define checkExclusiveUsage(ku, cb, ob, em)
195 static void checkExclusiveUsage(
196 uint32 keyUsage
, // requested usage word
197 uint32 checkBits
, // if any of these are set
198 uint32 otherBits
, // these are the only other bits which can be set
201 if(keyUsage
& checkBits
) {
202 if(keyUsage
& ~otherBits
) {
203 errorLog0((char *)errMsg
);
204 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
208 #endif /* IGNORE_KEYUSE_EXCLUSIVITY */
211 * Validate key usage bits for specified key type.
213 void cspValidateKeyUsageBits (
217 /* general restrictions */
218 checkExclusiveUsage(keyUsage
,
221 "CSSM_KEYUSE_ANY overload");
222 checkExclusiveUsage(keyUsage
,
225 "CSSM_KEYUSE_DERIVE overload\n");
227 /* brute force per key type. */
230 checkExclusiveUsage(keyUsage
,
231 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
232 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
233 "session key usage: encrypt/decrypt overload\n");
234 checkExclusiveUsage(keyUsage
,
235 CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
|
236 CSSM_KEYUSE_SIGN_RECOVER
| CSSM_KEYUSE_VERIFY_RECOVER
,
237 CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
|
238 CSSM_KEYUSE_SIGN_RECOVER
| CSSM_KEYUSE_VERIFY_RECOVER
,
239 "session key usage: sign/verify overload\n");
240 checkExclusiveUsage(keyUsage
,
241 CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
,
242 CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
,
243 "session key usage: wrap/unwrap overload\n");
247 checkExclusiveUsage(keyUsage
,
250 "public key usage: encrypt overload\n");
251 if(keyUsage
& CSSM_KEYUSE_DECRYPT
) {
252 errorLog0("public key usage: DECRYPT illegal\n");
253 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
255 if(keyUsage
& (CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_SIGN_RECOVER
)) {
256 errorLog0("public key usage: SIGN illegal\n");
257 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
259 checkExclusiveUsage(keyUsage
,
260 CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_VERIFY_RECOVER
,
261 CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_VERIFY_RECOVER
,
262 "public key usage: verify overload\n");
263 checkExclusiveUsage(keyUsage
,
266 "public key usage: wrap overload\n");
267 if(keyUsage
& CSSM_KEYUSE_UNWRAP
) {
268 errorLog0("public key usage: UNWRAP illegal\n");
269 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
274 if(keyUsage
& CSSM_KEYUSE_ENCRYPT
) {
275 errorLog0("private key usage: ENCRYPT illegal\n");
276 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
278 checkExclusiveUsage(keyUsage
,
281 "private key usage: decrypt overload\n");
282 checkExclusiveUsage(keyUsage
,
283 CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_SIGN_RECOVER
,
284 CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_SIGN_RECOVER
,
285 "private key usage: sign overload\n");
286 if(keyUsage
& (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_VERIFY_RECOVER
)) {
287 errorLog0("private key usage: VERIFY illegal\n");
288 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
290 if(keyUsage
& CSSM_KEYUSE_WRAP
) {
291 errorLog0("private key usage: WRAP illegal\n");
292 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
294 checkExclusiveUsage(keyUsage
,
297 "private key usage: unwrap overload\n");
300 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
305 * Validate existing key's usage bits against intended use.
309 * For now, a key marked for KEYUSE_{WRAP|UNWRAP} can also be used for
310 * KEYUSE_{ENCRYPT|DECRYPT}. This is a temporary workaround for
313 #define RELAXED_WRAP_USAGE 1
315 void cspValidateIntendedKeyUsage(
316 const CSSM_KEYHEADER
*hdr
,
317 CSSM_KEYUSE intendedUsage
)
319 uint32 keyUsage
= hdr
->KeyUsage
;
322 /* first, the obvious */
323 if(keyUsage
& CSSM_KEYUSE_ANY
) {
327 if(!(keyUsage
& intendedUsage
)) {
328 #if RELAXED_WRAP_USAGE
329 if(! ( ( (keyUsage
& CSSM_KEYUSE_WRAP
) &&
330 (intendedUsage
== CSSM_KEYUSE_ENCRYPT
)
332 ( (keyUsage
& CSSM_KEYUSE_UNWRAP
) &&
333 (intendedUsage
== CSSM_KEYUSE_DECRYPT
)
337 CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT
);
340 /* now validate all of the key's usage bits - this is mainly to
341 * prevent and detect tampering */
342 switch(hdr
->KeyClass
) {
343 case CSSM_KEYCLASS_SESSION_KEY
:
344 keyType
= CKT_Session
;
346 case CSSM_KEYCLASS_PUBLIC_KEY
:
347 keyType
= CKT_Public
;
349 case CSSM_KEYCLASS_PRIVATE_KEY
:
350 keyType
= CKT_Private
;
353 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
356 cspValidateKeyUsageBits(keyType
, keyUsage
);
359 /* override error.... */
360 CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT
);
365 * Set up a key header.
371 CSSM_KEYCLASS keyClass
,
372 CSSM_KEYATTR_FLAGS attrs
,
375 memset(&hdr
, 0, sizeof(CSSM_KEYHEADER
));
376 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
378 hdr
.AlgorithmId
= alg
;
379 hdr
.KeyClass
= keyClass
;
383 // defaults (change as needed)
384 hdr
.WrapAlgorithmId
= CSSM_ALGID_NONE
;
388 * Ensure that indicated CssmData can handle 'length' bytes
389 * of data. Malloc the Data ptr if necessary.
394 CssmAllocator
&allocator
)
396 /* FIXME - I'm sure Perry has more elegant ways of doing this,
397 * but I can't figure them out. */
398 if(data
.Length
== 0) {
399 data
.Data
= (uint8
*)allocator
.malloc(length
);
401 else if(data
.Length
< length
) {
402 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA
);
404 data
.Length
= length
;
410 CssmAllocator
&allocator
)
412 setUpCssmData(CssmData::overlay(data
), length
, allocator
);
417 CssmAllocator
&allocator
)
420 allocator
.free(data
.Data
);
428 CssmAllocator
&allocator
,
429 bool freeStruct
) // free the CSSM_DATA itself
435 allocator
.free(data
->Data
);
440 allocator
.free(data
);
445 * Copy source to destination, mallocing destination if necessary.
450 CssmAllocator
&allocator
)
452 setUpCssmData(dst
, src
.Length
, allocator
);
453 memmove(dst
.Data
, src
.Data
, src
.Length
);
457 const CSSM_DATA
&src
,
459 CssmAllocator
&allocator
)
461 copyCssmData(CssmData::overlay(src
),
462 CssmData::overlay(dst
),
467 * This takes care of mallocing the KeyLabel field.
470 const CssmKey::Header
&src
,
471 CssmKey::Header
&dst
,
472 CssmAllocator
&allocator
)
478 * Given a wrapped key, infer its raw format.
479 * This is a real kludge; it only works as long as each {algorithm, keyClass}
480 * maps to exactly one format.
482 CSSM_KEYBLOB_FORMAT
inferFormat(
483 const CssmKey
&wrappedKey
)
485 switch(wrappedKey
.keyClass()) {
486 case CSSM_KEYCLASS_SESSION_KEY
:
487 return CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;
488 case CSSM_KEYCLASS_PUBLIC_KEY
:
489 switch(wrappedKey
.algorithm()) {
491 return CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
493 return CSSM_KEYBLOB_RAW_FORMAT_FIPS186
;
494 #ifdef CRYPTKIT_CSP_ENABLE
496 return FEE_KEYBLOB_DEFAULT_FORMAT
;
500 return CSSM_KEYBLOB_RAW_FORMAT_NONE
;
502 case CSSM_KEYCLASS_PRIVATE_KEY
:
503 switch(wrappedKey
.algorithm()) {
505 return CSSM_KEYBLOB_RAW_FORMAT_PKCS8
;
507 return CSSM_KEYBLOB_RAW_FORMAT_FIPS186
;
508 #ifdef CRYPTKIT_CSP_ENABLE
510 return FEE_KEYBLOB_DEFAULT_FORMAT
;
514 return CSSM_KEYBLOB_RAW_FORMAT_NONE
;
518 return CSSM_KEYBLOB_RAW_FORMAT_NONE
;
523 * Given a key and a Context, obtain the optional associated
524 * CSSM_ATTRIBUTE_{PUBLIC,PRIVATE,SYMMETRIC}_KEY_FORMAT attribute as a
525 * CSSM_KEYBLOB_FORMAT.
527 CSSM_KEYBLOB_FORMAT
requestedKeyFormat(
528 const Context
&context
,
531 CSSM_ATTRIBUTE_TYPE attrType
;
533 switch(key
.keyClass()) {
534 case CSSM_KEYCLASS_SESSION_KEY
:
535 attrType
= CSSM_ATTRIBUTE_SYMMETRIC_KEY_FORMAT
;
537 case CSSM_KEYCLASS_PUBLIC_KEY
:
538 attrType
= CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT
;
540 case CSSM_KEYCLASS_PRIVATE_KEY
:
541 attrType
= CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT
;
544 return CSSM_KEYBLOB_RAW_FORMAT_NONE
;
546 /* not present ==> 0 ==> CSSM_KEYBLOB_RAW_FORMAT_NONE */
547 return context
.getInt(attrType
);
550 /* one-shot SHA1 digest */
554 void *out
) // caller mallocs, digest goes here
559 sha1
.digestUpdate(inData
, inDataLen
);
560 sha1
.digestFinal(out
);