2 * Copyright (c) 2000-2001,2011,2014 Apple 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/alloc.h>
26 #include <security_cdsa_utilities/cssmdates.h>
28 #include <FEECSPUtils.h>
29 #include <SHA1_MD5_Object.h>
30 #include "RSA_DSA_keys.h"
34 * Validate key attribute bits per specified key type.
36 * Used to check requested key attributes for new keys and for validating
37 * incoming existing keys. For checking key attributes for new keys,
38 * assumes that KEYATTR_RETURN_xxx bits have been checked elsewhere
39 * and stripped off before coming here.
41 void cspValidateKeyAttr(
45 uint32 sensitiveBit
= (keyAttr
& CSSM_KEYATTR_SENSITIVE
) ? 1 : 0;
46 uint32 extractBit
= (keyAttr
& CSSM_KEYATTR_EXTRACTABLE
) ? 1 : 0;
48 /* first general CSP-wide checks */
49 if(keyAttr
& KEY_ATTR_RETURN_MASK
) {
50 //errorLog0(" KEY_ATTR_RETURN bits set\n");
51 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
53 if(keyAttr
& CSSM_KEYATTR_PERMANENT
) {
54 //errorLog0(" PERMANENT bit not supported\n");
55 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
);
57 if(keyAttr
& CSSM_KEYATTR_PRIVATE
) {
58 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
);
62 /* now check per keyType */
68 if(sensitiveBit
|| !extractBit
) {
69 //errorLog0("Public keys must be extractable in the clear\n");
70 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
76 // errorLog0("Private keys must have KEYATTR_SENSITIVE\n");
77 // CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
81 * One more restriction - EXTRACTABLE - caller must check since
82 * that involves KEYUSE bits.
86 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
92 * Perform sanity check of incoming key attribute bits for a given
93 * key type, and return a cspKeyStorage value.
95 * Called from any routine which generates a new key. This specifically
98 cspKeyStorage
cspParseKeyAttr(
102 uint32 sensitiveBit
= (keyAttr
& CSSM_KEYATTR_SENSITIVE
) ? 1 : 0;
103 uint32 rtnDataBit
= (keyAttr
& CSSM_KEYATTR_RETURN_DATA
) ? 1 : 0;
104 uint32 rtnRefBit
= (keyAttr
& CSSM_KEYATTR_RETURN_REF
) ? 1 : 0;
105 uint32 extractBit
= (keyAttr
& CSSM_KEYATTR_EXTRACTABLE
) ? 1 : 0;
109 /* first general CDSA-wide checks */
110 if(keyAttr
& (CSSM_KEYATTR_ALWAYS_SENSITIVE
|
111 CSSM_KEYATTR_NEVER_EXTRACTABLE
)) {
112 //errorLog0("ALWAYS_SENSITIVE, NEVER_EXTRACTABLE illegal at SPI\n");
113 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
115 switch(keyAttr
& KEY_ATTR_RETURN_MASK
) {
116 /* ensure only one bit is set */
117 case CSSM_KEYATTR_RETURN_DATA
:
120 case CSSM_KEYATTR_RETURN_REF
:
123 case CSSM_KEYATTR_RETURN_NONE
:
126 case CSSM_KEYATTR_RETURN_DEFAULT
:
132 //errorLog0("Multiple KEYATTR_RETURN bits set\n");
133 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
136 /* now CSP-wide checks for all key types */
137 if(keyType
!= CKT_Session
) {
138 /* session keys modifiable, no others are */
139 if(keyAttr
& CSSM_KEYATTR_MODIFIABLE
) {
140 //errorLog0("CSSM_KEYATTR_MODIFIABLE not supported\n");
141 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
146 //errorLog0("RETURN_DATA and !EXTRACTABLE not supported\n");
147 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
150 //errorLog0("RETURN_DATA and SENSITIVE not supported\n");
151 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
155 /* now check per keyType. We're ust checking for things specific
156 * to KEYATTR_RETURN_xxx; cspValidateKeyAttr will check other fields. */
168 errorLog0("Private keys must be generated by ref\n");
172 * One more restriction - EXTRACTABLE - caller must check since
173 * that involves KEYUSE bits.
177 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
181 /* validate other common static attributes */
182 cspValidateKeyAttr(keyType
, (keyAttr
& ~KEY_ATTR_RETURN_MASK
));
187 /* used in cspValidateKeyUsageBits() */
189 * This is a vestige from OS9/ASA. In the real world there are in fact certs with
190 * keyUsage extensions which specify, e.g., verify and wrap. I think we'll just
191 * have to ignore the old exclusivity rules.
193 #define IGNORE_KEYUSE_EXCLUSIVITY 1
194 #if IGNORE_KEYUSE_EXCLUSIVITY
195 #define checkExclusiveUsage(ku, cb, ob, em)
197 static void checkExclusiveUsage(
198 uint32 keyUsage
, // requested usage word
199 uint32 checkBits
, // if any of these are set
200 uint32 otherBits
, // these are the only other bits which can be set
203 if(keyUsage
& checkBits
) {
204 if(keyUsage
& ~otherBits
) {
205 errorLog0((char *)errMsg
);
206 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
210 #endif /* IGNORE_KEYUSE_EXCLUSIVITY */
213 * Validate key usage bits for specified key type.
215 void cspValidateKeyUsageBits (
219 /* general restrictions */
220 checkExclusiveUsage(keyUsage
,
223 "CSSM_KEYUSE_ANY overload");
224 checkExclusiveUsage(keyUsage
,
227 "CSSM_KEYUSE_DERIVE overload\n");
229 /* brute force per key type. */
232 checkExclusiveUsage(keyUsage
,
233 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
234 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
235 "session key usage: encrypt/decrypt overload\n");
236 checkExclusiveUsage(keyUsage
,
237 CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
|
238 CSSM_KEYUSE_SIGN_RECOVER
| CSSM_KEYUSE_VERIFY_RECOVER
,
239 CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
|
240 CSSM_KEYUSE_SIGN_RECOVER
| CSSM_KEYUSE_VERIFY_RECOVER
,
241 "session key usage: sign/verify overload\n");
242 checkExclusiveUsage(keyUsage
,
243 CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
,
244 CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
,
245 "session key usage: wrap/unwrap overload\n");
249 checkExclusiveUsage(keyUsage
,
252 "public key usage: encrypt overload\n");
253 if(keyUsage
& CSSM_KEYUSE_DECRYPT
) {
254 errorLog0("public key usage: DECRYPT illegal\n");
255 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
257 if(keyUsage
& (CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_SIGN_RECOVER
)) {
258 errorLog0("public key usage: SIGN illegal\n");
259 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
261 checkExclusiveUsage(keyUsage
,
262 CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_VERIFY_RECOVER
,
263 CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_VERIFY_RECOVER
,
264 "public key usage: verify overload\n");
265 checkExclusiveUsage(keyUsage
,
268 "public key usage: wrap overload\n");
269 if(keyUsage
& CSSM_KEYUSE_UNWRAP
) {
270 errorLog0("public key usage: UNWRAP illegal\n");
271 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
276 if(keyUsage
& CSSM_KEYUSE_ENCRYPT
) {
277 errorLog0("private key usage: ENCRYPT illegal\n");
278 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
280 checkExclusiveUsage(keyUsage
,
283 "private key usage: decrypt overload\n");
284 checkExclusiveUsage(keyUsage
,
285 CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_SIGN_RECOVER
,
286 CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_SIGN_RECOVER
,
287 "private key usage: sign overload\n");
288 if(keyUsage
& (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_VERIFY_RECOVER
)) {
289 errorLog0("private key usage: VERIFY illegal\n");
290 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
292 if(keyUsage
& CSSM_KEYUSE_WRAP
) {
293 errorLog0("private key usage: WRAP illegal\n");
294 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK
);
296 checkExclusiveUsage(keyUsage
,
299 "private key usage: unwrap overload\n");
302 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
307 * Validate existing key's usage bits against intended use.
311 * For now, a key marked for KEYUSE_{WRAP|UNWRAP} can also be used for
312 * KEYUSE_{ENCRYPT|DECRYPT}. This is a temporary workaround for
315 #define RELAXED_WRAP_USAGE 1
317 void cspValidateIntendedKeyUsage(
318 const CSSM_KEYHEADER
*hdr
,
319 CSSM_KEYUSE intendedUsage
)
321 uint32 keyUsage
= hdr
->KeyUsage
;
324 /* first, the obvious */
325 if(keyUsage
& CSSM_KEYUSE_ANY
) {
329 if(!(keyUsage
& intendedUsage
)) {
330 #if RELAXED_WRAP_USAGE
331 if(! ( ( (keyUsage
& CSSM_KEYUSE_WRAP
) &&
332 (intendedUsage
== CSSM_KEYUSE_ENCRYPT
)
334 ( (keyUsage
& CSSM_KEYUSE_UNWRAP
) &&
335 (intendedUsage
== CSSM_KEYUSE_DECRYPT
)
339 CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT
);
342 /* now validate all of the key's usage bits - this is mainly to
343 * prevent and detect tampering */
344 switch(hdr
->KeyClass
) {
345 case CSSM_KEYCLASS_SESSION_KEY
:
346 keyType
= CKT_Session
;
348 case CSSM_KEYCLASS_PUBLIC_KEY
:
349 keyType
= CKT_Public
;
351 case CSSM_KEYCLASS_PRIVATE_KEY
:
352 keyType
= CKT_Private
;
355 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
358 cspValidateKeyUsageBits(keyType
, keyUsage
);
361 /* override error.... */
362 CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT
);
367 * Set up a key header.
373 CSSM_KEYCLASS keyClass
,
374 CSSM_KEYATTR_FLAGS attrs
,
377 memset(&hdr
, 0, sizeof(CSSM_KEYHEADER
));
378 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
380 hdr
.AlgorithmId
= alg
;
381 hdr
.KeyClass
= keyClass
;
385 // defaults (change as needed)
386 hdr
.WrapAlgorithmId
= CSSM_ALGID_NONE
;
390 * Ensure that indicated CssmData can handle 'length' bytes
391 * of data. Malloc the Data ptr if necessary.
396 Allocator
&allocator
)
398 /* FIXME - I'm sure Perry has more elegant ways of doing this,
399 * but I can't figure them out. */
400 if(data
.Length
== 0) {
401 data
.Data
= (uint8
*)allocator
.malloc(length
);
403 else if(data
.Length
< length
) {
404 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA
);
406 data
.Length
= length
;
412 Allocator
&allocator
)
414 setUpCssmData(CssmData::overlay(data
), length
, allocator
);
419 Allocator
&allocator
)
422 allocator
.free(data
.Data
);
430 Allocator
&allocator
,
431 bool freeStruct
) // free the CSSM_DATA itself
437 allocator
.free(data
->Data
);
442 allocator
.free(data
);
447 * Copy source to destination, mallocing destination if necessary.
452 Allocator
&allocator
)
454 setUpCssmData(dst
, src
.Length
, allocator
);
455 memmove(dst
.Data
, src
.Data
, src
.Length
);
459 const CSSM_DATA
&src
,
461 Allocator
&allocator
)
463 copyCssmData(CssmData::overlay(src
),
464 CssmData::overlay(dst
),
469 * Compare two CSSM_DATAs, return CSSM_TRUE if identical.
471 CSSM_BOOL
cspCompareCssmData(
472 const CSSM_DATA
*data1
,
473 const CSSM_DATA
*data2
)
475 if((data1
== NULL
) || (data1
->Data
== NULL
) ||
476 (data2
== NULL
) || (data2
->Data
== NULL
) ||
477 (data1
->Length
!= data2
->Length
)) {
480 if(data1
->Length
!= data2
->Length
) {
483 if(memcmp(data1
->Data
, data2
->Data
, data1
->Length
) == 0) {
492 * This takes care of mallocing the KeyLabel field.
495 const CssmKey::Header
&src
,
496 CssmKey::Header
&dst
,
497 Allocator
&allocator
)
503 * Given a wrapped key, infer its raw format for custom Apple unwrapping.
504 * This is a real kludge; it only works as long as each the key's
505 * default format is used to generate the blob to be wrapped.
507 CSSM_KEYBLOB_FORMAT
inferFormat(
508 const CssmKey
&wrappedKey
)
510 switch(wrappedKey
.keyClass()) {
511 case CSSM_KEYCLASS_SESSION_KEY
:
512 return CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;
513 case CSSM_KEYCLASS_PUBLIC_KEY
:
514 switch(wrappedKey
.algorithm()) {
516 return RSA_PUB_KEY_FORMAT
;
518 return DSA_PUB_KEY_FORMAT
;
519 #ifdef CRYPTKIT_CSP_ENABLE
521 return FEE_KEYBLOB_DEFAULT_FORMAT
;
522 case CSSM_ALGID_ECDSA
:
523 return CSSM_KEYBLOB_RAW_FORMAT_X509
;
526 return CSSM_KEYBLOB_RAW_FORMAT_PKCS3
;
529 return CSSM_KEYBLOB_RAW_FORMAT_NONE
;
531 case CSSM_KEYCLASS_PRIVATE_KEY
:
532 switch(wrappedKey
.algorithm()) {
534 return RSA_PRIV_KEY_FORMAT
;
536 return DSA_PRIV_KEY_FORMAT
;
537 #ifdef CRYPTKIT_CSP_ENABLE
539 return FEE_KEYBLOB_DEFAULT_FORMAT
;
540 case CSSM_ALGID_ECDSA
:
541 return CSSM_KEYBLOB_RAW_FORMAT_OPENSSL
;
544 return CSSM_KEYBLOB_RAW_FORMAT_PKCS3
;
547 return CSSM_KEYBLOB_RAW_FORMAT_NONE
;
551 return CSSM_KEYBLOB_RAW_FORMAT_NONE
;
556 * Given a key and a Context, obtain the optional associated
557 * CSSM_ATTRIBUTE_{PUBLIC,PRIVATE,SYMMETRIC}_KEY_FORMAT attribute as a
558 * CSSM_KEYBLOB_FORMAT.
560 CSSM_KEYBLOB_FORMAT
requestedKeyFormat(
561 const Context
&context
,
564 CSSM_ATTRIBUTE_TYPE attrType
;
566 switch(key
.keyClass()) {
567 case CSSM_KEYCLASS_SESSION_KEY
:
568 attrType
= CSSM_ATTRIBUTE_SYMMETRIC_KEY_FORMAT
;
570 case CSSM_KEYCLASS_PUBLIC_KEY
:
571 attrType
= CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT
;
573 case CSSM_KEYCLASS_PRIVATE_KEY
:
574 attrType
= CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT
;
577 return CSSM_KEYBLOB_RAW_FORMAT_NONE
;
579 /* not present ==> 0 ==> CSSM_KEYBLOB_RAW_FORMAT_NONE */
580 return context
.getInt(attrType
);
583 /* one-shot SHA1 digest */
587 void *out
) // caller mallocs, digest goes here
592 sha1
.digestUpdate(inData
, inDataLen
);
593 sha1
.digestFinal(out
);
597 * Convert a CSSM_DATE to a CssmUniformDate, or NULL if the CSSM_DATE
600 static CssmUniformDate
*cspGetUniformDate(
601 const CSSM_DATE
&cdate
)
604 unsigned char *cp
= (unsigned char *)&cdate
;
605 for(unsigned i
=0; i
<sizeof(cdate
); i
++) {
615 return new CssmUniformDate(CssmDate::overlay(cdate
));
620 * Get "now" as a CssmUniformDate.
622 static CssmUniformDate
*cspNow()
624 CFAbsoluteTime cfTime
= CFAbsoluteTimeGetCurrent();
625 return new CssmUniformDate(cfTime
);
628 #define keyDateDebug(args...) secinfo("keyDate", ## args)
631 * Verify temporal validity of specified key.
632 * An empty (all zero) time field means "ignore this".
633 * Throws CSSMERR_CSP_APPLE_INVALID_KEY_START_DATE or
634 * CSSMERR_CSP_APPLE_INVALID_KEY_END_DATE as appropriate.
636 void cspVerifyKeyTimes(
637 const CSSM_KEYHEADER
&hdr
)
639 CSSM_RETURN err
= CSSM_OK
;
640 CssmUniformDate
*now
= NULL
; // evaluate lazily
641 CssmUniformDate
*end
= NULL
; // ditto
642 CssmUniformDate
*start
= cspGetUniformDate(hdr
.StartDate
);
647 keyDateDebug("Invalid start date");
648 err
= CSSMERR_CSP_APPLE_INVALID_KEY_START_DATE
;
651 keyDateDebug("Valid start date");
655 keyDateDebug("Empty start date");
659 end
= cspGetUniformDate(hdr
.EndDate
);
665 keyDateDebug("Invalid end date");
666 err
= CSSMERR_CSP_APPLE_INVALID_KEY_END_DATE
;
669 keyDateDebug("Valid end date");
673 keyDateDebug("Empty end date");
686 CssmError::throwMe(err
);