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
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.
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.8 2010/04/04 20:50:52 nelson%bolyard.com Exp $
52 * Find out (saving pointer to lookup result for future reference)
53 * and return the inner content type.
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.
72 SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *cinfo)
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)
85 if (cinfo->refCount > 0)
90 recipientinfos = NULL;
93 kind = SEC_PKCS7ContentType (cinfo);
95 case SEC_OID_PKCS7_ENVELOPED_DATA:
97 SEC_PKCS7EnvelopedData *edp;
99 edp = cinfo->content.envelopedData;
101 recipientinfos = edp->recipientInfos;
105 case SEC_OID_PKCS7_SIGNED_DATA:
107 SEC_PKCS7SignedData *sdp;
109 sdp = cinfo->content.signedData;
112 certlists = sdp->certLists;
113 signerinfos = sdp->signerInfos;
117 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
119 SEC_PKCS7SignedAndEnvelopedData *saedp;
121 saedp = cinfo->content.signedAndEnvelopedData;
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);
133 /* XXX Anything else that needs to be "manually" freed/destroyed? */
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)
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...
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.
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.
218 SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo)
222 kind = SEC_PKCS7ContentType (cinfo);
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;
233 return SEC_PKCS7GetContent (&(digd->contentInfo));
235 case SEC_OID_PKCS7_ENCRYPTED_DATA:
237 SEC_PKCS7EncryptedData *encd;
239 encd = cinfo->content.encryptedData;
242 return &(encd->encContentInfo.plainContent);
244 case SEC_OID_PKCS7_ENVELOPED_DATA:
246 SEC_PKCS7EnvelopedData *envd;
248 envd = cinfo->content.envelopedData;
251 return &(envd->encContentInfo.plainContent);
253 case SEC_OID_PKCS7_SIGNED_DATA:
255 SEC_PKCS7SignedData *sigd;
257 sigd = cinfo->content.signedData;
260 return SEC_PKCS7GetContent (&(sigd->contentInfo));
262 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
264 SEC_PKCS7SignedAndEnvelopedData *saed;
266 saed = cinfo->content.signedAndEnvelopedData;
269 return &(saed->encContentInfo.plainContent);
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.
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;
306 case SEC_OID_PKCS7_ENVELOPED_DATA:
307 alg = &cinfo->content.envelopedData->encContentInfo.contentEncAlg;
309 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
310 alg = &cinfo->content.signedAndEnvelopedData
311 ->encContentInfo.contentEncAlg;
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.
335 SEC_PKCS7SetContent(SEC_PKCS7ContentInfo *cinfo,
339 SECOidTag cinfo_type;
342 SECOidData *contentTypeTag = NULL;
344 content.type = siBuffer;
345 content.data = (unsigned char *)buf;
348 cinfo_type = SEC_PKCS7ContentType(cinfo);
350 /* set inner content */
353 case SEC_OID_PKCS7_SIGNED_DATA:
354 if(content.len > 0) {
355 /* we "leak" the old content here, but as it's all in the pool */
356 /* it does not really matter */
358 /* create content item if necessary */
359 if (cinfo->content.signedData->contentInfo.content.data == NULL)
360 cinfo->content.signedData->contentInfo.content.data = SECITEM_AllocItem(cinfo->poolp, NULL, 0);
361 rv = SECITEM_CopyItem(cinfo->poolp,
362 cinfo->content.signedData->contentInfo.content.data,
365 cinfo->content.signedData->contentInfo.content.data->data = NULL;
366 cinfo->content.signedData->contentInfo.content.data->len = 0;
373 case SEC_OID_PKCS7_ENCRYPTED_DATA:
374 /* XXX this forces the inner content type to be "data" */
375 /* do we really want to override without asking or reason? */
376 contentTypeTag = SECOID_FindOIDByTag(SEC_OID_PKCS7_DATA);
377 if(contentTypeTag == NULL)
379 rv = SECITEM_CopyItem(cinfo->poolp,
380 &(cinfo->content.encryptedData->encContentInfo.contentType),
381 &(contentTypeTag->oid));
384 if(content.len > 0) {
385 rv = SECITEM_CopyItem(cinfo->poolp,
386 &(cinfo->content.encryptedData->encContentInfo.plainContent),
389 cinfo->content.encryptedData->encContentInfo.plainContent.data = NULL;
390 cinfo->content.encryptedData->encContentInfo.encContent.data = NULL;
391 cinfo->content.encryptedData->encContentInfo.plainContent.len = 0;
392 cinfo->content.encryptedData->encContentInfo.encContent.len = 0;
398 case SEC_OID_PKCS7_DATA:
399 cinfo->content.data = (SECItem *)PORT_ArenaZAlloc(cinfo->poolp,
401 if(cinfo->content.data == NULL)
403 if(content.len > 0) {
404 rv = SECITEM_CopyItem(cinfo->poolp,
405 cinfo->content.data, &content);
407 /* handle case with NULL content */
424 /* the content of an encrypted data content info is encrypted.
425 * it is assumed that for encrypted data, that the data has already
426 * been set and is in the "plainContent" field of the content info.
428 * cinfo is the content info to encrypt
430 * key is the key with which to perform the encryption. if the
431 * algorithm is a password based encryption algorithm, the
432 * key is actually a password which will be processed per
435 * in the event of an error, SECFailure is returned. SECSuccess
436 * indicates a success.
439 SEC_PKCS7EncryptContents(PRArenaPool *poolp,
440 SEC_PKCS7ContentInfo *cinfo,
444 SECAlgorithmID *algid = NULL;
445 SECItem * result = NULL;
448 SECItem * blocked_data = NULL;
451 PK11SymKey * eKey = NULL;
452 PK11SlotInfo * slot = NULL;
454 CK_MECHANISM_TYPE cryptoMechType;
456 SECStatus rv = SECFailure;
457 SECItem *c_param = NULL;
459 if((cinfo == NULL) || (key == NULL))
462 if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
465 algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
470 poolp = cinfo->poolp;
472 mark = PORT_ArenaMark(poolp);
474 src = &cinfo->content.encryptedData->encContentInfo.plainContent;
475 dest = &cinfo->content.encryptedData->encContentInfo.encContent;
476 dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
477 dest->len = (src->len + 64);
478 if(dest->data == NULL) {
483 slot = PK11_GetInternalKeySlot();
489 eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
495 cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
496 if (cryptoMechType == CKM_INVALID_MECHANISM) {
501 /* block according to PKCS 8 */
502 bs = PK11_GetBlockSize(cryptoMechType, c_param);
506 pad_char = (char)(bs - (src->len % bs));
509 blocked_data = PK11_BlockData(src, bs);
511 PORT_Memset((blocked_data->data + blocked_data->len
513 pad_char, (int)pad_char);
519 blocked_data = SECITEM_DupItem(src);
521 blocked_data->data = (unsigned char*)PORT_Realloc(
523 blocked_data->len + bs);
524 if(blocked_data->data) {
525 blocked_data->len += bs;
526 PORT_Memset((blocked_data->data + src->len), (char)bs, bs);
537 blocked_data = SECITEM_DupItem(src);
544 cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
551 rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len),
552 (int)(src->len + 64), blocked_data->data,
553 (int)blocked_data->len);
554 PK11_DestroyContext((PK11Context*)cx, PR_TRUE);
557 /* let success fall through */
558 if(blocked_data != NULL)
559 SECITEM_ZfreeItem(blocked_data, PR_TRUE);
562 SECITEM_ZfreeItem(result, PR_TRUE);
565 PORT_ArenaRelease(poolp, mark);
567 PORT_ArenaUnmark(poolp, mark);
570 PK11_FreeSymKey(eKey);
576 SECITEM_ZfreeItem(c_param, PR_TRUE);
581 /* the content of an encrypted data content info is decrypted.
582 * it is assumed that for encrypted data, that the data has already
583 * been set and is in the "encContent" field of the content info.
585 * cinfo is the content info to decrypt
587 * key is the key with which to perform the decryption. if the
588 * algorithm is a password based encryption algorithm, the
589 * key is actually a password which will be processed per
592 * in the event of an error, SECFailure is returned. SECSuccess
593 * indicates a success.
596 SEC_PKCS7DecryptContents(PRArenaPool *poolp,
597 SEC_PKCS7ContentInfo *cinfo,
601 SECAlgorithmID *algid = NULL;
602 SECStatus rv = SECFailure;
603 SECItem *result = NULL, *dest, *src;
606 PK11SymKey *eKey = NULL;
607 PK11SlotInfo *slot = NULL;
608 CK_MECHANISM_TYPE cryptoMechType;
610 SECItem *c_param = NULL;
613 if((cinfo == NULL) || (key == NULL))
616 if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
619 algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
624 poolp = cinfo->poolp;
626 mark = PORT_ArenaMark(poolp);
628 src = &cinfo->content.encryptedData->encContentInfo.encContent;
629 dest = &cinfo->content.encryptedData->encContentInfo.plainContent;
630 dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
631 dest->len = (src->len + 64);
632 if(dest->data == NULL) {
637 slot = PK11_GetInternalKeySlot();
643 eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
649 cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
650 if (cryptoMechType == CKM_INVALID_MECHANISM) {
655 cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
662 rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len),
663 (int)(src->len + 64), src->data, (int)src->len);
664 PK11_DestroyContext((PK11Context *)cx, PR_TRUE);
666 bs = PK11_GetBlockSize(cryptoMechType, c_param);
668 /* check for proper badding in block algorithms. this assumes
669 * RC2 cbc or a DES cbc variant. and the padding is thus defined
671 if(((int)dest->data[dest->len-1] <= bs) &&
672 ((int)dest->data[dest->len-1] > 0)) {
673 dest->len -= (int)dest->data[dest->len-1];
681 /* let success fall through */
683 SECITEM_ZfreeItem(result, PR_TRUE);
686 PORT_ArenaRelease(poolp, mark);
688 PORT_ArenaUnmark(poolp, mark);
691 PK11_FreeSymKey(eKey);
697 SECITEM_ZfreeItem(c_param, PR_TRUE);
703 SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo)
705 switch(SEC_PKCS7ContentType(cinfo))
707 case SEC_OID_PKCS7_SIGNED_DATA:
708 return cinfo->content.signedData->rawCerts;
718 SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo)
720 if (cinfo->contentTypeTag->offset == SEC_OID_PKCS7_ENVELOPED_DATA)
721 return cinfo->content.envelopedData->encContentInfo.keysize;