]> git.saurik.com Git - apple/security.git/blob - AppleCSP/AppleCSP/AppleCSPUtils.cpp
Security-28.tar.gz
[apple/security.git] / AppleCSP / AppleCSP / AppleCSPUtils.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, 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
19 //
20 // AppleCSPUtils.cpp - CSP-wide utility functions
21 //
22
23 #include "AppleCSPUtils.h"
24 #include <Security/cssmerr.h>
25 #include <Security/utilities.h>
26 #include <Security/cssmalloc.h>
27 #include <string.h>
28 #include <CryptKitCSP/FEECSPUtils.h>
29 #include <MiscCSPAlgs/SHA1_MD5_Object.h>
30
31 /*
32 * Validate key attribute bits per specified key type.
33 *
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.
38 */
39 void cspValidateKeyAttr(
40 cspKeyType keyType,
41 uint32 keyAttr)
42 {
43 uint32 sensitiveBit = (keyAttr & CSSM_KEYATTR_SENSITIVE) ? 1 : 0;
44 uint32 extractBit = (keyAttr & CSSM_KEYATTR_EXTRACTABLE) ? 1 : 0;
45
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);
50 }
51 if(keyAttr & CSSM_KEYATTR_PERMANENT) {
52 //errorLog0(" PERMANENT bit not supported\n");
53 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK);
54 }
55 if(keyAttr & CSSM_KEYATTR_PRIVATE) {
56 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK);
57 }
58 /* Anything else? */
59
60 /* now check per keyType */
61 switch(keyType) {
62 case CKT_Session:
63 break;
64
65 case CKT_Public:
66 if(sensitiveBit || !extractBit) {
67 //errorLog0("Public keys must be extractable in the clear\n");
68 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
69 }
70 break;
71
72 case CKT_Private:
73 //if(!sensitiveBit) {
74 // errorLog0("Private keys must have KEYATTR_SENSITIVE\n");
75 // CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
76 //}
77
78 /*
79 * One more restriction - EXTRACTABLE - caller must check since
80 * that involves KEYUSE bits.
81 */
82 break;
83 default:
84 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
85 }
86 return;
87 }
88
89 /*
90 * Perform sanity check of incoming key attribute bits for a given
91 * key type, and return a cspKeyStorage value.
92 *
93 * Called from any routine which generates a new key. This specifically
94 * excludes WrapKey().
95 */
96 cspKeyStorage cspParseKeyAttr(
97 cspKeyType keyType,
98 uint32 keyAttr)
99 {
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;
104
105 cspKeyStorage rtn;
106
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);
112 }
113 switch(keyAttr & KEY_ATTR_RETURN_MASK) {
114 /* ensure only one bit is set */
115 case CSSM_KEYATTR_RETURN_DATA:
116 rtn = CKS_Data;
117 break;
118 case CSSM_KEYATTR_RETURN_REF:
119 rtn = CKS_Ref;
120 break;
121 case CSSM_KEYATTR_RETURN_NONE:
122 rtn = CKS_None;
123 break;
124 case CSSM_KEYATTR_RETURN_DEFAULT:
125 /* CSP default */
126 rtnRefBit = 1;
127 rtn = CKS_Ref;
128 break;
129 default:
130 //errorLog0("Multiple KEYATTR_RETURN bits set\n");
131 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
132 }
133
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);
140 }
141 }
142 if(rtnDataBit) {
143 if(!extractBit) {
144 //errorLog0("RETURN_DATA and !EXTRACTABLE not supported\n");
145 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
146 }
147 if(sensitiveBit) {
148 //errorLog0("RETURN_DATA and SENSITIVE not supported\n");
149 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
150 }
151 }
152
153 /* now check per keyType. We're ust checking for things specific
154 * to KEYATTR_RETURN_xxx; cspValidateKeyAttr will check other fields. */
155 #if 0
156 // nothing for now
157 switch(keyType) {
158 case CKT_Session:
159 break;
160
161 case MKT_Public:
162 break;
163
164 case MKT_Private:
165 if(rtnDataBit) {
166 errorLog0("Private keys must be generated by ref\n");
167 goto errorOut;
168 }
169 /*
170 * One more restriction - EXTRACTABLE - caller must check since
171 * that involves KEYUSE bits.
172 */
173 break;
174 default:
175 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
176 }
177 #endif // 0
178
179 /* validate other common static attributes */
180 cspValidateKeyAttr(keyType, (keyAttr & ~KEY_ATTR_RETURN_MASK));
181 return rtn;
182 }
183
184
185 /* used in cspValidateKeyUsageBits() */
186 /*
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.
190 */
191 #define IGNORE_KEYUSE_EXCLUSIVITY 1
192 #if IGNORE_KEYUSE_EXCLUSIVITY
193 #define checkExclusiveUsage(ku, cb, ob, em)
194 #else
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
199 const char *errMsg)
200 {
201 if(keyUsage & checkBits) {
202 if(keyUsage & ~otherBits) {
203 errorLog0((char *)errMsg);
204 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK);
205 }
206 }
207 }
208 #endif /* IGNORE_KEYUSE_EXCLUSIVITY */
209
210 /*
211 * Validate key usage bits for specified key type.
212 */
213 void cspValidateKeyUsageBits (
214 cspKeyType keyType,
215 uint32 keyUsage)
216 {
217 /* general restrictions */
218 checkExclusiveUsage(keyUsage,
219 CSSM_KEYUSE_ANY,
220 CSSM_KEYUSE_ANY,
221 "CSSM_KEYUSE_ANY overload");
222 checkExclusiveUsage(keyUsage,
223 CSSM_KEYUSE_DERIVE,
224 CSSM_KEYUSE_DERIVE,
225 "CSSM_KEYUSE_DERIVE overload\n");
226
227 /* brute force per key type. */
228 switch(keyType) {
229 case CKT_Session:
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");
244 break;
245
246 case CKT_Public:
247 checkExclusiveUsage(keyUsage,
248 CSSM_KEYUSE_ENCRYPT,
249 CSSM_KEYUSE_ENCRYPT,
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);
254 }
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);
258 }
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,
264 CSSM_KEYUSE_WRAP,
265 CSSM_KEYUSE_WRAP,
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);
270 }
271 break;
272
273 case CKT_Private:
274 if(keyUsage & CSSM_KEYUSE_ENCRYPT) {
275 errorLog0("private key usage: ENCRYPT illegal\n");
276 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK);
277 }
278 checkExclusiveUsage(keyUsage,
279 CSSM_KEYUSE_DECRYPT,
280 CSSM_KEYUSE_DECRYPT,
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);
289 }
290 if(keyUsage & CSSM_KEYUSE_WRAP) {
291 errorLog0("private key usage: WRAP illegal\n");
292 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK);
293 }
294 checkExclusiveUsage(keyUsage,
295 CSSM_KEYUSE_UNWRAP,
296 CSSM_KEYUSE_UNWRAP,
297 "private key usage: unwrap overload\n");
298 break;
299 default:
300 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
301 }
302 }
303
304 /*
305 * Validate existing key's usage bits against intended use.
306 */
307
308 /*
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
311 * Radar 2716153.
312 */
313 #define RELAXED_WRAP_USAGE 1
314
315 void cspValidateIntendedKeyUsage(
316 const CSSM_KEYHEADER *hdr,
317 CSSM_KEYUSE intendedUsage)
318 {
319 uint32 keyUsage = hdr->KeyUsage;
320 cspKeyType keyType;
321
322 /* first, the obvious */
323 if(keyUsage & CSSM_KEYUSE_ANY) {
324 /* OK for now */
325 return;
326 }
327 if(!(keyUsage & intendedUsage)) {
328 #if RELAXED_WRAP_USAGE
329 if(! ( ( (keyUsage & CSSM_KEYUSE_WRAP) &&
330 (intendedUsage == CSSM_KEYUSE_ENCRYPT)
331 ) ||
332 ( (keyUsage & CSSM_KEYUSE_UNWRAP) &&
333 (intendedUsage == CSSM_KEYUSE_DECRYPT)
334 )
335 ) )
336 #endif
337 CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT);
338 }
339
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;
345 break;
346 case CSSM_KEYCLASS_PUBLIC_KEY:
347 keyType = CKT_Public;
348 break;
349 case CSSM_KEYCLASS_PRIVATE_KEY:
350 keyType = CKT_Private;
351 break;
352 default:
353 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
354 }
355 try {
356 cspValidateKeyUsageBits(keyType, keyUsage);
357 }
358 catch (...) {
359 /* override error.... */
360 CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT);
361 }
362 }
363
364 /*
365 * Set up a key header.
366 */
367 void setKeyHeader(
368 CSSM_KEYHEADER &hdr,
369 const Guid &myGuid,
370 CSSM_ALGORITHMS alg,
371 CSSM_KEYCLASS keyClass,
372 CSSM_KEYATTR_FLAGS attrs,
373 CSSM_KEYUSE use)
374 {
375 memset(&hdr, 0, sizeof(CSSM_KEYHEADER));
376 hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
377 hdr.CspId = myGuid;
378 hdr.AlgorithmId = alg;
379 hdr.KeyClass = keyClass;
380 hdr.KeyUsage = use;
381 hdr.KeyAttr = attrs;
382
383 // defaults (change as needed)
384 hdr.WrapAlgorithmId = CSSM_ALGID_NONE;
385 }
386
387 /*
388 * Ensure that indicated CssmData can handle 'length' bytes
389 * of data. Malloc the Data ptr if necessary.
390 */
391 void setUpCssmData(
392 CssmData &data,
393 size_t length,
394 CssmAllocator &allocator)
395 {
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);
400 }
401 else if(data.Length < length) {
402 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
403 }
404 data.Length = length;
405 }
406
407 void setUpData(
408 CSSM_DATA &data,
409 size_t length,
410 CssmAllocator &allocator)
411 {
412 setUpCssmData(CssmData::overlay(data), length, allocator);
413 }
414
415 void freeCssmData(
416 CssmData &data,
417 CssmAllocator &allocator)
418 {
419 if(data.Data) {
420 allocator.free(data.Data);
421 data.Data = NULL;
422 }
423 data.Length = 0;
424 }
425
426 void freeData(
427 CSSM_DATA *data,
428 CssmAllocator &allocator,
429 bool freeStruct) // free the CSSM_DATA itself
430 {
431 if(data == NULL) {
432 return;
433 }
434 if(data->Data) {
435 allocator.free(data->Data);
436 data->Data = NULL;
437 }
438 data->Length = 0;
439 if(freeStruct) {
440 allocator.free(data);
441 }
442 }
443
444 /*
445 * Copy source to destination, mallocing destination if necessary.
446 */
447 void copyCssmData(
448 const CssmData &src,
449 CssmData &dst,
450 CssmAllocator &allocator)
451 {
452 setUpCssmData(dst, src.Length, allocator);
453 memmove(dst.Data, src.Data, src.Length);
454 }
455
456 void copyData(
457 const CSSM_DATA &src,
458 CSSM_DATA &dst,
459 CssmAllocator &allocator)
460 {
461 copyCssmData(CssmData::overlay(src),
462 CssmData::overlay(dst),
463 allocator);
464 }
465
466 /*
467 * This takes care of mallocing the KeyLabel field.
468 */
469 void copyCssmHeader(
470 const CssmKey::Header &src,
471 CssmKey::Header &dst,
472 CssmAllocator &allocator)
473 {
474 dst = src;
475 }
476
477 /*
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.
481 */
482 CSSM_KEYBLOB_FORMAT inferFormat(
483 const CssmKey &wrappedKey)
484 {
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()) {
490 case CSSM_ALGID_RSA:
491 return CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
492 case CSSM_ALGID_DSA:
493 return CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
494 #ifdef CRYPTKIT_CSP_ENABLE
495 case CSSM_ALGID_FEE:
496 return FEE_KEYBLOB_DEFAULT_FORMAT;
497 #endif
498 default:
499 /* punt */
500 return CSSM_KEYBLOB_RAW_FORMAT_NONE;
501 }
502 case CSSM_KEYCLASS_PRIVATE_KEY:
503 switch(wrappedKey.algorithm()) {
504 case CSSM_ALGID_RSA:
505 return CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
506 case CSSM_ALGID_DSA:
507 return CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
508 #ifdef CRYPTKIT_CSP_ENABLE
509 case CSSM_ALGID_FEE:
510 return FEE_KEYBLOB_DEFAULT_FORMAT;
511 #endif
512 default:
513 /* punt */
514 return CSSM_KEYBLOB_RAW_FORMAT_NONE;
515 }
516 default:
517 /* punt */
518 return CSSM_KEYBLOB_RAW_FORMAT_NONE;
519 }
520 }
521
522 /*
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.
526 */
527 CSSM_KEYBLOB_FORMAT requestedKeyFormat(
528 const Context &context,
529 const CssmKey &key)
530 {
531 CSSM_ATTRIBUTE_TYPE attrType;
532
533 switch(key.keyClass()) {
534 case CSSM_KEYCLASS_SESSION_KEY:
535 attrType = CSSM_ATTRIBUTE_SYMMETRIC_KEY_FORMAT;
536 break;
537 case CSSM_KEYCLASS_PUBLIC_KEY:
538 attrType = CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT;
539 break;
540 case CSSM_KEYCLASS_PRIVATE_KEY:
541 attrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT;
542 break;
543 default:
544 return CSSM_KEYBLOB_RAW_FORMAT_NONE;
545 }
546 /* not present ==> 0 ==> CSSM_KEYBLOB_RAW_FORMAT_NONE */
547 return context.getInt(attrType);
548 }
549
550 /* one-shot SHA1 digest */
551 void cspGenSha1Hash(
552 const void *inData,
553 size_t inDataLen,
554 void *out) // caller mallocs, digest goes here
555 {
556 SHA1Object sha1;
557
558 sha1.digestInit();
559 sha1.digestUpdate(inData, inDataLen);
560 sha1.digestFinal(out);
561 }