]> git.saurik.com Git - apple/security.git/blob - AppleCSP/AppleCSP/wrapKey.cpp
e181fc668effb6f557199130febbabc537216396
[apple/security.git] / AppleCSP / AppleCSP / wrapKey.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 // wrapKey.cpp - wrap/unwrap key functions for AppleCSPSession
21 //
22
23 /*
24 * Currently the Security Server wraps public keys when they're stored, so we have
25 * to allow this. We might not want to do this in the real world.
26 */
27 #define ALLOW_PUB_KEY_WRAP 1
28
29 #include "AppleCSPSession.h"
30 #include "AppleCSPUtils.h"
31 #include "AppleCSPKeys.h"
32 #include "pkcs8.h"
33 #include "cspdebugging.h"
34
35 /*
36 * Wrap key function. Used for two things:
37 *
38 * -- Encrypt and encode a private or session key for export to
39 * a foreign system or program. Any type of keys may be used
40 * for the unwrapped key and the wrapping (encrypting) key,
41 * as long as this CSP understands those keys. The context
42 * must be of class ALGCLASS_SYMMETRIC or ALGCLASS_ASYMMETRIC,
43 * matching the wrapping key.
44 *
45 * In the absence of an explicit CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
46 * attribute, private keys will be PKCS8 wrapped; session keys will be
47 * PKCS7 wrapped. Both input keys may be in raw or reference
48 * format. Wrapped key will have BlobType CSSM_KEYBLOB_WRAPPED.
49 *
50 * -- Convert a reference key to a RAW key (with no encrypting).
51 * This is called a NULL wrap; no wrapping key need be present in
52 * the context, but the context must be of class
53 * ALGCLASS_SYMMETRIC and algorithm ALGID_NONE.
54 *
55 * There are serious inconsistencies in the specification of wrap
56 * algorithms to be used in the various CDSA specs (c914.pdf,
57 * CSP Behavior spec) and between those specs and the PKCS standards
58 * PKCS7, PKCS8, RFC2630). Here is what this module implements:
59 *
60 * On a wrap key op, the caller can add a CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
61 * attribute to the context to specify the wrapping algorithm to be used.
62 * If it's there, that's what we use if appropriate for the incoming key
63 * types. Otherwise we figure out a reasonable default from the incoming
64 * key types. The wrapped key always has the appropriate KeyHeader.Format
65 * field set indicating how it was wrapped. Defaults are shows below.
66 *
67 * The format CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM is used to indicate
68 * a modified CMS-style wrapping which is similar to that specified in
69 * RFC2630, with some modification.
70 *
71 * Default wrapping if none specified based on ther unwrapped key as
72 * follows:
73 *
74 * UnwrappedKey Wrap format
75 * ------------ -----------
76 * Symmetric PKCS7
77 * Public APPLE_CUSTOM
78 * FEE private APPLE_CUSTOM
79 * Other private PKCS8
80 */
81
82 void AppleCSPSession::WrapKey(
83 CSSM_CC_HANDLE CCHandle,
84 const Context &Context,
85 const AccessCredentials &AccessCred,
86 const CssmKey &UnwrappedKey,
87 const CssmData *DescriptiveData,
88 CssmKey &WrappedKey,
89 CSSM_PRIVILEGE Privilege)
90 {
91 CssmKey::Header &wrappedHdr = WrappedKey.header();
92 bool isNullWrap = false;
93 CssmKey *wrappingKey = NULL;
94 CSSM_KEYBLOB_FORMAT wrapFormat;
95
96 switch(UnwrappedKey.keyClass()) {
97 case CSSM_KEYCLASS_PUBLIC_KEY:
98 case CSSM_KEYCLASS_PRIVATE_KEY:
99 case CSSM_KEYCLASS_SESSION_KEY:
100 break;
101 default:
102 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
103 }
104
105 /* wrapping key only required for non-NULL wrap */
106 wrappingKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_KEY);
107 if(wrappingKey == NULL) {
108 if((Context.algorithm() == CSSM_ALGID_NONE) &&
109 (Context.type() == CSSM_ALGCLASS_SYMMETRIC)) {
110 // NULL wrap, OK
111 isNullWrap = true;
112 }
113 else {
114 errorLog0("WrapKey: missing wrapping key\n");
115 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY);
116 }
117 }
118
119 /*
120 * Validate misc. params as best we can
121 */
122 if(isNullWrap) {
123 wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
124 }
125 else {
126 /*
127 * Can only wrap session and private keys.
128 */
129 #if !ALLOW_PUB_KEY_WRAP
130 if(UnwrappedKey.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) {
131 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
132 }
133 #endif /* ALLOW_PUB_KEY_WRAP */
134 cspValidateIntendedKeyUsage(&wrappingKey->KeyHeader, CSSM_KEYUSE_WRAP);
135 cspVerifyKeyTimes(wrappingKey->KeyHeader);
136
137 /*
138 * make sure wrapping key type matches context
139 */
140 CSSM_CONTEXT_TYPE wrapType;
141 switch(wrappingKey->KeyHeader.KeyClass) {
142 case CSSM_KEYCLASS_PUBLIC_KEY:
143 case CSSM_KEYCLASS_PRIVATE_KEY:
144 wrapType = CSSM_ALGCLASS_ASYMMETRIC;
145 break;
146 case CSSM_KEYCLASS_SESSION_KEY:
147 wrapType = CSSM_ALGCLASS_SYMMETRIC;
148 break;
149 default:
150 errorLog0("WrapKey: bad class of wrappingKey\n");
151 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
152 }
153 if(wrapType != Context.type()) {
154 errorLog0("WrapKey: mismatch wrappingKey/contextType\n");
155 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
156 }
157 if(Context.algorithm() == CSSM_ALGID_NONE) {
158 errorLog0("WrapKey: null wrap alg, non-null key\n");
159 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
160 }
161
162 /*
163 * Get optional wrap format, set default per incoming keys
164 * Note: no such atrribute ==> 0 ==> FORMAT_NONE, which we
165 * take to mean "use the default".
166 */
167 wrapFormat = Context.getInt(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT);
168 if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) {
169 /* figure out a default based on unwrapped key */
170 switch(UnwrappedKey.keyClass()) {
171 case CSSM_KEYCLASS_SESSION_KEY:
172 wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
173 break;
174 case CSSM_KEYCLASS_PUBLIC_KEY:
175 wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM;
176 break;
177 case CSSM_KEYCLASS_PRIVATE_KEY:
178 switch(UnwrappedKey.algorithm()) {
179 case CSSM_ALGID_FEE:
180 wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM;
181 break;
182 default:
183 wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
184 break;
185 }
186 break;
187 default:
188 /* NOT REACHED - checked above */
189 break;
190 }
191 } /* no format present or FORMAT_NONE */
192 }
193
194 /* make sure we have a valid format here */
195 switch(wrapFormat) {
196 case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7:
197 if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_SESSION_KEY) {
198 /* this wrapping style only for symmetric keys */
199 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
200 }
201 break;
202 case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
203 if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) {
204 /* this wrapping style only for private keys */
205 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
206 }
207 break;
208 case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM:
209 /* no restrictions (well AES can't be the wrap alg but that will
210 * be caught later */
211 break;
212 case CSSM_KEYBLOB_WRAPPED_FORMAT_NONE:
213 if(isNullWrap) {
214 /* only time this is OK */
215 break;
216 }
217 /* else fall thru */
218 default:
219 dprintf1("KeyWrap: invalid wrapFormat (%d)\n", (int)wrapFormat);
220 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_WRAPPED_KEY_FORMAT);
221 }
222 /* get the blob to be wrappped */
223 CssmData rawBlob;
224 bool allocdRawBlob = false;
225 CSSM_KEYBLOB_FORMAT rawFormat;
226
227 /*
228 * Outgoing same as incoming unless a partial key is completed during
229 * generateKeyBlob()
230 */
231 const CssmKey::Header &unwrappedHdr = UnwrappedKey.header();
232 CSSM_KEYATTR_FLAGS unwrappedKeyAttrFlags = unwrappedHdr.KeyAttr;
233
234 switch(UnwrappedKey.blobType()) {
235 case CSSM_KEYBLOB_RAW:
236 /* trivial case */
237 rawBlob = CssmData::overlay(UnwrappedKey.KeyData);
238 rawFormat = UnwrappedKey.blobFormat();
239 break;
240 case CSSM_KEYBLOB_REFERENCE:
241 /* get binary key, then get blob from it */
242 {
243 BinaryKey &binKey = lookupRefKey(UnwrappedKey);
244
245 /*
246 * Subsequent tests for extractability: don't trust the
247 * caller's header; use the one in the BinaryKey.
248 */
249 CSSM_KEYATTR_FLAGS keyAttr = binKey.mKeyHeader.KeyAttr;
250 if(!(keyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
251 /* this key not extractable in any form */
252 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
253 }
254
255 /*
256 * Null wrap - prevent caller from obtaining
257 * clear bits if CSSM_KEYATTR_SENSITIVE
258 */
259 if(isNullWrap && (keyAttr & CSSM_KEYATTR_SENSITIVE)) {
260 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
261 }
262
263 /*
264 * Special case for PKCS8: need to get blob of a specific
265 * algorithm-dependent format.
266 */
267 if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8) {
268 rawFormat = pkcs8RawKeyFormat(binKey.mKeyHeader.Format);
269 }
270 else {
271 rawFormat = requestedKeyFormat(Context, UnwrappedKey);
272 }
273 /* optional parameter-bearing key */
274 CssmKey *paramKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_PARAM_KEY);
275 binKey.generateKeyBlob(privAllocator,
276 rawBlob,
277 rawFormat,
278 *this,
279 paramKey,
280 unwrappedKeyAttrFlags);
281 }
282 allocdRawBlob = true; // remember - we need to free
283 break;
284
285 default:
286 errorLog0("WrapKey: bad unwrappedKey BlobType\n");
287 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
288 }
289
290 /*
291 * Prepare outgoing header.
292 */
293 setKeyHeader(wrappedHdr,
294 plugin.myGuid(),
295 unwrappedHdr.algorithm(), // same as incoming
296 unwrappedHdr.keyClass(), // same as incoming
297 unwrappedKeyAttrFlags,
298 unwrappedHdr.KeyUsage);
299 wrappedHdr.LogicalKeySizeInBits = unwrappedHdr.LogicalKeySizeInBits;
300 wrappedHdr.WrapAlgorithmId = Context.algorithm(); // true for null
301 // and non-Null
302 wrappedHdr.StartDate = unwrappedHdr.StartDate;
303 wrappedHdr.EndDate = unwrappedHdr.EndDate;
304 wrappedHdr.Format = wrapFormat;
305 if(isNullWrap) {
306 wrappedHdr.BlobType = CSSM_KEYBLOB_RAW;
307 }
308 else {
309 wrappedHdr.BlobType = CSSM_KEYBLOB_WRAPPED;
310 }
311
312 /*
313 * special case - break out here for custom Apple CMS
314 */
315 if(!isNullWrap && (wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM)) {
316 try {
317 WrapKeyCms(CCHandle,
318 Context,
319 AccessCred,
320 UnwrappedKey,
321 rawBlob,
322 allocdRawBlob,
323 DescriptiveData,
324 WrappedKey,
325 Privilege);
326 }
327 catch(...) {
328 if(allocdRawBlob) {
329 freeCssmData(rawBlob, privAllocator);
330 }
331 throw;
332 }
333 if(allocdRawBlob) {
334 freeCssmData(rawBlob, privAllocator);
335 }
336 return;
337 }
338
339
340 /*
341 * Generate wrapped blob. Careful, we need to conditionally free
342 * rawBlob on error.
343 */
344 CssmData encryptedBlob;
345 CssmData remData;
346 WrappedKey.KeyData.Data = NULL; // ignore possible incoming KeyData
347 WrappedKey.KeyData.Length = 0;
348
349 try {
350 if(isNullWrap) {
351 /* copy raw blob to caller's wrappedKey */
352 copyCssmData(rawBlob,
353 CssmData::overlay(WrappedKey.KeyData),
354 normAllocator);
355 wrappedHdr.Format = rawFormat;
356 }
357 else {
358 /* encrypt rawBlob using caller's context, then encode to
359 * WrappedKey.KeyData */
360 uint32 bytesEncrypted;
361 EncryptData(CCHandle,
362 Context,
363 &rawBlob, // ClearBufs[]
364 1, // ClearBufCount
365 &encryptedBlob, // CipherBufs[],
366 1, // CipherBufCount,
367 bytesEncrypted,
368 remData,
369 Privilege);
370
371 // I'm not 100% sure about this....
372 assert(remData.Length == 0);
373 encryptedBlob.Length = bytesEncrypted;
374 WrappedKey.KeyData = encryptedBlob;
375 wrappedHdr.BlobType = CSSM_KEYBLOB_WRAPPED;
376 // OK to be zero or not present
377 wrappedHdr.WrapMode = Context.getInt(
378 CSSM_ATTRIBUTE_MODE);
379 }
380 }
381 catch (...) {
382 errorLog0("WrapKey: EncryptData() threw exception\n");
383 if(allocdRawBlob) {
384 freeCssmData(rawBlob, privAllocator);
385 }
386 freeCssmData(remData,normAllocator);
387 throw;
388 }
389 if(allocdRawBlob) {
390 freeCssmData(rawBlob, privAllocator);
391 }
392 freeCssmData(remData, normAllocator);
393 }
394
395 /*
396 * Unwrap key function. Used for:
397 *
398 * -- Given key of BlobType CSSM_KEYBLOB_WRAPPED, decode and decrypt
399 * it, yielding a key in either raw or reference format. Unwrapping
400 * key may be either raw or reference. The context must match
401 * the unwrapping key (ALGCLASS_SYMMETRIC or ALGCLASS_ASYMMETRIC).
402 *
403 * Private keys are assumed to be PKCS8 encoded; session keys
404 * are assumed to be PKCS7 encoded.
405 *
406 * -- Convert a Raw key to a reference key (with no decrypting).
407 * This is called a NULL unwrap; no unwrapping key need be present in
408 * the context, but the context must be of class
409 * ALGCLASS_SYMMETRIC and algorithm ALGID_NONE.
410 */
411 void AppleCSPSession::UnwrapKey(
412 CSSM_CC_HANDLE CCHandle,
413 const Context &Context,
414 const CssmKey *PublicKey,
415 const CssmKey &WrappedKey,
416 uint32 KeyUsage,
417 uint32 KeyAttr,
418 const CssmData *KeyLabel,
419 const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
420 CssmKey &UnwrappedKey,
421 CssmData &DescriptiveData,
422 CSSM_PRIVILEGE Privilege)
423 {
424 bool isNullUnwrap = false;
425 CssmKey *unwrappingKey = NULL;
426 cspKeyType keyType; // CKT_Public, etc.
427 CSSM_KEYBLOB_FORMAT wrapFormat = WrappedKey.blobFormat();
428
429 /* obtain unwrapping key if present */
430 unwrappingKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_KEY);
431 if(unwrappingKey == NULL) {
432 if((Context.algorithm() == CSSM_ALGID_NONE) &&
433 (Context.type() == CSSM_ALGCLASS_SYMMETRIC)) {
434 // NULL unwrap, OK
435 isNullUnwrap = true;
436 }
437 else {
438 errorLog0("UnwrapKey: missing wrapping key\n");
439 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY);
440 }
441 }
442
443 /*
444 * validate unwrappingKey
445 */
446 if(!isNullUnwrap) {
447 /* make sure unwrapping key type matches context */
448 CSSM_CONTEXT_TYPE unwrapType;
449 switch(unwrappingKey->KeyHeader.KeyClass) {
450 case CSSM_KEYCLASS_PUBLIC_KEY:
451 case CSSM_KEYCLASS_PRIVATE_KEY:
452 unwrapType = CSSM_ALGCLASS_ASYMMETRIC;
453 break;
454 case CSSM_KEYCLASS_SESSION_KEY:
455 unwrapType = CSSM_ALGCLASS_SYMMETRIC;
456 break;
457 default:
458 errorLog0("UnwrapKey: bad class of wrappingKey\n");
459 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
460 }
461 if(unwrapType != Context.type()) {
462 errorLog0("UnwrapKey: mismatch unwrappingKey/contextType\n");
463 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
464 }
465 if(Context.algorithm() == CSSM_ALGID_NONE) {
466 errorLog0("UnwrapKey: null wrap alg, non-null key\n");
467 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
468 }
469 cspValidateIntendedKeyUsage(&unwrappingKey->KeyHeader, CSSM_KEYUSE_UNWRAP);
470 cspVerifyKeyTimes(unwrappingKey->KeyHeader);
471 }
472
473 /* validate WrappedKey */
474 switch(WrappedKey.keyClass()) {
475 case CSSM_KEYCLASS_PUBLIC_KEY:
476 #if !ALLOW_PUB_KEY_WRAP
477 if(!isNullUnwrap) {
478 errorLog0("UnwrapKey: unwrap of public key illegal\n");
479 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
480 }
481 #endif /* ALLOW_PUB_KEY_WRAP */
482 keyType = CKT_Public;
483 break;
484 case CSSM_KEYCLASS_PRIVATE_KEY:
485 keyType = CKT_Private;
486 break;
487 case CSSM_KEYCLASS_SESSION_KEY:
488 keyType = CKT_Session;
489 break;
490 default:
491 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
492 }
493 if(isNullUnwrap) {
494 if(WrappedKey.blobType() != CSSM_KEYBLOB_RAW) {
495 errorLog0("UnwrapKey: expected raw blobType\n");
496 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
497 }
498 }
499 else {
500 if(WrappedKey.blobType() != CSSM_KEYBLOB_WRAPPED) {
501 errorLog0("UnwrapKey: expected wrapped blobType\n");
502 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
503 }
504 }
505
506 /* validate requested storage and usage */
507 cspKeyStorage keyStorage = cspParseKeyAttr(keyType, KeyAttr);
508 switch(keyStorage) {
509 case CKS_Ref:
510 case CKS_Data:
511 break; // OK
512 default:
513 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
514 }
515 cspValidateKeyUsageBits(keyType, KeyUsage);
516
517 /* prepare outgoing header */
518 CssmKey::Header &unwrappedHdr = UnwrappedKey.header();
519 const CssmKey::Header &wrappedHdr = WrappedKey.header();
520 setKeyHeader(unwrappedHdr,
521 plugin.myGuid(),
522 wrappedHdr.algorithm(), // same as incoming
523 wrappedHdr.keyClass(), // same as incoming
524 KeyAttr & ~KEY_ATTR_RETURN_MASK,
525 KeyUsage);
526 unwrappedHdr.LogicalKeySizeInBits = wrappedHdr.LogicalKeySizeInBits;
527 unwrappedHdr.StartDate = wrappedHdr.StartDate;
528 unwrappedHdr.EndDate = wrappedHdr.EndDate;
529 UnwrappedKey.KeyData.Data = NULL; // ignore possible incoming KeyData
530 UnwrappedKey.KeyData.Length = 0;
531
532 /* validate wrappedKey format */
533 if(!isNullUnwrap) {
534 switch(wrapFormat) {
535 case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7:
536 if(WrappedKey.keyClass() != CSSM_KEYCLASS_SESSION_KEY) {
537 /* this unwrapping style only for symmetric keys */
538 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
539 }
540 break;
541 case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
542 if(WrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) {
543 /* this unwrapping style only for private keys */
544 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
545 }
546 break;
547 case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM:
548 UnwrapKeyCms(CCHandle,
549 Context,
550 WrappedKey,
551 CredAndAclEntry,
552 UnwrappedKey,
553 DescriptiveData,
554 Privilege,
555 keyStorage);
556 return;
557 default:
558 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_WRAPPED_KEY_FORMAT);
559 }
560 }
561
562 /* Get key blob, decoding and decrypting if necessary */
563 CssmData decodedBlob;
564 CssmData remData;
565 try {
566 if(isNullUnwrap) {
567 /* simple copy of raw blob */
568 copyData(WrappedKey.KeyData,
569 UnwrappedKey.KeyData,
570 normAllocator);
571 unwrappedHdr.BlobType = CSSM_KEYBLOB_RAW;
572 unwrappedHdr.Format = wrapFormat;
573 }
574 else {
575 decodedBlob = CssmData::overlay(WrappedKey.KeyData);
576 uint32 bytesDecrypted;
577 CssmData *unwrapData =
578 CssmData::overlay(&UnwrappedKey.KeyData);
579
580 DecryptData(CCHandle,
581 Context,
582 &decodedBlob, // CipherBufs[],
583 1, // CipherBufCount,
584 unwrapData, // ClearBufs[]
585 1, // ClearBufCount
586 bytesDecrypted,
587 remData,
588 Privilege);
589
590 // I'm not 100% sure about this....
591 assert(remData.Length == 0);
592 UnwrappedKey.KeyData.Length = bytesDecrypted;
593 unwrappedHdr.BlobType = CSSM_KEYBLOB_RAW;
594
595 /*
596 * Figure out various header fields from resulting blob
597 */
598 switch(wrapFormat) {
599 case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7:
600 unwrappedHdr.Format =
601 CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
602 if(unwrappedHdr.LogicalKeySizeInBits == 0) {
603 unwrappedHdr.LogicalKeySizeInBits =
604 bytesDecrypted * 8;
605 }
606 /* app has to infer/know algorithm */
607 break;
608 case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
609 pkcs8InferKeyHeader(UnwrappedKey);
610 break;
611 }
612 }
613 }
614 catch (...) {
615 errorLog0("UnwrapKey: DecryptData() threw exception\n");
616 freeCssmData(remData, normAllocator);
617 throw;
618 }
619 freeCssmData(remData, normAllocator);
620
621 /*
622 * One more thing: cook up a BinaryKey if caller wants a
623 * reference key.
624 */
625 if(keyStorage == CKS_Ref) {
626 /*
627 * We have a key in raw format; convert to BinaryKey.
628 */
629 BinaryKey *binKey = NULL;
630 CSPKeyInfoProvider *provider = infoProvider(UnwrappedKey);
631 /* optional parameter-bearing key */
632 CssmKey *paramKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_PARAM_KEY);
633 provider->CssmKeyToBinary(paramKey, UnwrappedKey.KeyHeader.KeyAttr, &binKey);
634 addRefKey(*binKey, UnwrappedKey);
635 delete provider;
636 }
637 }
638