Bug 449533. Set the mFixedPitch flag within SetFixedPitch. r+sr=vlad
[wine-gecko.git] / security / nss / lib / pkcs7 / p7common.c
blob63c9a2cc1b4484075e7ff00c07f49d771de0514b
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 * PKCS7 implementation -- the exported parts that are used whether
39 * creating or decoding.
41 * $Id: p7common.c,v 1.7 2008/02/03 06:08:48 nelson%bolyard.com Exp $
44 #include "p7local.h"
46 #include "cert.h"
47 #include "secitem.h"
48 #include "secoid.h"
49 #include "pk11func.h"
52 * Find out (saving pointer to lookup result for future reference)
53 * and return the inner content type.
55 SECOidTag
56 SEC_PKCS7ContentType (SEC_PKCS7ContentInfo *cinfo)
58 if (cinfo->contentTypeTag == NULL)
59 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
61 if (cinfo->contentTypeTag == NULL)
62 return SEC_OID_UNKNOWN;
64 return cinfo->contentTypeTag->offset;
69 * Destroy a PKCS7 contentInfo and all of its sub-pieces.
71 void
72 SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *cinfo)
74 SECOidTag kind;
75 CERTCertificate **certs;
76 CERTCertificateList **certlists;
77 SEC_PKCS7SignerInfo **signerinfos;
78 SEC_PKCS7RecipientInfo **recipientinfos;
80 PORT_Assert (cinfo->refCount > 0);
81 if (cinfo->refCount <= 0)
82 return;
84 cinfo->refCount--;
85 if (cinfo->refCount > 0)
86 return;
88 certs = NULL;
89 certlists = NULL;
90 recipientinfos = NULL;
91 signerinfos = NULL;
93 kind = SEC_PKCS7ContentType (cinfo);
94 switch (kind) {
95 case SEC_OID_PKCS7_ENVELOPED_DATA:
97 SEC_PKCS7EnvelopedData *edp;
99 edp = cinfo->content.envelopedData;
100 if (edp != NULL) {
101 recipientinfos = edp->recipientInfos;
104 break;
105 case SEC_OID_PKCS7_SIGNED_DATA:
107 SEC_PKCS7SignedData *sdp;
109 sdp = cinfo->content.signedData;
110 if (sdp != NULL) {
111 certs = sdp->certs;
112 certlists = sdp->certLists;
113 signerinfos = sdp->signerInfos;
116 break;
117 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
119 SEC_PKCS7SignedAndEnvelopedData *saedp;
121 saedp = cinfo->content.signedAndEnvelopedData;
122 if (saedp != NULL) {
123 certs = saedp->certs;
124 certlists = saedp->certLists;
125 recipientinfos = saedp->recipientInfos;
126 signerinfos = saedp->signerInfos;
127 if (saedp->sigKey != NULL)
128 PK11_FreeSymKey (saedp->sigKey);
131 break;
132 default:
133 /* XXX Anything else that needs to be "manually" freed/destroyed? */
134 break;
137 if (certs != NULL) {
138 CERTCertificate *cert;
140 while ((cert = *certs++) != NULL) {
141 CERT_DestroyCertificate (cert);
145 if (certlists != NULL) {
146 CERTCertificateList *certlist;
148 while ((certlist = *certlists++) != NULL) {
149 CERT_DestroyCertificateList (certlist);
153 if (recipientinfos != NULL) {
154 SEC_PKCS7RecipientInfo *ri;
156 while ((ri = *recipientinfos++) != NULL) {
157 if (ri->cert != NULL)
158 CERT_DestroyCertificate (ri->cert);
162 if (signerinfos != NULL) {
163 SEC_PKCS7SignerInfo *si;
165 while ((si = *signerinfos++) != NULL) {
166 if (si->cert != NULL)
167 CERT_DestroyCertificate (si->cert);
168 if (si->certList != NULL)
169 CERT_DestroyCertificateList (si->certList);
173 if (cinfo->poolp != NULL) {
174 PORT_FreeArena (cinfo->poolp, PR_FALSE); /* XXX clear it? */
180 * Return a copy of the given contentInfo. The copy may be virtual
181 * or may be real -- either way, the result needs to be passed to
182 * SEC_PKCS7DestroyContentInfo later (as does the original).
184 SEC_PKCS7ContentInfo *
185 SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *cinfo)
187 if (cinfo == NULL)
188 return NULL;
190 PORT_Assert (cinfo->refCount > 0);
192 if (cinfo->created) {
194 * Want to do a real copy of these; otherwise subsequent
195 * changes made to either copy are likely to be a surprise.
196 * XXX I suspect that this will not actually be called for yet,
197 * which is why the assert, so to notice if it is...
199 PORT_Assert (0);
201 * XXX Create a new pool here, and copy everything from
202 * within. For cert stuff, need to call the appropriate
203 * copy functions, etc.
207 cinfo->refCount++;
208 return cinfo;
213 * Return a pointer to the actual content. In the case of those types
214 * which are encrypted, this returns the *plain* content.
215 * XXX Needs revisiting if/when we handle nested encrypted types.
217 SECItem *
218 SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo)
220 SECOidTag kind;
222 kind = SEC_PKCS7ContentType (cinfo);
223 switch (kind) {
224 case SEC_OID_PKCS7_DATA:
225 return cinfo->content.data;
226 case SEC_OID_PKCS7_DIGESTED_DATA:
228 SEC_PKCS7DigestedData *digd;
230 digd = cinfo->content.digestedData;
231 if (digd == NULL)
232 break;
233 return SEC_PKCS7GetContent (&(digd->contentInfo));
235 case SEC_OID_PKCS7_ENCRYPTED_DATA:
237 SEC_PKCS7EncryptedData *encd;
239 encd = cinfo->content.encryptedData;
240 if (encd == NULL)
241 break;
242 return &(encd->encContentInfo.plainContent);
244 case SEC_OID_PKCS7_ENVELOPED_DATA:
246 SEC_PKCS7EnvelopedData *envd;
248 envd = cinfo->content.envelopedData;
249 if (envd == NULL)
250 break;
251 return &(envd->encContentInfo.plainContent);
253 case SEC_OID_PKCS7_SIGNED_DATA:
255 SEC_PKCS7SignedData *sigd;
257 sigd = cinfo->content.signedData;
258 if (sigd == NULL)
259 break;
260 return SEC_PKCS7GetContent (&(sigd->contentInfo));
262 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
264 SEC_PKCS7SignedAndEnvelopedData *saed;
266 saed = cinfo->content.signedAndEnvelopedData;
267 if (saed == NULL)
268 break;
269 return &(saed->encContentInfo.plainContent);
271 default:
272 PORT_Assert(0);
273 break;
276 return NULL;
281 * XXX Fix the placement and formatting of the
282 * following routines (i.e. make them consistent with the rest of
283 * the pkcs7 code -- I think some/many belong in other files and
284 * they all need a formatting/style rehaul)
287 /* retrieve the algorithm identifier for encrypted data.
288 * the identifier returned is a copy of the algorithm identifier
289 * in the content info and needs to be freed after being used.
291 * cinfo is the content info for which to retrieve the
292 * encryption algorithm.
294 * if the content info is not encrypted data or an error
295 * occurs NULL is returned.
297 SECAlgorithmID *
298 SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo)
300 SECAlgorithmID *alg = 0;
301 switch (SEC_PKCS7ContentType(cinfo))
303 case SEC_OID_PKCS7_ENCRYPTED_DATA:
304 alg = &cinfo->content.encryptedData->encContentInfo.contentEncAlg;
305 break;
306 case SEC_OID_PKCS7_ENVELOPED_DATA:
307 alg = &cinfo->content.envelopedData->encContentInfo.contentEncAlg;
308 break;
309 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
310 alg = &cinfo->content.signedAndEnvelopedData
311 ->encContentInfo.contentEncAlg;
312 break;
313 default:
314 alg = 0;
315 break;
318 return alg;
321 /* set the content of the content info. For data content infos,
322 * the data is set. For encrytped content infos, the plainContent
323 * is set, and is expected to be encrypted later.
325 * cinfo is the content info where the data will be set
327 * buf is a buffer of the data to set
329 * len is the length of the data being set.
331 * in the event of an error, SECFailure is returned. SECSuccess
332 * indicates the content was successfully set.
334 SECStatus
335 SEC_PKCS7SetContent(SEC_PKCS7ContentInfo *cinfo,
336 const char *buf,
337 unsigned long len)
339 SECOidTag cinfo_type;
340 SECStatus rv;
341 SECItem content;
342 SECOidData *contentTypeTag = NULL;
344 content.data = (unsigned char *)buf;
345 content.len = len;
347 cinfo_type = SEC_PKCS7ContentType(cinfo);
349 /* set inner content */
350 switch(cinfo_type)
352 case SEC_OID_PKCS7_SIGNED_DATA:
353 if(content.len > 0) {
354 /* we "leak" the old content here, but as it's all in the pool */
355 /* it does not really matter */
357 /* create content item if necessary */
358 if (cinfo->content.signedData->contentInfo.content.data == NULL)
359 cinfo->content.signedData->contentInfo.content.data = SECITEM_AllocItem(cinfo->poolp, NULL, 0);
360 rv = SECITEM_CopyItem(cinfo->poolp,
361 cinfo->content.signedData->contentInfo.content.data,
362 &content);
363 } else {
364 cinfo->content.signedData->contentInfo.content.data->data = NULL;
365 cinfo->content.signedData->contentInfo.content.data->len = 0;
366 rv = SECSuccess;
368 if(rv == SECFailure)
369 goto loser;
371 break;
372 case SEC_OID_PKCS7_ENCRYPTED_DATA:
373 /* XXX this forces the inner content type to be "data" */
374 /* do we really want to override without asking or reason? */
375 contentTypeTag = SECOID_FindOIDByTag(SEC_OID_PKCS7_DATA);
376 if(contentTypeTag == NULL)
377 goto loser;
378 rv = SECITEM_CopyItem(cinfo->poolp,
379 &(cinfo->content.encryptedData->encContentInfo.contentType),
380 &(contentTypeTag->oid));
381 if(rv == SECFailure)
382 goto loser;
383 if(content.len > 0) {
384 rv = SECITEM_CopyItem(cinfo->poolp,
385 &(cinfo->content.encryptedData->encContentInfo.plainContent),
386 &content);
387 } else {
388 cinfo->content.encryptedData->encContentInfo.plainContent.data = NULL;
389 cinfo->content.encryptedData->encContentInfo.encContent.data = NULL;
390 cinfo->content.encryptedData->encContentInfo.plainContent.len = 0;
391 cinfo->content.encryptedData->encContentInfo.encContent.len = 0;
392 rv = SECSuccess;
394 if(rv == SECFailure)
395 goto loser;
396 break;
397 case SEC_OID_PKCS7_DATA:
398 cinfo->content.data = (SECItem *)PORT_ArenaZAlloc(cinfo->poolp,
399 sizeof(SECItem));
400 if(cinfo->content.data == NULL)
401 goto loser;
402 if(content.len > 0) {
403 rv = SECITEM_CopyItem(cinfo->poolp,
404 cinfo->content.data, &content);
405 } else {
406 /* handle case with NULL content */
407 rv = SECSuccess;
409 if(rv == SECFailure)
410 goto loser;
411 break;
412 default:
413 goto loser;
416 return SECSuccess;
418 loser:
420 return SECFailure;
423 /* the content of an encrypted data content info is encrypted.
424 * it is assumed that for encrypted data, that the data has already
425 * been set and is in the "plainContent" field of the content info.
427 * cinfo is the content info to encrypt
429 * key is the key with which to perform the encryption. if the
430 * algorithm is a password based encryption algorithm, the
431 * key is actually a password which will be processed per
432 * PKCS #5.
434 * in the event of an error, SECFailure is returned. SECSuccess
435 * indicates a success.
437 SECStatus
438 SEC_PKCS7EncryptContents(PRArenaPool *poolp,
439 SEC_PKCS7ContentInfo *cinfo,
440 SECItem *key,
441 void *wincx)
443 SECAlgorithmID *algid = NULL;
444 SECItem * result = NULL;
445 SECItem * src;
446 SECItem * dest;
447 SECItem * blocked_data = NULL;
448 void * mark;
449 void * cx;
450 PK11SymKey * eKey = NULL;
451 PK11SlotInfo * slot = NULL;
453 CK_MECHANISM_TYPE cryptoMechType;
454 int bs;
455 SECStatus rv = SECFailure;
456 SECItem *c_param = NULL;
458 if((cinfo == NULL) || (key == NULL))
459 return SECFailure;
461 if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
462 return SECFailure;
464 algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
465 if(algid == NULL)
466 return SECFailure;
468 if(poolp == NULL)
469 poolp = cinfo->poolp;
471 mark = PORT_ArenaMark(poolp);
473 src = &cinfo->content.encryptedData->encContentInfo.plainContent;
474 dest = &cinfo->content.encryptedData->encContentInfo.encContent;
475 dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
476 dest->len = (src->len + 64);
477 if(dest->data == NULL) {
478 rv = SECFailure;
479 goto loser;
482 slot = PK11_GetInternalKeySlot();
483 if(slot == NULL) {
484 rv = SECFailure;
485 goto loser;
488 eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
489 if(eKey == NULL) {
490 rv = SECFailure;
491 goto loser;
494 cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
495 if (cryptoMechType == CKM_INVALID_MECHANISM) {
496 rv = SECFailure;
497 goto loser;
500 /* block according to PKCS 8 */
501 bs = PK11_GetBlockSize(cryptoMechType, c_param);
502 rv = SECSuccess;
503 if(bs) {
504 char pad_char;
505 pad_char = (char)(bs - (src->len % bs));
506 if(src->len % bs) {
507 rv = SECSuccess;
508 blocked_data = PK11_BlockData(src, bs);
509 if(blocked_data) {
510 PORT_Memset((blocked_data->data + blocked_data->len
511 - (int)pad_char),
512 pad_char, (int)pad_char);
513 } else {
514 rv = SECFailure;
515 goto loser;
517 } else {
518 blocked_data = SECITEM_DupItem(src);
519 if(blocked_data) {
520 blocked_data->data = (unsigned char*)PORT_Realloc(
521 blocked_data->data,
522 blocked_data->len + bs);
523 if(blocked_data->data) {
524 blocked_data->len += bs;
525 PORT_Memset((blocked_data->data + src->len), (char)bs, bs);
526 } else {
527 rv = SECFailure;
528 goto loser;
530 } else {
531 rv = SECFailure;
532 goto loser;
535 } else {
536 blocked_data = SECITEM_DupItem(src);
537 if(!blocked_data) {
538 rv = SECFailure;
539 goto loser;
543 cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
544 eKey, c_param);
545 if(cx == NULL) {
546 rv = SECFailure;
547 goto loser;
550 rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len),
551 (int)(src->len + 64), blocked_data->data,
552 (int)blocked_data->len);
553 PK11_DestroyContext((PK11Context*)cx, PR_TRUE);
555 loser:
556 /* let success fall through */
557 if(blocked_data != NULL)
558 SECITEM_ZfreeItem(blocked_data, PR_TRUE);
560 if(result != NULL)
561 SECITEM_ZfreeItem(result, PR_TRUE);
563 if(rv == SECFailure)
564 PORT_ArenaRelease(poolp, mark);
565 else
566 PORT_ArenaUnmark(poolp, mark);
568 if(eKey != NULL)
569 PK11_FreeSymKey(eKey);
571 if(slot != NULL)
572 PK11_FreeSlot(slot);
574 if(c_param != NULL)
575 SECITEM_ZfreeItem(c_param, PR_TRUE);
577 return rv;
580 /* the content of an encrypted data content info is decrypted.
581 * it is assumed that for encrypted data, that the data has already
582 * been set and is in the "encContent" field of the content info.
584 * cinfo is the content info to decrypt
586 * key is the key with which to perform the decryption. if the
587 * algorithm is a password based encryption algorithm, the
588 * key is actually a password which will be processed per
589 * PKCS #5.
591 * in the event of an error, SECFailure is returned. SECSuccess
592 * indicates a success.
594 SECStatus
595 SEC_PKCS7DecryptContents(PRArenaPool *poolp,
596 SEC_PKCS7ContentInfo *cinfo,
597 SECItem *key,
598 void *wincx)
600 SECAlgorithmID *algid = NULL;
601 SECStatus rv = SECFailure;
602 SECItem *result = NULL, *dest, *src;
603 void *mark;
605 PK11SymKey *eKey = NULL;
606 PK11SlotInfo *slot = NULL;
607 CK_MECHANISM_TYPE cryptoMechType;
608 void *cx;
609 SECItem *c_param = NULL;
610 int bs;
612 if((cinfo == NULL) || (key == NULL))
613 return SECFailure;
615 if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
616 return SECFailure;
618 algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
619 if(algid == NULL)
620 return SECFailure;
622 if(poolp == NULL)
623 poolp = cinfo->poolp;
625 mark = PORT_ArenaMark(poolp);
627 src = &cinfo->content.encryptedData->encContentInfo.encContent;
628 dest = &cinfo->content.encryptedData->encContentInfo.plainContent;
629 dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
630 dest->len = (src->len + 64);
631 if(dest->data == NULL) {
632 rv = SECFailure;
633 goto loser;
636 slot = PK11_GetInternalKeySlot();
637 if(slot == NULL) {
638 rv = SECFailure;
639 goto loser;
642 eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
643 if(eKey == NULL) {
644 rv = SECFailure;
645 goto loser;
648 cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
649 if (cryptoMechType == CKM_INVALID_MECHANISM) {
650 rv = SECFailure;
651 goto loser;
654 cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
655 eKey, c_param);
656 if(cx == NULL) {
657 rv = SECFailure;
658 goto loser;
661 rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len),
662 (int)(src->len + 64), src->data, (int)src->len);
663 PK11_DestroyContext((PK11Context *)cx, PR_TRUE);
665 bs = PK11_GetBlockSize(cryptoMechType, c_param);
666 if(bs) {
667 /* check for proper badding in block algorithms. this assumes
668 * RC2 cbc or a DES cbc variant. and the padding is thus defined
670 if(((int)dest->data[dest->len-1] <= bs) &&
671 ((int)dest->data[dest->len-1] > 0)) {
672 dest->len -= (int)dest->data[dest->len-1];
673 } else {
674 rv = SECFailure;
675 /* set an error ? */
679 loser:
680 /* let success fall through */
681 if(result != NULL)
682 SECITEM_ZfreeItem(result, PR_TRUE);
684 if(rv == SECFailure)
685 PORT_ArenaRelease(poolp, mark);
686 else
687 PORT_ArenaUnmark(poolp, mark);
689 if(eKey != NULL)
690 PK11_FreeSymKey(eKey);
692 if(slot != NULL)
693 PK11_FreeSlot(slot);
695 if(c_param != NULL)
696 SECITEM_ZfreeItem(c_param, PR_TRUE);
698 return rv;
701 SECItem **
702 SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo)
704 switch(SEC_PKCS7ContentType(cinfo))
706 case SEC_OID_PKCS7_SIGNED_DATA:
707 return cinfo->content.signedData->rawCerts;
708 break;
709 default:
710 return NULL;
711 break;
717 SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo)
719 if (cinfo->contentTypeTag->offset == SEC_OID_PKCS7_ENVELOPED_DATA)
720 return cinfo->content.envelopedData->encContentInfo.keysize;
721 else
722 return 0;