Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C; tab-width: 8 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "crmf.h"
7 #include "crmfi.h"
8 #include "pk11func.h"
9 #include "keyhi.h"
10 #include "secoid.h"
12 static SECStatus
13 crmf_modify_control_array (CRMFCertRequest *inCertReq, int count)
14 {
15 if (count > 0) {
16 void *dummy = PORT_Realloc(inCertReq->controls,
17 sizeof(CRMFControl*)*(count+2));
18 if (dummy == NULL) {
19 return SECFailure;
20 }
21 inCertReq->controls = dummy;
22 } else {
23 inCertReq->controls = PORT_ZNewArray(CRMFControl*, 2);
24 }
25 return (inCertReq->controls == NULL) ? SECFailure : SECSuccess ;
26 }
28 static SECStatus
29 crmf_add_new_control(CRMFCertRequest *inCertReq,SECOidTag inTag,
30 CRMFControl **destControl)
31 {
32 SECOidData *oidData;
33 SECStatus rv;
34 PLArenaPool *poolp;
35 int numControls = 0;
36 CRMFControl *newControl;
37 CRMFControl **controls;
38 void *mark;
40 poolp = inCertReq->poolp;
41 if (poolp == NULL) {
42 return SECFailure;
43 }
44 mark = PORT_ArenaMark(poolp);
45 if (inCertReq->controls != NULL) {
46 while (inCertReq->controls[numControls] != NULL)
47 numControls++;
48 }
49 rv = crmf_modify_control_array(inCertReq, numControls);
50 if (rv != SECSuccess) {
51 goto loser;
52 }
53 controls = inCertReq->controls;
54 oidData = SECOID_FindOIDByTag(inTag);
55 newControl = *destControl = PORT_ArenaZNew(poolp,CRMFControl);
56 if (newControl == NULL) {
57 goto loser;
58 }
59 rv = SECITEM_CopyItem(poolp, &newControl->derTag, &oidData->oid);
60 if (rv != SECSuccess) {
61 goto loser;
62 }
63 newControl->tag = inTag;
64 controls[numControls] = newControl;
65 controls[numControls+1] = NULL;
66 PORT_ArenaUnmark(poolp, mark);
67 return SECSuccess;
69 loser:
70 PORT_ArenaRelease(poolp, mark);
71 *destControl = NULL;
72 return SECFailure;
74 }
76 static SECStatus
77 crmf_add_secitem_control(CRMFCertRequest *inCertReq, SECItem *value,
78 SECOidTag inTag)
79 {
80 SECStatus rv;
81 CRMFControl *newControl;
82 void *mark;
84 rv = crmf_add_new_control(inCertReq, inTag, &newControl);
85 if (rv != SECSuccess) {
86 return rv;
87 }
88 mark = PORT_ArenaMark(inCertReq->poolp);
89 rv = SECITEM_CopyItem(inCertReq->poolp, &newControl->derValue, value);
90 if (rv != SECSuccess) {
91 PORT_ArenaRelease(inCertReq->poolp, mark);
92 return rv;
93 }
94 PORT_ArenaUnmark(inCertReq->poolp, mark);
95 return SECSuccess;
96 }
98 SECStatus
99 CRMF_CertRequestSetRegTokenControl(CRMFCertRequest *inCertReq, SECItem *value)
100 {
101 return crmf_add_secitem_control(inCertReq, value,
102 SEC_OID_PKIX_REGCTRL_REGTOKEN);
103 }
105 SECStatus
106 CRMF_CertRequestSetAuthenticatorControl (CRMFCertRequest *inCertReq,
107 SECItem *value)
108 {
109 return crmf_add_secitem_control(inCertReq, value,
110 SEC_OID_PKIX_REGCTRL_AUTHENTICATOR);
111 }
113 SECStatus
114 crmf_destroy_encrypted_value(CRMFEncryptedValue *inEncrValue, PRBool freeit)
115 {
116 if (inEncrValue != NULL) {
117 if (inEncrValue->intendedAlg) {
118 SECOID_DestroyAlgorithmID(inEncrValue->intendedAlg, PR_TRUE);
119 inEncrValue->intendedAlg = NULL;
120 }
121 if (inEncrValue->symmAlg) {
122 SECOID_DestroyAlgorithmID(inEncrValue->symmAlg, PR_TRUE);
123 inEncrValue->symmAlg = NULL;
124 }
125 if (inEncrValue->encSymmKey.data) {
126 PORT_Free(inEncrValue->encSymmKey.data);
127 inEncrValue->encSymmKey.data = NULL;
128 }
129 if (inEncrValue->keyAlg) {
130 SECOID_DestroyAlgorithmID(inEncrValue->keyAlg, PR_TRUE);
131 inEncrValue->keyAlg = NULL;
132 }
133 if (inEncrValue->valueHint.data) {
134 PORT_Free(inEncrValue->valueHint.data);
135 inEncrValue->valueHint.data = NULL;
136 }
137 if (inEncrValue->encValue.data) {
138 PORT_Free(inEncrValue->encValue.data);
139 inEncrValue->encValue.data = NULL;
140 }
141 if (freeit) {
142 PORT_Free(inEncrValue);
143 }
144 }
145 return SECSuccess;
146 }
148 SECStatus
149 CRMF_DestroyEncryptedValue(CRMFEncryptedValue *inEncrValue)
150 {
151 return crmf_destroy_encrypted_value(inEncrValue, PR_TRUE);
152 }
154 SECStatus
155 crmf_copy_encryptedvalue_secalg(PLArenaPool *poolp,
156 SECAlgorithmID *srcAlgId,
157 SECAlgorithmID **destAlgId)
158 {
159 SECAlgorithmID *newAlgId;
160 SECStatus rv;
162 newAlgId = (poolp != NULL) ? PORT_ArenaZNew(poolp, SECAlgorithmID) :
163 PORT_ZNew(SECAlgorithmID);
164 if (newAlgId == NULL) {
165 return SECFailure;
166 }
168 rv = SECOID_CopyAlgorithmID(poolp, newAlgId, srcAlgId);
169 if (rv != SECSuccess) {
170 if (!poolp) {
171 SECOID_DestroyAlgorithmID(newAlgId, PR_TRUE);
172 }
173 return rv;
174 }
175 *destAlgId = newAlgId;
177 return rv;
178 }
180 SECStatus
181 crmf_copy_encryptedvalue(PLArenaPool *poolp,
182 CRMFEncryptedValue *srcValue,
183 CRMFEncryptedValue *destValue)
184 {
185 SECStatus rv;
187 if (srcValue->intendedAlg != NULL) {
188 rv = crmf_copy_encryptedvalue_secalg(poolp,
189 srcValue->intendedAlg,
190 &destValue->intendedAlg);
191 if (rv != SECSuccess) {
192 goto loser;
193 }
194 }
195 if (srcValue->symmAlg != NULL) {
196 rv = crmf_copy_encryptedvalue_secalg(poolp,
197 srcValue->symmAlg,
198 &destValue->symmAlg);
199 if (rv != SECSuccess) {
200 goto loser;
201 }
202 }
203 if (srcValue->encSymmKey.data != NULL) {
204 rv = crmf_make_bitstring_copy(poolp,
205 &destValue->encSymmKey,
206 &srcValue->encSymmKey);
207 if (rv != SECSuccess) {
208 goto loser;
209 }
210 }
211 if (srcValue->keyAlg != NULL) {
212 rv = crmf_copy_encryptedvalue_secalg(poolp,
213 srcValue->keyAlg,
214 &destValue->keyAlg);
215 if (rv != SECSuccess) {
216 goto loser;
217 }
218 }
219 if (srcValue->valueHint.data != NULL) {
220 rv = SECITEM_CopyItem(poolp,
221 &destValue->valueHint,
222 &srcValue->valueHint);
223 if (rv != SECSuccess) {
224 goto loser;
225 }
226 }
227 if (srcValue->encValue.data != NULL) {
228 rv = crmf_make_bitstring_copy(poolp,
229 &destValue->encValue,
230 &srcValue->encValue);
231 if (rv != SECSuccess) {
232 goto loser;
233 }
234 }
235 return SECSuccess;
236 loser:
237 if (poolp == NULL && destValue != NULL) {
238 crmf_destroy_encrypted_value(destValue, PR_FALSE);
239 }
240 return SECFailure;
241 }
243 SECStatus
244 crmf_copy_encryptedkey(PLArenaPool *poolp,
245 CRMFEncryptedKey *srcEncrKey,
246 CRMFEncryptedKey *destEncrKey)
247 {
248 SECStatus rv;
249 void *mark = NULL;
251 if (poolp != NULL) {
252 mark = PORT_ArenaMark(poolp);
253 }
255 switch (srcEncrKey->encKeyChoice) {
256 case crmfEncryptedValueChoice:
257 rv = crmf_copy_encryptedvalue(poolp,
258 &srcEncrKey->value.encryptedValue,
259 &destEncrKey->value.encryptedValue);
260 break;
261 case crmfEnvelopedDataChoice:
262 destEncrKey->value.envelopedData =
263 SEC_PKCS7CopyContentInfo(srcEncrKey->value.envelopedData);
264 rv = (destEncrKey->value.envelopedData != NULL) ? SECSuccess:
265 SECFailure;
266 break;
267 default:
268 rv = SECFailure;
269 }
270 if (rv != SECSuccess) {
271 goto loser;
272 }
273 destEncrKey->encKeyChoice = srcEncrKey->encKeyChoice;
274 if (mark) {
275 PORT_ArenaUnmark(poolp, mark);
276 }
277 return SECSuccess;
279 loser:
280 if (mark) {
281 PORT_ArenaRelease(poolp, mark);
282 }
283 return SECFailure;
284 }
286 static CRMFPKIArchiveOptions*
287 crmf_create_encr_pivkey_option(CRMFEncryptedKey *inEncryptedKey)
288 {
289 CRMFPKIArchiveOptions *newArchOpt;
290 SECStatus rv;
292 newArchOpt = PORT_ZNew(CRMFPKIArchiveOptions);
293 if (newArchOpt == NULL) {
294 goto loser;
295 }
297 rv = crmf_copy_encryptedkey(NULL, inEncryptedKey,
298 &newArchOpt->option.encryptedKey);
300 if (rv != SECSuccess) {
301 goto loser;
302 }
303 newArchOpt->archOption = crmfEncryptedPrivateKey;
304 return newArchOpt;
305 loser:
306 if (newArchOpt != NULL) {
307 CRMF_DestroyPKIArchiveOptions(newArchOpt);
308 }
309 return NULL;
310 }
312 static CRMFPKIArchiveOptions*
313 crmf_create_keygen_param_option(SECItem *inKeyGenParams)
314 {
315 CRMFPKIArchiveOptions *newArchOptions;
316 SECStatus rv;
318 newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions);
319 if (newArchOptions == NULL) {
320 goto loser;
321 }
322 newArchOptions->archOption = crmfKeyGenParameters;
323 rv = SECITEM_CopyItem(NULL, &newArchOptions->option.keyGenParameters,
324 inKeyGenParams);
325 if (rv != SECSuccess) {
326 goto loser;
327 }
328 return newArchOptions;
329 loser:
330 if (newArchOptions != NULL) {
331 CRMF_DestroyPKIArchiveOptions(newArchOptions);
332 }
333 return NULL;
334 }
336 static CRMFPKIArchiveOptions*
337 crmf_create_arch_rem_gen_privkey(PRBool archiveRemGenPrivKey)
338 {
339 unsigned char value;
340 SECItem *dummy;
341 CRMFPKIArchiveOptions *newArchOptions;
343 value = (archiveRemGenPrivKey) ? hexTrue : hexFalse;
344 newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions);
345 if (newArchOptions == NULL) {
346 goto loser;
347 }
348 dummy = SEC_ASN1EncodeItem(NULL,
349 &newArchOptions->option.archiveRemGenPrivKey,
350 &value, SEC_ASN1_GET(SEC_BooleanTemplate));
351 PORT_Assert (dummy == &newArchOptions->option.archiveRemGenPrivKey);
352 if (dummy != &newArchOptions->option.archiveRemGenPrivKey) {
353 SECITEM_FreeItem (dummy, PR_TRUE);
354 goto loser;
355 }
356 newArchOptions->archOption = crmfArchiveRemGenPrivKey;
357 return newArchOptions;
358 loser:
359 if (newArchOptions != NULL) {
360 CRMF_DestroyPKIArchiveOptions(newArchOptions);
361 }
362 return NULL;
363 }
365 CRMFPKIArchiveOptions*
366 CRMF_CreatePKIArchiveOptions(CRMFPKIArchiveOptionsType inType, void *data)
367 {
368 CRMFPKIArchiveOptions* retOptions;
370 PORT_Assert(data != NULL);
371 if (data == NULL) {
372 return NULL;
373 }
374 switch(inType) {
375 case crmfEncryptedPrivateKey:
376 retOptions = crmf_create_encr_pivkey_option((CRMFEncryptedKey*)data);
377 break;
378 case crmfKeyGenParameters:
379 retOptions = crmf_create_keygen_param_option((SECItem*)data);
380 break;
381 case crmfArchiveRemGenPrivKey:
382 retOptions = crmf_create_arch_rem_gen_privkey(*(PRBool*)data);
383 break;
384 default:
385 retOptions = NULL;
386 }
387 return retOptions;
388 }
390 static SECStatus
391 crmf_destroy_encrypted_key(CRMFEncryptedKey *inEncrKey, PRBool freeit)
392 {
393 PORT_Assert(inEncrKey != NULL);
394 if (inEncrKey != NULL) {
395 switch (inEncrKey->encKeyChoice){
396 case crmfEncryptedValueChoice:
397 crmf_destroy_encrypted_value(&inEncrKey->value.encryptedValue,
398 PR_FALSE);
399 break;
400 case crmfEnvelopedDataChoice:
401 SEC_PKCS7DestroyContentInfo(inEncrKey->value.envelopedData);
402 break;
403 default:
404 break;
405 }
406 if (freeit) {
407 PORT_Free(inEncrKey);
408 }
409 }
410 return SECSuccess;
411 }
413 SECStatus
414 crmf_destroy_pkiarchiveoptions(CRMFPKIArchiveOptions *inArchOptions,
415 PRBool freeit)
416 {
417 PORT_Assert(inArchOptions != NULL);
418 if (inArchOptions != NULL) {
419 switch (inArchOptions->archOption) {
420 case crmfEncryptedPrivateKey:
421 crmf_destroy_encrypted_key(&inArchOptions->option.encryptedKey,
422 PR_FALSE);
423 break;
424 case crmfKeyGenParameters:
425 case crmfArchiveRemGenPrivKey:
426 /* This is a union, so having a pointer to one is like
427 * having a pointer to both.
428 */
429 SECITEM_FreeItem(&inArchOptions->option.keyGenParameters,
430 PR_FALSE);
431 break;
432 case crmfNoArchiveOptions:
433 break;
434 }
435 if (freeit) {
436 PORT_Free(inArchOptions);
437 }
438 }
439 return SECSuccess;
440 }
442 SECStatus
443 CRMF_DestroyPKIArchiveOptions(CRMFPKIArchiveOptions *inArchOptions)
444 {
445 return crmf_destroy_pkiarchiveoptions(inArchOptions, PR_TRUE);
446 }
448 static CK_MECHANISM_TYPE
449 crmf_get_non_pad_mechanism(CK_MECHANISM_TYPE type)
450 {
451 switch (type) {
452 case CKM_DES3_CBC_PAD:
453 return CKM_DES3_CBC;
454 case CKM_CAST5_CBC_PAD:
455 return CKM_CAST5_CBC;
456 case CKM_DES_CBC_PAD:
457 return CKM_DES_CBC;
458 case CKM_IDEA_CBC_PAD:
459 return CKM_IDEA_CBC;
460 case CKM_CAST3_CBC_PAD:
461 return CKM_CAST3_CBC;
462 case CKM_CAST_CBC_PAD:
463 return CKM_CAST_CBC;
464 case CKM_RC5_CBC_PAD:
465 return CKM_RC5_CBC;
466 case CKM_RC2_CBC_PAD:
467 return CKM_RC2_CBC;
468 case CKM_CDMF_CBC_PAD:
469 return CKM_CDMF_CBC;
470 }
471 return type;
472 }
474 static CK_MECHANISM_TYPE
475 crmf_get_pad_mech_from_tag(SECOidTag oidTag)
476 {
477 CK_MECHANISM_TYPE mechType;
478 SECOidData *oidData;
480 oidData = SECOID_FindOIDByTag(oidTag);
481 mechType = (CK_MECHANISM_TYPE)oidData->mechanism;
482 return PK11_GetPadMechanism(mechType);
483 }
485 static CK_MECHANISM_TYPE
486 crmf_get_best_privkey_wrap_mechanism(PK11SlotInfo *slot)
487 {
488 CK_MECHANISM_TYPE privKeyPadMechs[] = { CKM_DES3_CBC_PAD,
489 CKM_CAST5_CBC_PAD,
490 CKM_DES_CBC_PAD,
491 CKM_IDEA_CBC_PAD,
492 CKM_CAST3_CBC_PAD,
493 CKM_CAST_CBC_PAD,
494 CKM_RC5_CBC_PAD,
495 CKM_RC2_CBC_PAD,
496 CKM_CDMF_CBC_PAD };
497 int mechCount = sizeof(privKeyPadMechs)/sizeof(privKeyPadMechs[0]);
498 int i;
500 for (i=0; i < mechCount; i++) {
501 if (PK11_DoesMechanism(slot, privKeyPadMechs[i])) {
502 return privKeyPadMechs[i];
503 }
504 }
505 return CKM_INVALID_MECHANISM;
506 }
508 CK_MECHANISM_TYPE
509 CRMF_GetBestWrapPadMechanism(PK11SlotInfo *slot)
510 {
511 return crmf_get_best_privkey_wrap_mechanism(slot);
512 }
514 static SECItem*
515 crmf_get_iv(CK_MECHANISM_TYPE mechType)
516 {
517 int iv_size = PK11_GetIVLength(mechType);
518 SECItem *iv;
519 SECStatus rv;
521 iv = PORT_ZNew(SECItem);
522 if (iv == NULL) {
523 return NULL;
524 }
525 if (iv_size == 0) {
526 iv->data = NULL;
527 iv->len = 0;
528 return iv;
529 }
530 iv->data = PORT_NewArray(unsigned char, iv_size);
531 if (iv->data == NULL) {
532 iv->len = 0;
533 return iv;
534 }
535 iv->len = iv_size;
536 rv = PK11_GenerateRandom(iv->data, iv->len);
537 if (rv != SECSuccess) {
538 PORT_Free(iv->data);
539 iv->data = NULL;
540 iv->len = 0;
541 }
542 return iv;
543 }
545 SECItem*
546 CRMF_GetIVFromMechanism(CK_MECHANISM_TYPE mechType)
547 {
548 return crmf_get_iv(mechType);
549 }
551 CK_MECHANISM_TYPE
552 crmf_get_mechanism_from_public_key(SECKEYPublicKey *inPubKey)
553 {
554 CERTSubjectPublicKeyInfo *spki = NULL;
555 SECOidTag tag;
558 spki = SECKEY_CreateSubjectPublicKeyInfo(inPubKey);
559 if (spki == NULL) {
560 return CKM_INVALID_MECHANISM;
561 }
562 tag = SECOID_FindOIDTag(&spki->algorithm.algorithm);
563 SECKEY_DestroySubjectPublicKeyInfo(spki);
564 spki = NULL;
565 return PK11_AlgtagToMechanism(tag);
566 }
568 SECItem*
569 crmf_get_public_value(SECKEYPublicKey *pubKey, SECItem *dest)
570 {
571 SECItem *src;
573 switch(pubKey->keyType) {
574 case dsaKey:
575 src = &pubKey->u.dsa.publicValue;
576 break;
577 case rsaKey:
578 src = &pubKey->u.rsa.modulus;
579 break;
580 case dhKey:
581 src = &pubKey->u.dh.publicValue;
582 break;
583 default:
584 src = NULL;
585 break;
586 }
587 if (!src) {
588 PORT_SetError(SEC_ERROR_INVALID_ARGS);
589 return NULL;
590 }
592 if (dest != NULL) {
593 SECStatus rv = SECITEM_CopyItem(NULL, dest, src);
594 if (rv != SECSuccess) {
595 dest = NULL;
596 }
597 } else {
598 dest = SECITEM_ArenaDupItem(NULL, src);
599 }
600 return dest;
601 }
603 static SECItem*
604 crmf_decode_params(SECItem *inParams)
605 {
606 SECItem *params;
607 SECStatus rv = SECFailure;
608 PLArenaPool *poolp;
610 poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
611 if (poolp == NULL) {
612 return NULL;
613 }
615 params = PORT_ArenaZNew(poolp, SECItem);
616 if (params) {
617 rv = SEC_ASN1DecodeItem(poolp, params,
618 SEC_ASN1_GET(SEC_OctetStringTemplate),
619 inParams);
620 }
621 params = (rv == SECSuccess) ? SECITEM_ArenaDupItem(NULL, params) : NULL;
622 PORT_FreeArena(poolp, PR_FALSE);
623 return params;
624 }
626 static int
627 crmf_get_key_size_from_mech(CK_MECHANISM_TYPE mechType)
628 {
629 CK_MECHANISM_TYPE keyGen = PK11_GetKeyGen(mechType);
631 switch (keyGen) {
632 case CKM_CDMF_KEY_GEN:
633 case CKM_DES_KEY_GEN:
634 return 8;
635 case CKM_DES2_KEY_GEN:
636 return 16;
637 case CKM_DES3_KEY_GEN:
638 return 24;
639 }
640 return 0;
641 }
643 SECStatus
644 crmf_encrypted_value_unwrap_priv_key(PLArenaPool *poolp,
645 CRMFEncryptedValue *encValue,
646 SECKEYPrivateKey *privKey,
647 SECKEYPublicKey *newPubKey,
648 SECItem *nickname,
649 PK11SlotInfo *slot,
650 unsigned char keyUsage,
651 SECKEYPrivateKey **unWrappedKey,
652 void *wincx)
653 {
654 PK11SymKey *wrappingKey = NULL;
655 CK_MECHANISM_TYPE wrapMechType;
656 SECOidTag oidTag;
657 SECItem *params = NULL, *publicValue = NULL;
658 int keySize, origLen;
659 CK_KEY_TYPE keyType;
660 CK_ATTRIBUTE_TYPE *usage = NULL;
661 CK_ATTRIBUTE_TYPE rsaUsage[] = {
662 CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER };
663 CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN };
664 CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE };
665 int usageCount = 0;
667 oidTag = SECOID_GetAlgorithmTag(encValue->symmAlg);
668 wrapMechType = crmf_get_pad_mech_from_tag(oidTag);
669 keySize = crmf_get_key_size_from_mech(wrapMechType);
670 wrappingKey = PK11_PubUnwrapSymKey(privKey, &encValue->encSymmKey,
671 wrapMechType, CKA_UNWRAP, keySize);
672 if (wrappingKey == NULL) {
673 goto loser;
674 }/* Make the length a byte length instead of bit length*/
675 params = (encValue->symmAlg != NULL) ?
676 crmf_decode_params(&encValue->symmAlg->parameters) : NULL;
677 origLen = encValue->encValue.len;
678 encValue->encValue.len = CRMF_BITS_TO_BYTES(origLen);
679 publicValue = crmf_get_public_value(newPubKey, NULL);
680 switch(newPubKey->keyType) {
681 default:
682 case rsaKey:
683 keyType = CKK_RSA;
684 switch (keyUsage & (KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE)) {
685 case KU_KEY_ENCIPHERMENT:
686 usage = rsaUsage;
687 usageCount = 2;
688 break;
689 case KU_DIGITAL_SIGNATURE:
690 usage = &rsaUsage[2];
691 usageCount = 2;
692 break;
693 case KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE:
694 case 0: /* default to everything */
695 usage = rsaUsage;
696 usageCount = 4;
697 break;
698 }
699 break;
700 case dhKey:
701 keyType = CKK_DH;
702 usage = dhUsage;
703 usageCount = sizeof(dhUsage)/sizeof(dhUsage[0]);
704 break;
705 case dsaKey:
706 keyType = CKK_DSA;
707 usage = dsaUsage;
708 usageCount = sizeof(dsaUsage)/sizeof(dsaUsage[0]);
709 break;
710 }
711 PORT_Assert(usage != NULL);
712 PORT_Assert(usageCount != 0);
713 *unWrappedKey = PK11_UnwrapPrivKey(slot, wrappingKey, wrapMechType, params,
714 &encValue->encValue, nickname,
715 publicValue, PR_TRUE,PR_TRUE,
716 keyType, usage, usageCount, wincx);
717 encValue->encValue.len = origLen;
718 if (*unWrappedKey == NULL) {
719 goto loser;
720 }
721 SECITEM_FreeItem (publicValue, PR_TRUE);
722 if (params!= NULL) {
723 SECITEM_FreeItem(params, PR_TRUE);
724 }
725 PK11_FreeSymKey(wrappingKey);
726 return SECSuccess;
727 loser:
728 *unWrappedKey = NULL;
729 return SECFailure;
730 }
732 CRMFEncryptedValue *
733 crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey *inPrivKey,
734 SECKEYPublicKey *inCAKey,
735 CRMFEncryptedValue *destValue)
736 {
737 SECItem wrappedPrivKey, wrappedSymKey;
738 SECItem encodedParam, *dummy;
739 SECStatus rv;
740 CK_MECHANISM_TYPE pubMechType, symKeyType;
741 unsigned char *wrappedSymKeyBits;
742 unsigned char *wrappedPrivKeyBits;
743 SECItem *iv = NULL;
744 SECOidTag tag;
745 PK11SymKey *symKey;
746 PK11SlotInfo *slot;
747 SECAlgorithmID *symmAlg;
748 CRMFEncryptedValue *myEncrValue = NULL;
750 encodedParam.data = NULL;
751 wrappedSymKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
752 wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
753 if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) {
754 goto loser;
755 }
756 if (destValue == NULL) {
757 myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue);
758 if (destValue == NULL) {
759 goto loser;
760 }
761 }
763 pubMechType = crmf_get_mechanism_from_public_key(inCAKey);
764 if (pubMechType == CKM_INVALID_MECHANISM) {
765 /* XXX I should probably do something here for non-RSA
766 * keys that are in certs. (ie DSA)
767 * XXX or at least SET AN ERROR CODE.
768 */
769 goto loser;
770 }
771 slot = inPrivKey->pkcs11Slot;
772 PORT_Assert(slot != NULL);
773 symKeyType = crmf_get_best_privkey_wrap_mechanism(slot);
774 symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL);
775 if (symKey == NULL) {
776 goto loser;
777 }
779 wrappedSymKey.data = wrappedSymKeyBits;
780 wrappedSymKey.len = MAX_WRAPPED_KEY_LEN;
781 rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey);
782 if (rv != SECSuccess) {
783 goto loser;
784 }
785 /* Make the length of the result a Bit String length. */
786 wrappedSymKey.len <<= 3;
788 wrappedPrivKey.data = wrappedPrivKeyBits;
789 wrappedPrivKey.len = MAX_WRAPPED_KEY_LEN;
790 iv = crmf_get_iv(symKeyType);
791 rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv,
792 &wrappedPrivKey, NULL);
793 PK11_FreeSymKey(symKey);
794 if (rv != SECSuccess) {
795 goto loser;
796 }
797 /* Make the length of the result a Bit String length. */
798 wrappedPrivKey.len <<= 3;
799 rv = crmf_make_bitstring_copy(NULL,
800 &destValue->encValue,
801 &wrappedPrivKey);
802 if (rv != SECSuccess) {
803 goto loser;
804 }
806 rv = crmf_make_bitstring_copy(NULL,
807 &destValue->encSymmKey,
808 &wrappedSymKey);
809 if (rv != SECSuccess) {
810 goto loser;
811 }
812 destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID);
813 if (symmAlg == NULL) {
814 goto loser;
815 }
817 dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv,
818 SEC_ASN1_GET(SEC_OctetStringTemplate));
819 if (dummy != &encodedParam) {
820 SECITEM_FreeItem(dummy, PR_TRUE);
821 goto loser;
822 }
824 symKeyType = crmf_get_non_pad_mechanism(symKeyType);
825 tag = PK11_MechanismToAlgtag(symKeyType);
826 rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam);
827 if (rv != SECSuccess) {
828 goto loser;
829 }
830 SECITEM_FreeItem(&encodedParam, PR_FALSE);
831 PORT_Free(wrappedPrivKeyBits);
832 PORT_Free(wrappedSymKeyBits);
833 SECITEM_FreeItem(iv, PR_TRUE);
834 return destValue;
835 loser:
836 if (iv != NULL) {
837 SECITEM_FreeItem(iv, PR_TRUE);
838 }
839 if (myEncrValue != NULL) {
840 crmf_destroy_encrypted_value(myEncrValue, PR_TRUE);
841 }
842 if (wrappedSymKeyBits != NULL) {
843 PORT_Free(wrappedSymKeyBits);
844 }
845 if (wrappedPrivKeyBits != NULL) {
846 PORT_Free(wrappedPrivKeyBits);
847 }
848 if (encodedParam.data != NULL) {
849 SECITEM_FreeItem(&encodedParam, PR_FALSE);
850 }
851 return NULL;
852 }
854 CRMFEncryptedKey*
855 CRMF_CreateEncryptedKeyWithEncryptedValue (SECKEYPrivateKey *inPrivKey,
856 CERTCertificate *inCACert)
857 {
858 SECKEYPublicKey *caPubKey = NULL;
859 CRMFEncryptedKey *encKey = NULL;
860 CRMFEncryptedValue *dummy;
862 PORT_Assert(inPrivKey != NULL && inCACert != NULL);
863 if (inPrivKey == NULL || inCACert == NULL) {
864 return NULL;
865 }
867 caPubKey = CERT_ExtractPublicKey(inCACert);
868 if (caPubKey == NULL) {
869 goto loser;
870 }
872 encKey = PORT_ZNew(CRMFEncryptedKey);
873 if (encKey == NULL) {
874 goto loser;
875 }
876 dummy = crmf_create_encrypted_value_wrapped_privkey(inPrivKey,
877 caPubKey,
878 &encKey->value.encryptedValue);
879 PORT_Assert(dummy == &encKey->value.encryptedValue);
880 /* We won't add the der value here, but rather when it
881 * becomes part of a certificate request.
882 */
883 SECKEY_DestroyPublicKey(caPubKey);
884 encKey->encKeyChoice = crmfEncryptedValueChoice;
885 return encKey;
886 loser:
887 if (encKey != NULL) {
888 CRMF_DestroyEncryptedKey(encKey);
889 }
890 if (caPubKey != NULL) {
891 SECKEY_DestroyPublicKey(caPubKey);
892 }
893 return NULL;
894 }
896 SECStatus
897 CRMF_DestroyEncryptedKey(CRMFEncryptedKey *inEncrKey)
898 {
899 return crmf_destroy_encrypted_key(inEncrKey, PR_TRUE);
900 }
902 SECStatus
903 crmf_copy_pkiarchiveoptions(PLArenaPool *poolp,
904 CRMFPKIArchiveOptions *destOpt,
905 CRMFPKIArchiveOptions *srcOpt)
906 {
907 SECStatus rv;
908 destOpt->archOption = srcOpt->archOption;
909 switch (srcOpt->archOption) {
910 case crmfEncryptedPrivateKey:
911 rv = crmf_copy_encryptedkey(poolp,
912 &srcOpt->option.encryptedKey,
913 &destOpt->option.encryptedKey);
914 break;
915 case crmfKeyGenParameters:
916 case crmfArchiveRemGenPrivKey:
917 /* We've got a union, so having a pointer to one is just
918 * like having a pointer to the other one.
919 */
920 rv = SECITEM_CopyItem(poolp,
921 &destOpt->option.keyGenParameters,
922 &srcOpt->option.keyGenParameters);
923 break;
924 default:
925 rv = SECFailure;
926 }
927 return rv;
928 }
930 static SECStatus
931 crmf_check_and_adjust_archoption(CRMFControl *inControl)
932 {
933 CRMFPKIArchiveOptions *options;
935 options = &inControl->value.archiveOptions;
936 if (options->archOption == crmfNoArchiveOptions) {
937 /* It hasn't been set, so figure it out from the
938 * der.
939 */
940 switch (inControl->derValue.data[0] & 0x0f) {
941 case 0:
942 options->archOption = crmfEncryptedPrivateKey;
943 break;
944 case 1:
945 options->archOption = crmfKeyGenParameters;
946 break;
947 case 2:
948 options->archOption = crmfArchiveRemGenPrivKey;
949 break;
950 default:
951 /* We've got bad DER. Return an error. */
952 return SECFailure;
953 }
954 }
955 return SECSuccess;
956 }
958 static const SEC_ASN1Template *
959 crmf_get_pkiarchive_subtemplate(CRMFControl *inControl)
960 {
961 const SEC_ASN1Template *retTemplate;
962 SECStatus rv;
963 /*
964 * We could be in the process of decoding, in which case the
965 * archOption field will not be set. Let's check it and set
966 * it accordingly.
967 */
969 rv = crmf_check_and_adjust_archoption(inControl);
970 if (rv != SECSuccess) {
971 return NULL;
972 }
974 switch (inControl->value.archiveOptions.archOption) {
975 case crmfEncryptedPrivateKey:
976 retTemplate = CRMFEncryptedKeyWithEncryptedValueTemplate;
977 inControl->value.archiveOptions.option.encryptedKey.encKeyChoice =
978 crmfEncryptedValueChoice;
979 break;
980 default:
981 retTemplate = NULL;
982 }
983 return retTemplate;
984 }
986 const SEC_ASN1Template*
987 crmf_get_pkiarchiveoptions_subtemplate(CRMFControl *inControl)
988 {
989 const SEC_ASN1Template *retTemplate;
991 switch (inControl->tag) {
992 case SEC_OID_PKIX_REGCTRL_REGTOKEN:
993 case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
994 retTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate);
995 break;
996 case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
997 retTemplate = crmf_get_pkiarchive_subtemplate(inControl);
998 break;
999 case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
1000 case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
1001 case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
1002 /* We don't support these controls, so we fail for now.*/
1003 retTemplate = NULL;
1004 break;
1005 default:
1006 retTemplate = NULL;
1007 }
1008 return retTemplate;
1009 }
1011 static SECStatus
1012 crmf_encode_pkiarchiveoptions(PLArenaPool *poolp, CRMFControl *inControl)
1013 {
1014 const SEC_ASN1Template *asn1Template;
1016 asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
1017 /* We've got a union, so passing a pointer to one element of the
1018 * union, is the same as passing a pointer to any of the other
1019 * members of the union.
1020 */
1021 SEC_ASN1EncodeItem(poolp, &inControl->derValue,
1022 &inControl->value.archiveOptions, asn1Template);
1024 if (inControl->derValue.data == NULL) {
1025 goto loser;
1026 }
1027 return SECSuccess;
1028 loser:
1029 return SECFailure;
1030 }
1032 SECStatus
1033 CRMF_CertRequestSetPKIArchiveOptions(CRMFCertRequest *inCertReq,
1034 CRMFPKIArchiveOptions *inOptions)
1035 {
1036 CRMFControl *newControl;
1037 PLArenaPool *poolp;
1038 SECStatus rv;
1039 void *mark;
1041 PORT_Assert(inCertReq != NULL && inOptions != NULL);
1042 if (inCertReq == NULL || inOptions == NULL) {
1043 return SECFailure;
1044 }
1045 poolp = inCertReq->poolp;
1046 mark = PORT_ArenaMark(poolp);
1047 rv = crmf_add_new_control(inCertReq,
1048 SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS,
1049 &newControl);
1050 if (rv != SECSuccess) {
1051 goto loser;
1052 }
1054 rv = crmf_copy_pkiarchiveoptions(poolp,
1055 &newControl->value.archiveOptions,
1056 inOptions);
1057 if (rv != SECSuccess) {
1058 goto loser;
1059 }
1061 rv = crmf_encode_pkiarchiveoptions(poolp, newControl);
1062 if (rv != SECSuccess) {
1063 goto loser;
1064 }
1065 PORT_ArenaUnmark(poolp, mark);
1066 return SECSuccess;
1067 loser:
1068 PORT_ArenaRelease(poolp, mark);
1069 return SECFailure;
1070 }
1072 static SECStatus
1073 crmf_destroy_control(CRMFControl *inControl, PRBool freeit)
1074 {
1075 PORT_Assert(inControl != NULL);
1076 if (inControl != NULL) {
1077 SECITEM_FreeItem(&inControl->derTag, PR_FALSE);
1078 SECITEM_FreeItem(&inControl->derValue, PR_FALSE);
1079 /* None of the other tags require special processing at
1080 * the moment when freeing because they are not supported,
1081 * but if/when they are, add the necessary routines here.
1082 * If all controls are supported, then every member of the
1083 * union inControl->value will have a case that deals with
1084 * it in the following switch statement.
1085 */
1086 switch (inControl->tag) {
1087 case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
1088 crmf_destroy_pkiarchiveoptions(&inControl->value.archiveOptions,
1089 PR_FALSE);
1090 break;
1091 default:
1092 /* Put this here to get rid of all those annoying warnings.*/
1093 break;
1094 }
1095 if (freeit) {
1096 PORT_Free(inControl);
1097 }
1098 }
1099 return SECSuccess;
1100 }
1102 SECStatus
1103 CRMF_DestroyControl(CRMFControl *inControl)
1104 {
1105 return crmf_destroy_control(inControl, PR_TRUE);
1106 }
1108 static SECOidTag
1109 crmf_controltype_to_tag(CRMFControlType inControlType)
1110 {
1111 SECOidTag retVal;
1113 switch(inControlType) {
1114 case crmfRegTokenControl:
1115 retVal = SEC_OID_PKIX_REGCTRL_REGTOKEN;
1116 break;
1117 case crmfAuthenticatorControl:
1118 retVal = SEC_OID_PKIX_REGCTRL_AUTHENTICATOR;
1119 break;
1120 case crmfPKIPublicationInfoControl:
1121 retVal = SEC_OID_PKIX_REGCTRL_PKIPUBINFO;
1122 break;
1123 case crmfPKIArchiveOptionsControl:
1124 retVal = SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS;
1125 break;
1126 case crmfOldCertIDControl:
1127 retVal = SEC_OID_PKIX_REGCTRL_OLD_CERT_ID;
1128 break;
1129 case crmfProtocolEncrKeyControl:
1130 retVal = SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY;
1131 break;
1132 default:
1133 retVal = SEC_OID_UNKNOWN;
1134 break;
1135 }
1136 return retVal;
1137 }
1139 PRBool
1140 CRMF_CertRequestIsControlPresent(CRMFCertRequest *inCertReq,
1141 CRMFControlType inControlType)
1142 {
1143 SECOidTag controlTag;
1144 int i;
1146 PORT_Assert(inCertReq != NULL);
1147 if (inCertReq == NULL || inCertReq->controls == NULL) {
1148 return PR_FALSE;
1149 }
1150 controlTag = crmf_controltype_to_tag(inControlType);
1151 for (i=0; inCertReq->controls[i] != NULL; i++) {
1152 if (inCertReq->controls[i]->tag == controlTag) {
1153 return PR_TRUE;
1154 }
1155 }
1156 return PR_FALSE;
1157 }