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.7 2008/02/03 06:08:48 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
.data
= (unsigned char *)buf
;
347 cinfo_type
= SEC_PKCS7ContentType(cinfo
);
349 /* set inner content */
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
,
364 cinfo
->content
.signedData
->contentInfo
.content
.data
->data
= NULL
;
365 cinfo
->content
.signedData
->contentInfo
.content
.data
->len
= 0;
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
)
378 rv
= SECITEM_CopyItem(cinfo
->poolp
,
379 &(cinfo
->content
.encryptedData
->encContentInfo
.contentType
),
380 &(contentTypeTag
->oid
));
383 if(content
.len
> 0) {
384 rv
= SECITEM_CopyItem(cinfo
->poolp
,
385 &(cinfo
->content
.encryptedData
->encContentInfo
.plainContent
),
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;
397 case SEC_OID_PKCS7_DATA
:
398 cinfo
->content
.data
= (SECItem
*)PORT_ArenaZAlloc(cinfo
->poolp
,
400 if(cinfo
->content
.data
== NULL
)
402 if(content
.len
> 0) {
403 rv
= SECITEM_CopyItem(cinfo
->poolp
,
404 cinfo
->content
.data
, &content
);
406 /* handle case with NULL content */
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
434 * in the event of an error, SECFailure is returned. SECSuccess
435 * indicates a success.
438 SEC_PKCS7EncryptContents(PRArenaPool
*poolp
,
439 SEC_PKCS7ContentInfo
*cinfo
,
443 SECAlgorithmID
*algid
= NULL
;
444 SECItem
* result
= NULL
;
447 SECItem
* blocked_data
= NULL
;
450 PK11SymKey
* eKey
= NULL
;
451 PK11SlotInfo
* slot
= NULL
;
453 CK_MECHANISM_TYPE cryptoMechType
;
455 SECStatus rv
= SECFailure
;
456 SECItem
*c_param
= NULL
;
458 if((cinfo
== NULL
) || (key
== NULL
))
461 if(SEC_PKCS7ContentType(cinfo
) != SEC_OID_PKCS7_ENCRYPTED_DATA
)
464 algid
= SEC_PKCS7GetEncryptionAlgorithm(cinfo
);
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
) {
482 slot
= PK11_GetInternalKeySlot();
488 eKey
= PK11_PBEKeyGen(slot
, algid
, key
, PR_FALSE
, wincx
);
494 cryptoMechType
= PK11_GetPBECryptoMechanism(algid
, &c_param
, key
);
495 if (cryptoMechType
== CKM_INVALID_MECHANISM
) {
500 /* block according to PKCS 8 */
501 bs
= PK11_GetBlockSize(cryptoMechType
, c_param
);
505 pad_char
= (char)(bs
- (src
->len
% bs
));
508 blocked_data
= PK11_BlockData(src
, bs
);
510 PORT_Memset((blocked_data
->data
+ blocked_data
->len
512 pad_char
, (int)pad_char
);
518 blocked_data
= SECITEM_DupItem(src
);
520 blocked_data
->data
= (unsigned char*)PORT_Realloc(
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
);
536 blocked_data
= SECITEM_DupItem(src
);
543 cx
= PK11_CreateContextBySymKey(cryptoMechType
, CKA_ENCRYPT
,
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
);
556 /* let success fall through */
557 if(blocked_data
!= NULL
)
558 SECITEM_ZfreeItem(blocked_data
, PR_TRUE
);
561 SECITEM_ZfreeItem(result
, PR_TRUE
);
564 PORT_ArenaRelease(poolp
, mark
);
566 PORT_ArenaUnmark(poolp
, mark
);
569 PK11_FreeSymKey(eKey
);
575 SECITEM_ZfreeItem(c_param
, PR_TRUE
);
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
591 * in the event of an error, SECFailure is returned. SECSuccess
592 * indicates a success.
595 SEC_PKCS7DecryptContents(PRArenaPool
*poolp
,
596 SEC_PKCS7ContentInfo
*cinfo
,
600 SECAlgorithmID
*algid
= NULL
;
601 SECStatus rv
= SECFailure
;
602 SECItem
*result
= NULL
, *dest
, *src
;
605 PK11SymKey
*eKey
= NULL
;
606 PK11SlotInfo
*slot
= NULL
;
607 CK_MECHANISM_TYPE cryptoMechType
;
609 SECItem
*c_param
= NULL
;
612 if((cinfo
== NULL
) || (key
== NULL
))
615 if(SEC_PKCS7ContentType(cinfo
) != SEC_OID_PKCS7_ENCRYPTED_DATA
)
618 algid
= SEC_PKCS7GetEncryptionAlgorithm(cinfo
);
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
) {
636 slot
= PK11_GetInternalKeySlot();
642 eKey
= PK11_PBEKeyGen(slot
, algid
, key
, PR_FALSE
, wincx
);
648 cryptoMechType
= PK11_GetPBECryptoMechanism(algid
, &c_param
, key
);
649 if (cryptoMechType
== CKM_INVALID_MECHANISM
) {
654 cx
= PK11_CreateContextBySymKey(cryptoMechType
, CKA_DECRYPT
,
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
);
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];
680 /* let success fall through */
682 SECITEM_ZfreeItem(result
, PR_TRUE
);
685 PORT_ArenaRelease(poolp
, mark
);
687 PORT_ArenaUnmark(poolp
, mark
);
690 PK11_FreeSymKey(eKey
);
696 SECITEM_ZfreeItem(c_param
, PR_TRUE
);
702 SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo
*cinfo
)
704 switch(SEC_PKCS7ContentType(cinfo
))
706 case SEC_OID_PKCS7_SIGNED_DATA
:
707 return cinfo
->content
.signedData
->rawCerts
;
717 SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo
*cinfo
)
719 if (cinfo
->contentTypeTag
->offset
== SEC_OID_PKCS7_ENVELOPED_DATA
)
720 return cinfo
->content
.envelopedData
->encContentInfo
.keysize
;