]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cmspubkey.c
Security-59306.11.20.tar.gz
[apple/security.git] / libsecurity_smime / lib / cmspubkey.c
1 /*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Netscape security libraries.
13 *
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation. Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above. If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL. If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
31 * GPL.
32 */
33
34 /*
35 * CMS public key crypto
36 */
37
38 #include "cmslocal.h"
39
40 #include "SecAsn1Item.h"
41 #include "secoid.h"
42 #include "cryptohi.h"
43
44 #include <security_asn1/secasn1.h>
45 #include <security_asn1/secerr.h>
46 #include <security_asn1/secport.h>
47
48 #include <Security/Security.h>
49 #include <Security/SecCertificateInternal.h>
50 #include <Security/SecKeyPriv.h>
51
52 #include <CommonCrypto/CommonCryptor.h>
53 #include <CommonCrypto/CommonRandomSPI.h>
54 #include <CommonCrypto/CommonRandom.h>
55
56 /* ====== RSA ======================================================================= */
57
58 /*
59 * SecCmsUtilEncryptSymKeyRSA - wrap a symmetric key with RSA
60 *
61 * this function takes a symmetric key and encrypts it using an RSA public key
62 * according to PKCS#1 and RFC2633 (S/MIME)
63 */
64 OSStatus
65 SecCmsUtilEncryptSymKeyRSA(PLArenaPool *poolp, SecCertificateRef cert,
66 SecSymmetricKeyRef bulkkey,
67 SecAsn1Item * encKey)
68 {
69 OSStatus rv;
70 SecPublicKeyRef publickey = SecCertificateCopyKey(cert);
71 if (publickey == NULL)
72 return SECFailure;
73
74 rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, publickey, bulkkey, encKey);
75 CFRelease(publickey);
76 return rv;
77 }
78
79 OSStatus
80 SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool *poolp,
81 SecPublicKeyRef publickey,
82 SecSymmetricKeyRef bulkkey, SecAsn1Item * encKey)
83 {
84 OSStatus rv;
85 size_t data_len;
86 //KeyType keyType;
87 void *mark = NULL;
88
89 mark = PORT_ArenaMark(poolp);
90 if (!mark)
91 goto loser;
92
93 #if 0
94 /* sanity check */
95 keyType = SECKEY_GetPublicKeyType(publickey);
96 PORT_Assert(keyType == rsaKey);
97 if (keyType != rsaKey) {
98 goto loser;
99 }
100 #endif
101 /* allocate memory for the encrypted key */
102 #if TARGET_OS_OSX
103 rv = SecKeyGetStrengthInBits(publickey, NULL, &data_len);
104 if (rv)
105 goto loser;
106 // Convert length to bytes;
107 data_len = data_len / 8;
108 #else
109 data_len = SecKeyGetSize(publickey, kSecKeyEncryptedDataSize);
110 #endif
111
112 encKey->Data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len);
113 encKey->Length = data_len;
114 if (encKey->Data == NULL)
115 goto loser;
116
117 /* encrypt the key now */
118 rv = WRAP_PubWrapSymKey(publickey, bulkkey, encKey);
119 if (rv != SECSuccess)
120 goto loser;
121
122 PORT_ArenaUnmark(poolp, mark);
123 return SECSuccess;
124
125 loser:
126 if (mark) {
127 PORT_ArenaRelease(poolp, mark);
128 }
129 return SECFailure;
130 }
131
132 /*
133 * SecCmsUtilDecryptSymKeyRSA - unwrap a RSA-wrapped symmetric key
134 *
135 * this function takes an RSA-wrapped symmetric key and unwraps it, returning a symmetric
136 * key handle. Please note that the actual unwrapped key data may not be allowed to leave
137 * a hardware token...
138 */
139 SecSymmetricKeyRef
140 SecCmsUtilDecryptSymKeyRSA(SecPrivateKeyRef privkey, SecAsn1Item * encKey, SECOidTag bulkalgtag)
141 {
142 /* that's easy */
143 return WRAP_PubUnwrapSymKey(privkey, encKey, bulkalgtag);
144 }
145
146 #if 0
147 // @@@ Implement Fortezza and Diffie hellman support
148
149 /* ====== MISSI (Fortezza) ========================================================== */
150
151 extern const SecAsn1Template NSS_SMIMEKEAParamTemplateAllParams[];
152
153 OSStatus
154 SecCmsUtilEncryptSymKeyMISSI(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef bulkkey,
155 SECOidTag symalgtag, SecAsn1Item * encKey, SecAsn1Item * *pparams, void *pwfn_arg)
156 {
157 SECOidTag certalgtag; /* the certificate's encryption algorithm */
158 SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
159 OSStatus rv = SECFailure;
160 SecAsn1Item * params = NULL;
161 OSStatus err;
162 SecSymmetricKeyRef tek;
163 SecCertificateRef ourCert;
164 SecPublicKeyRef ourPubKey, *publickey = NULL;
165 SecPrivateKeyRef ourPrivKey = NULL;
166 SecCmsKEATemplateSelector whichKEA = SecCmsKEAInvalid;
167 SecCmsSMIMEKEAParameters keaParams;
168 PLArenaPool *arena = NULL;
169 const SECAlgorithmID *algid;
170
171 /* Clear keaParams, since cleanup code checks the lengths */
172 (void) memset(&keaParams, 0, sizeof(keaParams));
173
174 #if USE_CDSA_CRYPTO
175 SecCertificateGetAlgorithmID(cert,&algid);
176 #endif
177
178 certalgtag = SECOID_GetAlgorithmTag(algid);
179 PORT_Assert(certalgtag == SEC_OID_MISSI_KEA_DSS_OLD ||
180 certalgtag == SEC_OID_MISSI_KEA_DSS ||
181 certalgtag == SEC_OID_MISSI_KEA);
182
183 #define SMIME_FORTEZZA_RA_LENGTH 128
184 #define SMIME_FORTEZZA_IV_LENGTH 24
185 #define SMIME_FORTEZZA_MAX_KEY_SIZE 256
186
187 /* We really want to show our KEA tag as the key exchange algorithm tag. */
188 encalgtag = SEC_OID_NETSCAPE_SMIME_KEA;
189
190 /* Get the public key of the recipient. */
191 publickey = CERT_ExtractPublicKey(cert);
192 if (publickey == NULL) goto loser;
193
194 /* Find our own cert, and extract its keys. */
195 ourCert = PK11_FindBestKEAMatch(cert, pwfn_arg);
196 if (ourCert == NULL) goto loser;
197
198 arena = PORT_NewArena(1024);
199 if (arena == NULL)
200 goto loser;
201
202 ourPubKey = CERT_ExtractPublicKey(ourCert);
203 if (ourPubKey == NULL) {
204 CERT_DestroyCertificate(ourCert);
205 goto loser;
206 }
207
208 /* While we're here, copy the public key into the outgoing
209 * KEA parameters. */
210 SECITEM_CopyItem(arena, &(keaParams.originatorKEAKey), &(ourPubKey->u.fortezza.KEAKey));
211 SECKEY_DestroyPublicKey(ourPubKey);
212 ourPubKey = NULL;
213
214 /* Extract our private key in order to derive the KEA key. */
215 ourPrivKey = PK11_FindKeyByAnyCert(ourCert, pwfn_arg);
216 CERT_DestroyCertificate(ourCert); /* we're done with this */
217 if (!ourPrivKey)
218 goto loser;
219
220 /* Prepare raItem with 128 bytes (filled with zeros). */
221 keaParams.originatorRA.Data = (unsigned char *)PORT_ArenaAlloc(arena,SMIME_FORTEZZA_RA_LENGTH);
222 keaParams.originatorRA.Length = SMIME_FORTEZZA_RA_LENGTH;
223
224 /* Generate the TEK (token exchange key) which we use
225 * to wrap the bulk encryption key. (keaparams.originatorRA) will be
226 * filled with a random seed which we need to send to
227 * the recipient. (user keying material in RFC2630/DSA speak) */
228 tek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
229 &keaParams.originatorRA, NULL,
230 CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
231 CKA_WRAP, 0, pwfn_arg);
232
233 SECKEY_DestroyPublicKey(publickey);
234 SECKEY_DestroyPrivateKey(ourPrivKey);
235 publickey = NULL;
236 ourPrivKey = NULL;
237
238 if (!tek)
239 goto loser;
240
241 /* allocate space for the wrapped key data */
242 encKey->Data = (unsigned char *)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
243 encKey->Length = SMIME_FORTEZZA_MAX_KEY_SIZE;
244
245 if (encKey->Data == NULL) {
246 CFRelease(tek);
247 goto loser;
248 }
249
250 /* Wrap the bulk key. What we do with the resulting data
251 depends on whether we're using Skipjack to wrap the key. */
252 switch (PK11_AlgtagToMechanism(symalgtag)) {
253 case CKM_SKIPJACK_CBC64:
254 case CKM_SKIPJACK_ECB64:
255 case CKM_SKIPJACK_OFB64:
256 case CKM_SKIPJACK_CFB64:
257 case CKM_SKIPJACK_CFB32:
258 case CKM_SKIPJACK_CFB16:
259 case CKM_SKIPJACK_CFB8:
260 /* SKIPJACK, we use the wrap mechanism because we can do it on the hardware */
261 err = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, tek, bulkkey, encKey);
262 whichKEA = SecCmsKEAUsesSkipjack;
263 break;
264 default:
265 /* Not SKIPJACK, we encrypt the raw key data */
266 keaParams.nonSkipjackIV.Data =
267 (unsigned char *)PORT_ArenaAlloc(arena, SMIME_FORTEZZA_IV_LENGTH);
268 keaParams.nonSkipjackIV.Length = SMIME_FORTEZZA_IV_LENGTH;
269 err = PK11_WrapSymKey(CKM_SKIPJACK_CBC64, &keaParams.nonSkipjackIV, tek, bulkkey, encKey);
270 if (err != SECSuccess)
271 goto loser;
272
273 if (encKey->Length != PK11_GetKeyLength(bulkkey)) {
274 /* The size of the encrypted key is not the same as
275 that of the original bulk key, presumably due to
276 padding. Encode and store the real size of the
277 bulk key. */
278 if (SEC_ASN1EncodeInteger(arena, &keaParams.bulkKeySize, PK11_GetKeyLength(bulkkey)) == NULL)
279 err = (OSStatus)PORT_GetError();
280 else
281 /* use full template for encoding */
282 whichKEA = SecCmsKEAUsesNonSkipjackWithPaddedEncKey;
283 }
284 else
285 /* enc key length == bulk key length */
286 whichKEA = SecCmsKEAUsesNonSkipjack;
287 break;
288 }
289
290 CFRelease(tek);
291
292 if (err != SECSuccess)
293 goto loser;
294
295 PORT_Assert(whichKEA != SecCmsKEAInvalid);
296
297 /* Encode the KEA parameters into the recipient info. */
298 params = SEC_ASN1EncodeItem(poolp, NULL, &keaParams, nss_cms_get_kea_template(whichKEA));
299 if (params == NULL)
300 goto loser;
301
302 /* pass back the algorithm params */
303 *pparams = params;
304
305 rv = SECSuccess;
306
307 loser:
308 if (arena)
309 PORT_FreeArena(arena, PR_FALSE);
310 if (publickey)
311 SECKEY_DestroyPublicKey(publickey);
312 if (ourPrivKey)
313 SECKEY_DestroyPrivateKey(ourPrivKey);
314 return rv;
315 }
316
317 SecSymmetricKeyRef
318 SecCmsUtilDecryptSymKeyMISSI(SecPrivateKeyRef privkey, SecAsn1Item * encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
319 {
320 /* fortezza: do a key exchange */
321 OSStatus err;
322 CK_MECHANISM_TYPE bulkType;
323 SecSymmetricKeyRef tek;
324 SecPublicKeyRef originatorPubKey;
325 SecCmsSMIMEKEAParameters keaParams;
326 SecSymmetricKeyRef bulkkey;
327 int bulkLength;
328
329 (void) memset(&keaParams, 0, sizeof(keaParams));
330
331 /* NOTE: this uses the SMIME v2 recipientinfo for compatibility.
332 All additional KEA parameters are DER-encoded in the encryption algorithm parameters */
333
334 /* Decode the KEA algorithm parameters. */
335 err = SEC_ASN1DecodeItem(NULL, &keaParams, NSS_SMIMEKEAParamTemplateAllParams,
336 &(keyEncAlg->parameters));
337 if (err != SECSuccess)
338 goto loser;
339
340 /* get originator's public key */
341 originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.Data,
342 keaParams.originatorKEAKey.Length);
343 if (originatorPubKey == NULL)
344 goto loser;
345
346 /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
347 The Derive function generates a shared secret and combines it with the originatorRA
348 data to come up with an unique session key */
349 tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
350 &keaParams.originatorRA, NULL,
351 CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
352 CKA_WRAP, 0, pwfn_arg);
353 SECKEY_DestroyPublicKey(originatorPubKey); /* not needed anymore */
354 if (tek == NULL)
355 goto loser;
356
357 /* Now that we have the TEK, unwrap the bulk key
358 with which to decrypt the message. We have to
359 do one of two different things depending on
360 whether Skipjack was used for *bulk* encryption
361 of the message. */
362 bulkType = PK11_AlgtagToMechanism(bulkalgtag);
363 switch (bulkType) {
364 case CKM_SKIPJACK_CBC64:
365 case CKM_SKIPJACK_ECB64:
366 case CKM_SKIPJACK_OFB64:
367 case CKM_SKIPJACK_CFB64:
368 case CKM_SKIPJACK_CFB32:
369 case CKM_SKIPJACK_CFB16:
370 case CKM_SKIPJACK_CFB8:
371 /* Skipjack is being used as the bulk encryption algorithm.*/
372 /* Unwrap the bulk key. */
373 bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
374 encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
375 break;
376 default:
377 /* Skipjack was not used for bulk encryption of this
378 message. Use Skipjack CBC64, with the nonSkipjackIV
379 part of the KEA key parameters, to decrypt
380 the bulk key. If the optional parameter bulkKeySize is present,
381 bulk key size is different than the encrypted key size */
382 if (keaParams.bulkKeySize.Length > 0) {
383 err = SEC_ASN1DecodeItem(NULL, &bulkLength,
384 SEC_ASN1_GET(SEC_IntegerTemplate),
385 &keaParams.bulkKeySize);
386 if (err != SECSuccess)
387 goto loser;
388 }
389
390 bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_CBC64, &keaParams.nonSkipjackIV,
391 encKey, bulkType, CKA_DECRYPT, bulkLength);
392 break;
393 }
394 return bulkkey;
395 loser:
396 return NULL;
397 }
398
399 /* ====== ESDH (Ephemeral-Static Diffie-Hellman) ==================================== */
400
401 OSStatus
402 SecCmsUtilEncryptSymKeyESDH(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef key,
403 SecAsn1Item * encKey, SecAsn1Item * *ukm, SECAlgorithmID *keyEncAlg,
404 SecAsn1Item * pubKey)
405 {
406 #if 0 /* not yet done */
407 SECOidTag certalgtag; /* the certificate's encryption algorithm */
408 SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
409 OSStatus rv;
410 SecAsn1Item * params = NULL;
411 int data_len;
412 OSStatus err;
413 SecSymmetricKeyRef tek;
414 SecCertificateRef ourCert;
415 SecPublicKeyRef ourPubKey;
416 SecCmsKEATemplateSelector whichKEA = SecCmsKEAInvalid;
417
418 certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
419 PORT_Assert(certalgtag == SEC_OID_X942_DIFFIE_HELMAN_KEY);
420
421 /* We really want to show our KEA tag as the key exchange algorithm tag. */
422 encalgtag = SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN;
423
424 /* Get the public key of the recipient. */
425 publickey = CERT_ExtractPublicKey(cert);
426 if (publickey == NULL) goto loser;
427
428 /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
429 /* XXXX */ourCert = PK11_FindBestKEAMatch(cert, wincx);
430 if (ourCert == NULL) goto loser;
431
432 arena = PORT_NewArena(1024);
433 if (arena == NULL) goto loser;
434
435 /* While we're here, extract the key pair's public key data and copy it into */
436 /* the outgoing parameters. */
437 /* XXXX */ourPubKey = CERT_ExtractPublicKey(ourCert);
438 if (ourPubKey == NULL)
439 {
440 goto loser;
441 }
442 SECITEM_CopyItem(arena, pubKey, /* XXX */&(ourPubKey->u.fortezza.KEAKey));
443 SECKEY_DestroyPublicKey(ourPubKey); /* we only need the private key from now on */
444 ourPubKey = NULL;
445
446 /* Extract our private key in order to derive the KEA key. */
447 ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
448 CERT_DestroyCertificate(ourCert); /* we're done with this */
449 if (!ourPrivKey) goto loser;
450
451 /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
452 if (ukm) {
453 ukm->Data = (unsigned char*)PORT_ArenaZAlloc(arena,/* XXXX */);
454 ukm->Length = /* XXXX */;
455 }
456
457 /* Generate the KEK (key exchange key) according to RFC2631 which we use
458 * to wrap the bulk encryption key. */
459 kek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
460 ukm, NULL,
461 /* XXXX */CKM_KEA_KEY_DERIVE, /* XXXX */CKM_SKIPJACK_WRAP,
462 CKA_WRAP, 0, wincx);
463
464 SECKEY_DestroyPublicKey(publickey);
465 SECKEY_DestroyPrivateKey(ourPrivKey);
466 publickey = NULL;
467 ourPrivKey = NULL;
468
469 if (!kek)
470 goto loser;
471
472 /* allocate space for the encrypted CEK (bulk key) */
473 encKey->Data = (unsigned char*)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
474 encKey->Length = SMIME_FORTEZZA_MAX_KEY_SIZE;
475
476 if (encKey->Data == NULL)
477 {
478 CFRelease(kek);
479 goto loser;
480 }
481
482
483 /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
484 /* bulk encryption algorithm */
485 switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo->encalg))
486 {
487 case /* XXXX */CKM_SKIPJACK_CFB8:
488 err = PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP, NULL, kek, bulkkey, encKey);
489 whichKEA = SecCmsKEAUsesSkipjack;
490 break;
491 case /* XXXX */CKM_SKIPJACK_CFB8:
492 err = PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP, NULL, kek, bulkkey, encKey);
493 whichKEA = SecCmsKEAUsesSkipjack;
494 break;
495 default:
496 /* XXXX what do we do here? Neither RC2 nor 3DES... */
497 err = SECFailure;
498 /* set error */
499 break;
500 }
501
502 CFRelease(kek); /* we do not need the KEK anymore */
503 if (err != SECSuccess)
504 goto loser;
505
506 PORT_Assert(whichKEA != SecCmsKEAInvalid);
507
508 /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
509 /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
510 params = SEC_ASN1EncodeItem(arena, NULL, &keaParams, sec_pkcs7_get_kea_template(whichKEA));
511 if (params == NULL)
512 goto loser;
513
514 /* now set keyEncAlg */
515 rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN, params);
516 if (rv != SECSuccess)
517 goto loser;
518
519 /* XXXXXXX this is not right yet */
520 loser:
521 if (arena) {
522 PORT_FreeArena(arena, PR_FALSE);
523 }
524 if (publickey) {
525 SECKEY_DestroyPublicKey(publickey);
526 }
527 if (ourPrivKey) {
528 SECKEY_DestroyPrivateKey(ourPrivKey);
529 }
530 #endif
531 return SECFailure;
532 }
533
534 SecSymmetricKeyRef
535 SecCmsUtilDecryptSymKeyESDH(SecPrivateKeyRef privkey, SecAsn1Item * encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
536 {
537 #if 0 /* not yet done */
538 OSStatus err;
539 CK_MECHANISM_TYPE bulkType;
540 SecSymmetricKeyRef tek;
541 SecPublicKeyRef originatorPubKey;
542 SecCmsSMIMEKEAParameters keaParams;
543
544 /* XXXX get originator's public key */
545 originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.Data,
546 keaParams.originatorKEAKey.Length);
547 if (originatorPubKey == NULL)
548 goto loser;
549
550 /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
551 The Derive function generates a shared secret and combines it with the originatorRA
552 data to come up with an unique session key */
553 tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
554 &keaParams.originatorRA, NULL,
555 CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
556 CKA_WRAP, 0, pwfn_arg);
557 SECKEY_DestroyPublicKey(originatorPubKey); /* not needed anymore */
558 if (tek == NULL)
559 goto loser;
560
561 /* Now that we have the TEK, unwrap the bulk key
562 with which to decrypt the message. */
563 /* Skipjack is being used as the bulk encryption algorithm.*/
564 /* Unwrap the bulk key. */
565 bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
566 encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
567
568 return bulkkey;
569
570 loser:
571 #endif
572 return NULL;
573 }
574
575 #endif
576
577 /* ====== ECDH (Ephemeral-Static Diffie-Hellman) ==================================== */
578
579 #pragma mark ---- ECDH support functions ----
580
581 #ifdef NDEBUG
582 #define CSSM_PERROR(f, r)
583 #define dprintf(args...)
584 #else
585 #define CSSM_PERROR(f, r) cssmPerror(f, r)
586 #define dprintf(args...) fprintf(stderr, args)
587 #endif
588
589 /* Length of KeyAgreeRecipientInfo.ukm we create */
590 #define UKM_LENGTH 8
591
592 /* KEK algorithm info we generate */
593 #define ECDH_KEK_ALG_TAG SEC_OID_DES_EDE3_CBC
594 #define ECDH_KEK_KEY_CSSM_ALGID CSSM_ALGID_3DES_3KEY
595 #define ECDH_KEK_ENCR_CSSM_ALGID CSSM_ALGID_3DES_3KEY_EDE
596 #define ECDH_KEK_KEY_LEN_BYTES 24
597 #define ECDH_KEK_IV_LEN_BYTES 8
598
599 #define CMS_DUMP_BUFS 0
600 #if CMS_DUMP_BUFS
601
602 static void dumpBuf(
603 const char *label,
604 const CSSM_DATA *cd)
605 {
606 unsigned dex;
607
608 printf("%s:\n ", label);
609 for(dex=0; dex<cd->Length; dex++) {
610 printf("%02X ", cd->Data[dex]);
611 if(((dex % 16) == 15) && (dex != (cd->Length - 1))) {
612 printf("\n ");
613 }
614 }
615 putchar('\n');
616 }
617
618 #else
619 #define dumpBuf(l, d)
620 #endif /* CMS_DUMP_BUFS */
621
622 /*
623 * The ECC-CMS-SharedInfo struct, as defined in RFC 3278 8.2, and the
624 * template for DER encoding and decoding it.
625 */
626 typedef struct {
627 SECAlgorithmID algId; /* KEK alg, NULL params */
628 SecAsn1Item entityUInfo; /* optional, ukm */
629 SecAsn1Item suppPubInfo; /* length of KEK in bits as 4-byte integer */
630 } ECC_CMS_SharedInfo;
631
632 static const SecAsn1Template ECC_CMS_SharedInfoTemplate[] = {
633 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ECC_CMS_SharedInfo) },
634 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 0,
635 offsetof(ECC_CMS_SharedInfo,entityUInfo),
636 kSecAsn1OctetStringTemplate },
637 { SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 2,
638 offsetof(ECC_CMS_SharedInfo,suppPubInfo),
639 kSecAsn1OctetStringTemplate },
640 { 0 }
641 };
642
643 /*
644 * Given a context specified via a CSSM_CC_HANDLE, add a new
645 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
646 * AttributeLength, and an untyped pointer.
647 */
648 /* specify either 32-bit integer or a pointer as an added attribute value */
649 typedef enum {
650 CAT_Uint32,
651 CAT_Ptr
652 } ContextAttrType;
653
654 /* convert uint32 to big-endian 4 bytes */
655 static void int32ToBytes(
656 uint32_t i,
657 unsigned char *b)
658 {
659 int dex;
660 for(dex=3; dex>=0; dex--) {
661 b[dex] = i;
662 i >>= 8;
663 }
664 }
665
666 /*
667 * Given an OID tag, return key size and mode.
668 * NOTE: ciphers with variable key sizes, like RC2, RC4, and RC5 cannot
669 * be used here because the message does not contain a key size
670 * indication.
671 */
672 static OSStatus encrAlgInfo(
673 SECOidTag oidTag,
674 uint32_t *keySizeBits, /* RETURNED */
675 CCAlgorithm *algorithm, /* RETURNED */
676 CCOptions *options) /* RETURNED */
677 {
678 *keySizeBits = 64; /* default */
679 *options = kCCOptionPKCS7Padding; /* default */
680
681 switch(oidTag) {
682 case SEC_OID_RC2_CBC:
683 case SEC_OID_RC4:
684 case SEC_OID_RC5_CBC_PAD:
685 dprintf("encrAlgInfo: key size unknowable\n");
686 return errSecNotAvailable;
687 case SEC_OID_DES_EDE:
688 /* Not sure about this; SecCmsCipherContextStart() treats this
689 * like SEC_OID_DES_EDE3_CBC... */
690 *options = kCCOptionECBMode;
691 // fall through
692 case SEC_OID_DES_EDE3_CBC:
693 *keySizeBits = 192;
694 *algorithm = kCCAlgorithm3DES;
695 break;
696 case SEC_OID_DES_ECB:
697 *options = kCCOptionECBMode;
698 // fall through
699 case SEC_OID_DES_CBC:
700 *algorithm = kCCAlgorithmDES;
701 break;
702 case SEC_OID_AES_128_CBC:
703 *keySizeBits = 128;
704 *algorithm = kCCAlgorithmAES;
705 break;
706 case SEC_OID_AES_192_CBC:
707 *keySizeBits = 192;
708 *algorithm = kCCAlgorithmAES;
709 break;
710 case SEC_OID_AES_256_CBC:
711 *keySizeBits = 256;
712 *algorithm = kCCAlgorithmAES;
713 break;
714 case SEC_OID_AES_128_ECB:
715 *keySizeBits = 128;
716 *algorithm = kCCAlgorithmAES;
717 *options = kCCOptionECBMode;
718 break;
719 case SEC_OID_AES_192_ECB:
720 *keySizeBits = 192;
721 *algorithm = kCCAlgorithmAES;
722 *options = kCCOptionECBMode;
723 break;
724 case SEC_OID_AES_256_ECB:
725 *keySizeBits = 256;
726 *algorithm = kCCAlgorithmAES;
727 *options = kCCOptionECBMode;
728 break;
729 default:
730 dprintf("encrAlgInfo: unknown alg tag (%d)\n", (int)oidTag);
731 return errSecNotAvailable;
732 }
733 return noErr;
734 }
735
736 #pragma mark ---- ECDH CEK key wrap ----
737
738 /*
739 * Encrypt bulk encryption key (a.k.a. content encryption key, CEK) using ECDH
740 */
741 OSStatus
742 SecCmsUtilEncryptSymKeyECDH(
743 PLArenaPool *poolp,
744 SecCertificateRef cert, /* recipient's cert */
745 SecSymmetricKeyRef key, /* bulk key */
746 /* remaining fields RETURNED */
747 SecAsn1Item *encKey, /* encrypted key --> recipientEncryptedKeys[0].EncryptedKey */
748 SecAsn1Item *ukm, /* random UKM --> KeyAgreeRecipientInfo.ukm */
749 SECAlgorithmID *keyEncAlg, /* alg := dhSinglePass-stdDH-sha1kdf-scheme
750 * params := another encoded AlgId, with the KEK alg and IV */
751 SecAsn1Item *pubKey) /* our pub key as ECPoint -->
752 * KeyAgreeRecipientInfo.originator.OriginatorPublicKey */
753 {
754 OSStatus rv = noErr;
755 SecKeyRef theirPubKey = NULL, ourPubKey = NULL, ourPrivKey = NULL;
756 CFDictionaryRef theirKeyAttrs = NULL, ourKeyParams = NULL, kekParams = NULL;
757 uint8_t iv[ECDH_KEK_IV_LEN_BYTES];
758 SecAsn1Item ivData = { ECDH_KEK_IV_LEN_BYTES, iv };
759 SECAlgorithmID kekAlgId;
760 SECOidData *kekOid;
761 ECC_CMS_SharedInfo sharedInfo;
762 SecAsn1Item sharedInfoEnc = {0, NULL};
763 uint8_t nullData[2] = {SEC_ASN1_NULL, 0};
764 uint8_t keyLenAsBytes[4];
765 CFDataRef sharedInfoData = NULL, kekData = NULL, ourPubData = NULL;
766 CFNumberRef kekLen = NULL;
767 CFErrorRef error = NULL;
768 CCCryptorRef ciphercc = NULL;
769
770 encKey->Data = NULL;
771 encKey->Length = 0;
772
773 /* Copy the recipient's static public ECDH key */
774 theirPubKey = SecCertificateCopyKey(cert);
775 if (rv || !theirPubKey) {
776 dprintf("SecCmsUtilEncryptSymKeyECDH: failed to get public key from cert, %d\n", (int)rv);
777 goto out;
778 }
779
780 theirKeyAttrs = SecKeyCopyAttributes(theirPubKey);
781 if (!theirKeyAttrs) {
782 dprintf("SecCmsUtilEncryptSymKeyECDH: failed to get key attributes\n");
783 goto out;
784 }
785
786 CFStringRef keyType = NULL;
787 CFNumberRef keySizeNum = NULL;
788 keyType = CFDictionaryGetValue(theirKeyAttrs, kSecAttrKeyType);
789 keySizeNum = CFDictionaryGetValue(theirKeyAttrs, kSecAttrKeySizeInBits);
790
791 if (!CFEqual(kSecAttrKeyTypeECSECPrimeRandom, keyType)) {
792 dprintf("SecCmsUtilEncryptSymKeyECDH: unsupported key type\n");
793 rv = SEC_ERROR_INVALID_KEY;
794 goto out;
795 }
796
797 /* Generate ephemeral ECDH key */
798 const void *keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits};
799 const void *values[] = { keyType, keySizeNum };
800 ourKeyParams = CFDictionaryCreate(NULL, keys, values, 2,
801 &kCFTypeDictionaryKeyCallBacks,
802 &kCFTypeDictionaryValueCallBacks);
803 rv = SecKeyGeneratePair(ourKeyParams, &ourPubKey, &ourPrivKey);
804 if (rv || !ourPubKey || !ourPrivKey) {
805 dprintf("SecKeyGeneratePair: unable to generate ECDH key pair, %d\n", (int)rv);
806 goto out;
807 }
808
809 /* Generate UKM */
810 ukm->Data = PORT_Alloc(UKM_LENGTH);
811 ukm->Length = UKM_LENGTH;
812 rv = CCRandomCopyBytes(kCCRandomDefault, ukm->Data, UKM_LENGTH);
813 if (rv || !ukm->Data) {
814 dprintf("CCRandomGenerateBytes failed, %d", (int)rv);
815 goto out;
816 }
817 ukm->Length = UKM_LENGTH;
818
819 /*
820 * OK, we have to set up a weird SECAlgorithmID.
821 * algorithm = dhSinglePass-stdDH-sha1kdf-scheme
822 * params = an encoded SECAlgorithmID representing the KEK algorithm, with
823 * algorithm = whatever we pick
824 * parameters = IV as octet string (though I haven't seen that specified
825 * anywhere; it's how the CEK IV is encoded)
826 */
827
828 /* Generate 8-byte IV */
829 rv = CCRandomCopyBytes(kCCRandomDefault, iv, ECDH_KEK_IV_LEN_BYTES);
830 if (rv) {
831 dprintf("CCRandomGenerateBytes failed, %d", (int)rv);
832 goto out;
833 }
834 dumpBuf("sender IV", &ivData);
835
836 memset(&kekAlgId, 0, sizeof(kekAlgId));
837 if (!SEC_ASN1EncodeItem(poolp, &kekAlgId.parameters,
838 &ivData, kSecAsn1OctetStringTemplate)) {
839 rv = errSecInternalComponent;
840 goto out;
841 }
842
843 /* Drop in the KEK OID and encode the whole thing */
844 kekOid = SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG);
845 if(kekOid == NULL) {
846 dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n");
847 rv = errSecInternalComponent;
848 goto out;
849 }
850 kekAlgId.algorithm = kekOid->oid;
851 memset(keyEncAlg, 0, sizeof(*keyEncAlg));
852 if (!SEC_ASN1EncodeItem(poolp, &keyEncAlg->parameters,
853 &kekAlgId, SECOID_AlgorithmIDTemplate)) {
854 rv = errSecInternalComponent;
855 goto out;
856 }
857 kekOid = SECOID_FindOIDByTag(SEC_OID_DH_SINGLE_STD_SHA1KDF);
858 if(kekOid == NULL) {
859 dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n");
860 rv = errSecInternalComponent;
861 goto out;
862 }
863 keyEncAlg->algorithm = kekOid->oid;
864
865 /*
866 * Now in order to derive the KEK proper, we have to create a
867 * ECC-CMS-SharedInfo, which does not appear in the message, and DER
868 * encode that struct, the result of which is used as the
869 * SharedInfo value in the KEK key derive.
870 */
871 memset(&sharedInfo, 0, sizeof(sharedInfo));
872 kekOid = SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG);
873 sharedInfo.algId.algorithm = kekOid->oid;
874 sharedInfo.algId.parameters.Data = nullData;
875 sharedInfo.algId.parameters.Length = 2;
876 sharedInfo.entityUInfo = *ukm;
877 int32ToBytes(ECDH_KEK_KEY_LEN_BYTES << 3, keyLenAsBytes);
878 sharedInfo.suppPubInfo.Length = 4;
879 sharedInfo.suppPubInfo.Data = keyLenAsBytes;
880 if (!SEC_ASN1EncodeItem(poolp, &sharedInfoEnc,
881 &sharedInfo, ECC_CMS_SharedInfoTemplate)) {
882 rv = errSecInternalComponent;
883 goto out;
884 }
885 dumpBuf("sender encoded SharedInfo", &sharedInfoEnc);
886
887 /* Derive KEK */
888 sharedInfoData = CFDataCreate(NULL, sharedInfoEnc.Data, sharedInfoEnc.Length);
889 int32_t ecdh_key_key_len = ECDH_KEK_KEY_LEN_BYTES;
890 kekLen = CFNumberCreate(NULL, kCFNumberSInt32Type, &ecdh_key_key_len);
891 const void *kekKeys[] = { kSecKeyKeyExchangeParameterRequestedSize, kSecKeyKeyExchangeParameterSharedInfo };
892 const void *kekValues[] = { kekLen, sharedInfoData };
893 kekParams = CFDictionaryCreate(NULL, kekKeys, kekValues, 2,
894 &kCFTypeDictionaryKeyCallBacks,
895 &kCFTypeDictionaryValueCallBacks);
896 kekData = SecKeyCopyKeyExchangeResult(ourPrivKey, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1,
897 theirPubKey, kekParams, &error);
898 if (error) {
899 dprintf("SecKeyCopyKeyExchangeResult: failed\n");
900 goto out;
901 }
902
903 /*
904 * Encrypt the raw CEK bits with the KEK we just derived
905 */
906 rv = CCCryptorCreate(kCCEncrypt, kCCAlgorithm3DES, kCCOptionPKCS7Padding,
907 CFDataGetBytePtr(kekData), CFDataGetLength(kekData), iv, &ciphercc);
908 if (rv) {
909 dprintf("CCCryptorCreate failed: %d\n", (int)rv);
910 goto out;
911 }
912
913 size_t expectedEncKeyLength = CCCryptorGetOutputLength(ciphercc, CFDataGetLength(key), true);
914 encKey->Data = PORT_ArenaAlloc(poolp, expectedEncKeyLength);
915 size_t bytes_output = 0;
916 rv = CCCryptorUpdate(ciphercc, CFDataGetBytePtr(key), CFDataGetLength(key), encKey->Data, expectedEncKeyLength, &bytes_output);
917 if (rv) {
918 dprintf("CCCryptorUpdate failed: %d\n", (int)rv);
919 goto out;
920 }
921 size_t final_bytes_output = 0;
922 rv = CCCryptorFinal(ciphercc, encKey->Data+bytes_output, expectedEncKeyLength - bytes_output, &final_bytes_output);
923 if (rv) {
924 dprintf("CCCryptorFinal failed: %d\n", (int)rv);
925 goto out;
926 }
927 encKey->Length = bytes_output + final_bytes_output;
928
929 /* Provide our ephemeral public key to the caller */
930 ourPubData = SecKeyCopyExternalRepresentation(ourPubKey, &error);
931 if (error) {
932 dprintf("SecKeyCopyExternalRepresentation failed\n");
933 goto out;
934 }
935 pubKey->Length = CFDataGetLength(ourPubData);
936 pubKey->Data = malloc(pubKey->Length);
937 if (pubKey->Data) {
938 memcpy(pubKey->Data, CFDataGetBytePtr(ourPubData), pubKey->Length);
939 } else {
940 rv = errSecAllocate;
941 }
942 /* pubKey is bit string, convert here */
943 pubKey->Length <<= 3;
944
945 out:
946 if (theirPubKey) { CFRelease(theirPubKey); }
947 if (theirKeyAttrs) { CFRelease(theirKeyAttrs); }
948 if (ourKeyParams) { CFRelease(ourKeyParams); }
949 if (ourPubKey) { CFRelease(ourPubKey); }
950 if (ourPrivKey) { CFRelease(ourPrivKey); }
951 if (sharedInfoData) { CFRelease(sharedInfoData); }
952 if (kekLen) { CFRelease(kekLen); }
953 if (kekParams) { CFRelease(kekParams); }
954 if (kekData) { CFRelease(kekData); }
955 if (error) { CFRelease(error); }
956 if (ciphercc) { CCCryptorRelease(ciphercc); }
957 if (ourPubData) { CFRelease(ourPubData); }
958 if (rv && encKey->Data) {
959 PORT_Free(encKey->Data);
960 encKey->Data = NULL;
961 encKey->Length = 0;
962 }
963 if (rv && ukm->Data) {
964 PORT_Free(ukm->Data);
965 ukm->Data = NULL;
966 ukm->Length = 0;
967 }
968 return rv;
969 }
970
971
972 #pragma mark ---- ECDH CEK key unwrap ----
973
974 SecSymmetricKeyRef
975 SecCmsUtilDecryptSymKeyECDH(
976 SecPrivateKeyRef privkey, /* our private key */
977 SecAsn1Item *encKey, /* encrypted CEK */
978 SecAsn1Item *ukm, /* random UKM from KeyAgreeRecipientInfo.ukm */
979 SECAlgorithmID *keyEncAlg, /* alg := dhSinglePass-stdDH-sha1kdf-scheme
980 * params := another encoded AlgId, with the KEK alg and IV */
981 SECOidTag bulkalgtag, /* algorithm of returned key */
982 SecAsn1Item *pubKey) /* sender's pub key as ECPoint from
983 * KeyAgreeRecipientInfo.originator.OriginatorPublicKey */
984 {
985 SecSymmetricKeyRef outKey = NULL;
986 OSStatus rv = noErr;
987 PLArenaPool *pool = NULL;
988 SECAlgorithmID keyAlgParam;
989 SECOidData *kekOid = NULL;
990 SecAsn1Item iv = {0, NULL};
991 ECC_CMS_SharedInfo sharedInfo;
992 SecAsn1Item sharedInfoEnc = {0, NULL};
993 uint8_t nullData[2] = {SEC_ASN1_NULL, 0};
994 uint8_t keyLenAsBytes[4];
995 uint32_t kekSizeBits;
996 SecKeyRef theirPubKey = NULL;
997 CFDictionaryRef theirKeyAttrs = NULL, kekParams = NULL;
998 CFDataRef sharedInfoData = NULL, theirPubData= NULL, kekData = NULL;
999 CFNumberRef kekLen = NULL, theirKeyLen = NULL;
1000 CFErrorRef error = NULL;
1001 CCAlgorithm alg;
1002 CCOptions options = 0;
1003 CCCryptorRef ciphercc = NULL;
1004 size_t theirKeySizeInBits = 0;
1005
1006 /*
1007 * Decode keyEncAlg.params to get KEK algorithm and IV
1008 */
1009 pool = PORT_NewArena(1024);
1010 if(pool == NULL) {
1011 goto out;
1012 }
1013 memset(&keyAlgParam, 0, sizeof(keyAlgParam));
1014 if(SEC_ASN1DecodeItem(pool, &keyAlgParam, SECOID_AlgorithmIDTemplate,
1015 &keyEncAlg->parameters)) {
1016 dprintf("SecCmsUtilDecryptSymKeyECDH: error decoding keyAlgParams\n");
1017 goto out;
1018 }
1019 kekOid = SECOID_FindOID(&keyAlgParam.algorithm);
1020 if(kekOid == NULL) {
1021 dprintf("SecCmsUtilDecryptSymKeyECDH: unknown KEK enc OID\n");
1022 goto out;
1023 }
1024 rv = encrAlgInfo(kekOid->offset, &kekSizeBits, &alg, &options);
1025 if(rv) {
1026 goto out;
1027 }
1028 /* IV is OCTET STRING in the alg params */
1029 if(SEC_ASN1DecodeItem(pool, &iv, kSecAsn1OctetStringTemplate,
1030 &keyAlgParam.parameters)) {
1031 /*
1032 * Not sure here - is it legal to have no IV? I haven't seen this
1033 * addressed in any spec. Maybe we should condition the behavior
1034 * here on the KEK algorithm.
1035 */
1036 dprintf("SecCmsUtilDecryptSymKeyECDH: no KEK IV\n");
1037 goto out;
1038 }
1039
1040 /*
1041 * Now in order to derive the KEK proper, we have to create a
1042 * ECC-CMS-SharedInfo, which does not appear in the message, and DER
1043 * encode that struct, the result of which is used as the
1044 * SharedInfo value in the KEK key derive.
1045 */
1046 memset(&sharedInfo, 0, sizeof(sharedInfo));
1047 sharedInfo.algId.algorithm = kekOid->oid;
1048 sharedInfo.algId.parameters.Data = nullData;
1049 sharedInfo.algId.parameters.Length = 2;
1050 sharedInfo.entityUInfo = *ukm;
1051 int32ToBytes(kekSizeBits, keyLenAsBytes);
1052 sharedInfo.suppPubInfo.Length = 4;
1053 sharedInfo.suppPubInfo.Data = keyLenAsBytes;
1054 if (!SEC_ASN1EncodeItem(pool, &sharedInfoEnc,
1055 &sharedInfo, ECC_CMS_SharedInfoTemplate)) {
1056 goto out;
1057 }
1058 dumpBuf("receiver encoded SharedInfo", &sharedInfoEnc);
1059 dumpBuf("receiver IV", &iv);
1060 dumpBuf("receiver UKM", ukm);
1061 dumpBuf("sender's public key", pubKey);
1062
1063 /* pubKey is bit string, convert here */
1064 theirKeySizeInBits = pubKey->Length;
1065 pubKey->Length = (theirKeySizeInBits + 7) >> 3;
1066 theirPubData = CFDataCreate(NULL, pubKey->Data, pubKey->Length);
1067 theirKeyLen = CFNumberCreate(NULL, kCFNumberSInt64Type, &theirKeySizeInBits);
1068 const void *keys[] = { kSecAttrKeyType, kSecAttrKeyClass, kSecAttrKeySizeInBits };
1069 const void *values[] = { kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClassPublic, theirKeyLen};
1070 theirKeyAttrs = CFDictionaryCreate(NULL, keys, values, 3,
1071 &kCFTypeDictionaryKeyCallBacks,
1072 &kCFTypeDictionaryValueCallBacks);
1073 theirPubKey = SecKeyCreateWithData(theirPubData, theirKeyAttrs, &error);
1074 if (error) {
1075 dprintf("SecKeyCreateWithData: failed\n");
1076 goto out;
1077 }
1078
1079 /* Derive KEK */
1080 sharedInfoData = CFDataCreate(NULL, sharedInfoEnc.Data, sharedInfoEnc.Length);
1081 int32_t ecdh_key_key_len = (kekSizeBits + 7) >> 3;
1082 kekLen = CFNumberCreate(NULL, kCFNumberSInt32Type, &ecdh_key_key_len);
1083 const void *kekKeys[] = { kSecKeyKeyExchangeParameterRequestedSize, kSecKeyKeyExchangeParameterSharedInfo };
1084 const void *kekValues[] = { kekLen, sharedInfoData };
1085 kekParams = CFDictionaryCreate(NULL, kekKeys, kekValues, 2,
1086 &kCFTypeDictionaryKeyCallBacks,
1087 &kCFTypeDictionaryValueCallBacks);
1088 kekData = SecKeyCopyKeyExchangeResult(privkey, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1,
1089 theirPubKey, kekParams, &error);
1090 if (error) {
1091 dprintf("SecKeyCopyKeyExchangeResult: failed\n");
1092 goto out;
1093 }
1094
1095 /*
1096 * Decrypt the raw CEK bits with the KEK we just derived
1097 */
1098 SecAsn1Item cek = { 0, NULL };
1099 rv = CCCryptorCreate(kCCDecrypt, alg, options,
1100 CFDataGetBytePtr(kekData), CFDataGetLength(kekData), iv.Data, &ciphercc);
1101 if (rv) {
1102 dprintf("CCCryptorCreate failed: %d\n", (int)rv);
1103 goto out;
1104 }
1105 size_t expectedKeyLength = CCCryptorGetOutputLength(ciphercc, encKey->Length, true);
1106 cek.Data = PORT_ArenaAlloc(pool, expectedKeyLength);
1107 size_t bytes_output = 0;
1108 rv = CCCryptorUpdate(ciphercc, encKey->Data, encKey->Length, cek.Data, expectedKeyLength, &bytes_output);
1109 if (rv) {
1110 dprintf("CCCryptorUpdate failed: %d\n", (int)rv);
1111 goto out;
1112 }
1113 size_t final_bytes_output = 0;
1114 rv = CCCryptorFinal(ciphercc, cek.Data+bytes_output, expectedKeyLength - bytes_output, &final_bytes_output);
1115 if (rv) {
1116 dprintf("CCCryptorFinal failed: %d\n", (int)rv);
1117 goto out;
1118 }
1119 cek.Length = bytes_output + final_bytes_output;
1120
1121 /* create the SecSymmetricKeyRef */
1122 outKey = (SecSymmetricKeyRef)CFDataCreate(NULL, cek.Data, cek.Length);
1123
1124 out:
1125 if (pool != NULL) {
1126 PORT_FreeArena(pool, PR_FALSE);
1127 }
1128 if (theirPubData) { CFRelease(theirPubData); }
1129 if (theirKeyLen) { CFRelease(theirKeyLen); }
1130 if (theirPubKey) { CFRelease(theirPubKey); }
1131 if (theirKeyAttrs) { CFRelease(theirKeyAttrs); }
1132 if (sharedInfoData) { CFRelease(sharedInfoData); }
1133 if (kekLen) { CFRelease(kekLen); }
1134 if (kekParams) { CFRelease(kekParams); }
1135 if (kekData) { CFRelease(kekData); }
1136 if (error) { CFRelease(error); }
1137 if (ciphercc) { CCCryptorRelease(ciphercc); }
1138 if (outKey == NULL) {
1139 PORT_SetError(SEC_ERROR_NO_KEY);
1140 }
1141 return outKey;
1142 }