summaryrefslogtreecommitdiff
path: root/security/nss/lib/pkcs7
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/pkcs7')
-rw-r--r--security/nss/lib/pkcs7/Makefile76
-rw-r--r--security/nss/lib/pkcs7/config.mk44
-rw-r--r--security/nss/lib/pkcs7/manifest.mn59
-rw-r--r--security/nss/lib/pkcs7/p7common.c738
-rw-r--r--security/nss/lib/pkcs7/p7create.c1320
-rw-r--r--security/nss/lib/pkcs7/p7decode.c2087
-rw-r--r--security/nss/lib/pkcs7/p7encode.c1329
-rw-r--r--security/nss/lib/pkcs7/p7local.c1431
-rw-r--r--security/nss/lib/pkcs7/p7local.h176
-rw-r--r--security/nss/lib/pkcs7/pkcs7t.h292
-rw-r--r--security/nss/lib/pkcs7/secmime.c901
-rw-r--r--security/nss/lib/pkcs7/secmime.h192
-rw-r--r--security/nss/lib/pkcs7/secpkcs7.h618
13 files changed, 0 insertions, 9263 deletions
diff --git a/security/nss/lib/pkcs7/Makefile b/security/nss/lib/pkcs7/Makefile
deleted file mode 100644
index cb85677bc..000000000
--- a/security/nss/lib/pkcs7/Makefile
+++ /dev/null
@@ -1,76 +0,0 @@
-#! gmake
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the "License"); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS
-# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Netscape security libraries.
-#
-# The Initial Developer of the Original Code is Netscape
-# Communications Corporation. Portions created by Netscape are
-# Copyright (C) 1994-2000 Netscape Communications Corporation. All
-# Rights Reserved.
-#
-# Contributor(s):
-#
-# Alternatively, the contents of this file may be used under the
-# terms of the GNU General Public License Version 2 or later (the
-# "GPL"), in which case the provisions of the GPL are applicable
-# instead of those above. If you wish to allow use of your
-# version of this file only under the terms of the GPL and not to
-# allow others to use your version of this file under the MPL,
-# indicate your decision by deleting the provisions above and
-# replace them with the notice and other provisions required by
-# the GPL. If you do not delete the provisions above, a recipient
-# may use your version of this file under either the MPL or the
-# GPL.
-#
-
-#######################################################################
-# (1) Include initial platform-independent assignments (MANDATORY). #
-#######################################################################
-
-include manifest.mn
-
-#######################################################################
-# (2) Include "global" configuration information. (OPTIONAL) #
-#######################################################################
-
-include $(CORE_DEPTH)/coreconf/config.mk
-
-#######################################################################
-# (3) Include "component" configuration information. (OPTIONAL) #
-#######################################################################
-
-
-
-#######################################################################
-# (4) Include "local" platform-dependent assignments (OPTIONAL). #
-#######################################################################
-
-include config.mk
-
-#######################################################################
-# (5) Execute "global" rules. (OPTIONAL) #
-#######################################################################
-
-include $(CORE_DEPTH)/coreconf/rules.mk
-
-#######################################################################
-# (6) Execute "component" rules. (OPTIONAL) #
-#######################################################################
-
-
-
-#######################################################################
-# (7) Execute "local" rules. (OPTIONAL). #
-#######################################################################
-
-
-
diff --git a/security/nss/lib/pkcs7/config.mk b/security/nss/lib/pkcs7/config.mk
deleted file mode 100644
index a73a1086e..000000000
--- a/security/nss/lib/pkcs7/config.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the "License"); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS
-# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Netscape security libraries.
-#
-# The Initial Developer of the Original Code is Netscape
-# Communications Corporation. Portions created by Netscape are
-# Copyright (C) 1994-2000 Netscape Communications Corporation. All
-# Rights Reserved.
-#
-# Contributor(s):
-#
-# Alternatively, the contents of this file may be used under the
-# terms of the GNU General Public License Version 2 or later (the
-# "GPL"), in which case the provisions of the GPL are applicable
-# instead of those above. If you wish to allow use of your
-# version of this file only under the terms of the GPL and not to
-# allow others to use your version of this file under the MPL,
-# indicate your decision by deleting the provisions above and
-# replace them with the notice and other provisions required by
-# the GPL. If you do not delete the provisions above, a recipient
-# may use your version of this file under either the MPL or the
-# GPL.
-#
-
-#
-# Override TARGETS variable so that only static libraries
-# are specifed as dependencies within rules.mk.
-#
-
-TARGETS = $(LIBRARY)
-SHARED_LIBRARY =
-IMPORT_LIBRARY =
-PURE_LIBRARY =
-PROGRAM =
-
diff --git a/security/nss/lib/pkcs7/manifest.mn b/security/nss/lib/pkcs7/manifest.mn
deleted file mode 100644
index b2b0e45d9..000000000
--- a/security/nss/lib/pkcs7/manifest.mn
+++ /dev/null
@@ -1,59 +0,0 @@
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the "License"); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS
-# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Netscape security libraries.
-#
-# The Initial Developer of the Original Code is Netscape
-# Communications Corporation. Portions created by Netscape are
-# Copyright (C) 1994-2000 Netscape Communications Corporation. All
-# Rights Reserved.
-#
-# Contributor(s):
-#
-# Alternatively, the contents of this file may be used under the
-# terms of the GNU General Public License Version 2 or later (the
-# "GPL"), in which case the provisions of the GPL are applicable
-# instead of those above. If you wish to allow use of your
-# version of this file only under the terms of the GPL and not to
-# allow others to use your version of this file under the MPL,
-# indicate your decision by deleting the provisions above and
-# replace them with the notice and other provisions required by
-# the GPL. If you do not delete the provisions above, a recipient
-# may use your version of this file under either the MPL or the
-# GPL.
-#
-
-CORE_DEPTH = ../../..
-
-EXPORTS = \
- secmime.h \
- secpkcs7.h \
- pkcs7t.h \
- $(NULL)
-
-PRIVATE_EXPORTS = \
- p7local.h \
- $(NULL)
-
-MODULE = security
-
-CSRCS = \
- p7common.c \
- p7create.c \
- p7decode.c \
- p7encode.c \
- p7local.c \
- secmime.c \
- $(NULL)
-
-REQUIRES = security dbm
-
-LIBRARY_NAME = pkcs7
diff --git a/security/nss/lib/pkcs7/p7common.c b/security/nss/lib/pkcs7/p7common.c
deleted file mode 100644
index e11a7f586..000000000
--- a/security/nss/lib/pkcs7/p7common.c
+++ /dev/null
@@ -1,738 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * PKCS7 implementation -- the exported parts that are used whether
- * creating or decoding.
- *
- * $Id$
- */
-
-#include "p7local.h"
-
-#include "cert.h"
-#include "secitem.h"
-#include "secoid.h"
-#include "secpkcs5.h"
-#include "pk11func.h"
-
-/*
- * Find out (saving pointer to lookup result for future reference)
- * and return the inner content type.
- */
-SECOidTag
-SEC_PKCS7ContentType (SEC_PKCS7ContentInfo *cinfo)
-{
- if (cinfo->contentTypeTag == NULL)
- cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
-
- if (cinfo->contentTypeTag == NULL)
- return SEC_OID_UNKNOWN;
-
- return cinfo->contentTypeTag->offset;
-}
-
-
-/*
- * Destroy a PKCS7 contentInfo and all of its sub-pieces.
- */
-void
-SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *cinfo)
-{
- SECOidTag kind;
- CERTCertificate **certs;
- CERTCertificateList **certlists;
- SEC_PKCS7SignerInfo **signerinfos;
- SEC_PKCS7RecipientInfo **recipientinfos;
-
- PORT_Assert (cinfo->refCount > 0);
- if (cinfo->refCount <= 0)
- return;
-
- cinfo->refCount--;
- if (cinfo->refCount > 0)
- return;
-
- certs = NULL;
- certlists = NULL;
- recipientinfos = NULL;
- signerinfos = NULL;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- {
- SEC_PKCS7EnvelopedData *edp;
-
- edp = cinfo->content.envelopedData;
- if (edp != NULL) {
- recipientinfos = edp->recipientInfos;
- }
- }
- break;
- case SEC_OID_PKCS7_SIGNED_DATA:
- {
- SEC_PKCS7SignedData *sdp;
-
- sdp = cinfo->content.signedData;
- if (sdp != NULL) {
- certs = sdp->certs;
- certlists = sdp->certLists;
- signerinfos = sdp->signerInfos;
- }
- }
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saedp;
-
- saedp = cinfo->content.signedAndEnvelopedData;
- if (saedp != NULL) {
- certs = saedp->certs;
- certlists = saedp->certLists;
- recipientinfos = saedp->recipientInfos;
- signerinfos = saedp->signerInfos;
- if (saedp->sigKey != NULL)
- PK11_FreeSymKey (saedp->sigKey);
- }
- }
- break;
- default:
- /* XXX Anything else that needs to be "manually" freed/destroyed? */
- break;
- }
-
- if (certs != NULL) {
- CERTCertificate *cert;
-
- while ((cert = *certs++) != NULL) {
- CERT_DestroyCertificate (cert);
- }
- }
-
- if (certlists != NULL) {
- CERTCertificateList *certlist;
-
- while ((certlist = *certlists++) != NULL) {
- CERT_DestroyCertificateList (certlist);
- }
- }
-
- if (recipientinfos != NULL) {
- SEC_PKCS7RecipientInfo *ri;
-
- while ((ri = *recipientinfos++) != NULL) {
- if (ri->cert != NULL)
- CERT_DestroyCertificate (ri->cert);
- }
- }
-
- if (signerinfos != NULL) {
- SEC_PKCS7SignerInfo *si;
-
- while ((si = *signerinfos++) != NULL) {
- if (si->cert != NULL)
- CERT_DestroyCertificate (si->cert);
- if (si->certList != NULL)
- CERT_DestroyCertificateList (si->certList);
- }
- }
-
- if (cinfo->poolp != NULL) {
- PORT_FreeArena (cinfo->poolp, PR_FALSE); /* XXX clear it? */
- }
-}
-
-
-/*
- * Return a copy of the given contentInfo. The copy may be virtual
- * or may be real -- either way, the result needs to be passed to
- * SEC_PKCS7DestroyContentInfo later (as does the original).
- */
-SEC_PKCS7ContentInfo *
-SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *cinfo)
-{
- if (cinfo == NULL)
- return NULL;
-
- PORT_Assert (cinfo->refCount > 0);
-
- if (cinfo->created) {
- /*
- * Want to do a real copy of these; otherwise subsequent
- * changes made to either copy are likely to be a surprise.
- * XXX I suspect that this will not actually be called for yet,
- * which is why the assert, so to notice if it is...
- */
- PORT_Assert (0);
- /*
- * XXX Create a new pool here, and copy everything from
- * within. For cert stuff, need to call the appropriate
- * copy functions, etc.
- */
- }
-
- cinfo->refCount++;
- return cinfo;
-}
-
-
-/*
- * Return a pointer to the actual content. In the case of those types
- * which are encrypted, this returns the *plain* content.
- * XXX Needs revisiting if/when we handle nested encrypted types.
- */
-SECItem *
-SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo)
-{
- SECOidTag kind;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- case SEC_OID_PKCS7_DATA:
- return cinfo->content.data;
- case SEC_OID_PKCS7_DIGESTED_DATA:
- {
- SEC_PKCS7DigestedData *digd;
-
- digd = cinfo->content.digestedData;
- if (digd == NULL)
- break;
- return SEC_PKCS7GetContent (&(digd->contentInfo));
- }
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- {
- SEC_PKCS7EncryptedData *encd;
-
- encd = cinfo->content.encryptedData;
- if (encd == NULL)
- break;
- return &(encd->encContentInfo.plainContent);
- }
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- {
- SEC_PKCS7EnvelopedData *envd;
-
- envd = cinfo->content.envelopedData;
- if (envd == NULL)
- break;
- return &(envd->encContentInfo.plainContent);
- }
- case SEC_OID_PKCS7_SIGNED_DATA:
- {
- SEC_PKCS7SignedData *sigd;
-
- sigd = cinfo->content.signedData;
- if (sigd == NULL)
- break;
- return SEC_PKCS7GetContent (&(sigd->contentInfo));
- }
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saed;
-
- saed = cinfo->content.signedAndEnvelopedData;
- if (saed == NULL)
- break;
- return &(saed->encContentInfo.plainContent);
- }
- default:
- PORT_Assert(0);
- break;
- }
-
- return NULL;
-}
-
-
-/*
- * XXX Fix the placement and formatting of the
- * following routines (i.e. make them consistent with the rest of
- * the pkcs7 code -- I think some/many belong in other files and
- * they all need a formatting/style rehaul)
- */
-
-/* retrieve the algorithm identifier for encrypted data.
- * the identifier returned is a copy of the algorithm identifier
- * in the content info and needs to be freed after being used.
- *
- * cinfo is the content info for which to retrieve the
- * encryption algorithm.
- *
- * if the content info is not encrypted data or an error
- * occurs NULL is returned.
- */
-SECAlgorithmID *
-SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo)
-{
- SECAlgorithmID *alg = 0;
- switch (SEC_PKCS7ContentType(cinfo))
- {
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- alg = &cinfo->content.encryptedData->encContentInfo.contentEncAlg;
- break;
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- alg = &cinfo->content.envelopedData->encContentInfo.contentEncAlg;
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- alg = &cinfo->content.signedAndEnvelopedData
- ->encContentInfo.contentEncAlg;
- break;
- default:
- alg = 0;
- break;
- }
-
- return alg;
-}
-
-/* set the content of the content info. For data content infos,
- * the data is set. For encrytped content infos, the plainContent
- * is set, and is expected to be encrypted later.
- *
- * cinfo is the content info where the data will be set
- *
- * buf is a buffer of the data to set
- *
- * len is the length of the data being set.
- *
- * in the event of an error, SECFailure is returned. SECSuccess
- * indicates the content was successfully set.
- */
-SECStatus
-SEC_PKCS7SetContent(SEC_PKCS7ContentInfo *cinfo,
- const char *buf,
- unsigned long len)
-{
- SECOidTag cinfo_type;
- SECStatus rv;
- SECItem content;
- SECOidData *contentTypeTag = NULL;
-
- content.data = (unsigned char *)buf;
- content.len = len;
-
- cinfo_type = SEC_PKCS7ContentType(cinfo);
-
- /* set inner content */
- switch(cinfo_type)
- {
- case SEC_OID_PKCS7_SIGNED_DATA:
- if(content.len > 0) {
- /* we "leak" the old content here, but as it's all in the pool */
- /* it does not really matter */
-
- /* create content item if necessary */
- if (cinfo->content.signedData->contentInfo.content.data == NULL)
- cinfo->content.signedData->contentInfo.content.data = SECITEM_AllocItem(cinfo->poolp, NULL, 0);
- rv = SECITEM_CopyItem(cinfo->poolp,
- cinfo->content.signedData->contentInfo.content.data,
- &content);
- } else {
- cinfo->content.signedData->contentInfo.content.data->data = NULL;
- cinfo->content.signedData->contentInfo.content.data->len = 0;
- rv = SECSuccess;
- }
- if(rv == SECFailure)
- goto loser;
-
- break;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- /* XXX this forces the inner content type to be "data" */
- /* do we really want to override without asking or reason? */
- contentTypeTag = SECOID_FindOIDByTag(SEC_OID_PKCS7_DATA);
- if(contentTypeTag == NULL)
- goto loser;
- rv = SECITEM_CopyItem(cinfo->poolp,
- &(cinfo->content.encryptedData->encContentInfo.contentType),
- &(contentTypeTag->oid));
- if(rv == SECFailure)
- goto loser;
- if(content.len > 0) {
- rv = SECITEM_CopyItem(cinfo->poolp,
- &(cinfo->content.encryptedData->encContentInfo.plainContent),
- &content);
- } else {
- cinfo->content.encryptedData->encContentInfo.plainContent.data = NULL;
- cinfo->content.encryptedData->encContentInfo.encContent.data = NULL;
- cinfo->content.encryptedData->encContentInfo.plainContent.len = 0;
- cinfo->content.encryptedData->encContentInfo.encContent.len = 0;
- rv = SECSuccess;
- }
- if(rv == SECFailure)
- goto loser;
- break;
- case SEC_OID_PKCS7_DATA:
- cinfo->content.data = (SECItem *)PORT_ArenaZAlloc(cinfo->poolp,
- sizeof(SECItem));
- if(cinfo->content.data == NULL)
- goto loser;
- if(content.len > 0) {
- rv = SECITEM_CopyItem(cinfo->poolp,
- cinfo->content.data, &content);
- } else {
- /* handle case with NULL content */
- rv = SECSuccess;
- }
- if(rv == SECFailure)
- goto loser;
- break;
- default:
- goto loser;
- }
-
- return SECSuccess;
-
-loser:
-
- return SECFailure;
-}
-
-/* the content of an encrypted data content info is encrypted.
- * it is assumed that for encrypted data, that the data has already
- * been set and is in the "plainContent" field of the content info.
- *
- * cinfo is the content info to encrypt
- *
- * key is the key with which to perform the encryption. if the
- * algorithm is a password based encryption algorithm, the
- * key is actually a password which will be processed per
- * PKCS #5.
- *
- * in the event of an error, SECFailure is returned. SECSuccess
- * indicates a success.
- */
-SECStatus
-SEC_PKCS7EncryptContents(PRArenaPool *poolp,
- SEC_PKCS7ContentInfo *cinfo,
- SECItem *key,
- void *wincx)
-{
- SECAlgorithmID *algid = NULL;
- SECItem * result = NULL;
- SECItem * src;
- SECItem * dest;
- SECItem * blocked_data = NULL;
- void * mark;
- void * cx;
- PK11SymKey * eKey = NULL;
- PK11SlotInfo * slot = NULL;
-
- CK_MECHANISM pbeMech;
- CK_MECHANISM cryptoMech;
- int bs;
- SECOidTag algtag;
- SECStatus rv = SECFailure;
- SECItem c_param;
-
- if((cinfo == NULL) || (key == NULL))
- return SECFailure;
-
- if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
- return SECFailure;
-
- algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
- if(algid == NULL)
- return SECFailure;
-
- if(poolp == NULL)
- poolp = cinfo->poolp;
-
- mark = PORT_ArenaMark(poolp);
-
- src = &cinfo->content.encryptedData->encContentInfo.plainContent;
- dest = &cinfo->content.encryptedData->encContentInfo.encContent;
- algtag = SECOID_GetAlgorithmTag(algid);
- c_param.data = NULL;
- dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
- dest->len = (src->len + 64);
- if(dest->data == NULL) {
- rv = SECFailure;
- goto loser;
- }
-
- slot = PK11_GetInternalKeySlot();
- if(slot == NULL) {
- rv = SECFailure;
- goto loser;
- }
- eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
- if(eKey == NULL) {
- rv = SECFailure;
- goto loser;
- }
-
- pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
- result = PK11_ParamFromAlgid(algid);
- pbeMech.pParameter = result->data;
- pbeMech.ulParameterLen = result->len;
- if(PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, key,
- PR_FALSE) != CKR_OK) {
- rv = SECFailure;
- goto loser;
- }
- c_param.data = (unsigned char *)cryptoMech.pParameter;
- c_param.len = cryptoMech.ulParameterLen;
-
- /* block according to PKCS 8 */
- bs = PK11_GetBlockSize(cryptoMech.mechanism, &c_param);
- rv = SECSuccess;
- if(bs) {
- char pad_char;
- pad_char = (char)(bs - (src->len % bs));
- if(src->len % bs) {
- rv = SECSuccess;
- blocked_data = PK11_BlockData(src, bs);
- if(blocked_data) {
- PORT_Memset((blocked_data->data + blocked_data->len - (int)pad_char),
- pad_char, (int)pad_char);
- } else {
- rv = SECFailure;
- goto loser;
- }
- } else {
- blocked_data = SECITEM_DupItem(src);
- if(blocked_data) {
- blocked_data->data = (unsigned char*)PORT_Realloc(
- blocked_data->data,
- blocked_data->len + bs);
- if(blocked_data->data) {
- blocked_data->len += bs;
- PORT_Memset((blocked_data->data + src->len), (char)bs, bs);
- } else {
- rv = SECFailure;
- goto loser;
- }
- } else {
- rv = SECFailure;
- goto loser;
- }
- }
- } else {
- blocked_data = SECITEM_DupItem(src);
- if(!blocked_data) {
- rv = SECFailure;
- goto loser;
- }
- }
-
- cx = PK11_CreateContextBySymKey(cryptoMech.mechanism, CKA_ENCRYPT,
- eKey, &c_param);
- if(cx == NULL) {
- rv = SECFailure;
- goto loser;
- }
-
- rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len),
- (int)(src->len + 64), blocked_data->data,
- (int)blocked_data->len);
- PK11_DestroyContext((PK11Context*)cx, PR_TRUE);
-
-loser:
- /* let success fall through */
- if(blocked_data != NULL)
- SECITEM_ZfreeItem(blocked_data, PR_TRUE);
-
- if(result != NULL)
- SECITEM_ZfreeItem(result, PR_TRUE);
-
- if(rv == SECFailure)
- PORT_ArenaRelease(poolp, mark);
- else
- PORT_ArenaUnmark(poolp, mark);
-
- if(eKey != NULL)
- PK11_FreeSymKey(eKey);
-
- if(slot != NULL)
- PK11_FreeSlot(slot);
-
- if(c_param.data != NULL)
- SECITEM_ZfreeItem(&c_param, PR_FALSE);
-
- return rv;
-}
-
-/* the content of an encrypted data content info is decrypted.
- * it is assumed that for encrypted data, that the data has already
- * been set and is in the "encContent" field of the content info.
- *
- * cinfo is the content info to decrypt
- *
- * key is the key with which to perform the decryption. if the
- * algorithm is a password based encryption algorithm, the
- * key is actually a password which will be processed per
- * PKCS #5.
- *
- * in the event of an error, SECFailure is returned. SECSuccess
- * indicates a success.
- */
-SECStatus
-SEC_PKCS7DecryptContents(PRArenaPool *poolp,
- SEC_PKCS7ContentInfo *cinfo,
- SECItem *key,
- void *wincx)
-{
- SECAlgorithmID *algid = NULL;
- SECOidTag algtag;
- SECStatus rv = SECFailure;
- SECItem *result = NULL, *dest, *src;
- void *mark;
-
- PK11SymKey *eKey = NULL;
- PK11SlotInfo *slot = NULL;
- CK_MECHANISM pbeMech, cryptoMech;
- void *cx;
- SECItem c_param;
- int bs;
-
- if((cinfo == NULL) || (key == NULL))
- return SECFailure;
-
- if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
- return SECFailure;
-
- algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
- if(algid == NULL)
- return SECFailure;
-
- if(poolp == NULL)
- poolp = cinfo->poolp;
-
- mark = PORT_ArenaMark(poolp);
-
- src = &cinfo->content.encryptedData->encContentInfo.encContent;
- dest = &cinfo->content.encryptedData->encContentInfo.plainContent;
- algtag = SECOID_GetAlgorithmTag(algid);
- c_param.data = NULL;
- dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
- dest->len = (src->len + 64);
- if(dest->data == NULL) {
- rv = SECFailure;
- goto loser;
- }
-
- slot = PK11_GetInternalKeySlot();
- if(slot == NULL) {
- rv = SECFailure;
- goto loser;
- }
- eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
- if(eKey == NULL) {
- rv = SECFailure;
- goto loser;
- }
-
- pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
- result = PK11_ParamFromAlgid(algid);
- pbeMech.pParameter = result->data;
- pbeMech.ulParameterLen = result->len;
- if(PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, key,
- PR_FALSE) != CKR_OK) {
- rv = SECFailure;
- goto loser;
- }
- c_param.data = (unsigned char *)cryptoMech.pParameter;
- c_param.len = cryptoMech.ulParameterLen;
-
- cx = PK11_CreateContextBySymKey(cryptoMech.mechanism, CKA_DECRYPT,
- eKey, &c_param);
- if(cx == NULL) {
- rv = SECFailure;
- goto loser;
- }
-
- rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len),
- (int)(src->len + 64), src->data, (int)src->len);
- PK11_DestroyContext((PK11Context *)cx, PR_TRUE);
-
- bs = PK11_GetBlockSize(cryptoMech.mechanism, &c_param);
- if(bs) {
- /* check for proper badding in block algorithms. this assumes
- * RC2 cbc or a DES cbc variant. and the padding is thus defined
- */
- if(((int)dest->data[dest->len-1] <= bs) &&
- ((int)dest->data[dest->len-1] > 0)) {
- dest->len -= (int)dest->data[dest->len-1];
- } else {
- rv = SECFailure;
- /* set an error ? */
- }
- }
-
-loser:
- /* let success fall through */
- if(result != NULL)
- SECITEM_ZfreeItem(result, PR_TRUE);
-
- if(rv == SECFailure)
- PORT_ArenaRelease(poolp, mark);
- else
- PORT_ArenaUnmark(poolp, mark);
-
- if(eKey != NULL)
- PK11_FreeSymKey(eKey);
-
- if(slot != NULL)
- PK11_FreeSlot(slot);
-
- if(c_param.data != NULL)
- SECITEM_ZfreeItem(&c_param, PR_FALSE);
-
- return rv;
-}
-
-SECItem **
-SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo)
-{
- switch(SEC_PKCS7ContentType(cinfo))
- {
- case SEC_OID_PKCS7_SIGNED_DATA:
- return cinfo->content.signedData->rawCerts;
- break;
- default:
- return NULL;
- break;
- }
-}
-
-
-int
-SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo)
-{
- if (cinfo->contentTypeTag->offset == SEC_OID_PKCS7_ENVELOPED_DATA)
- return cinfo->content.envelopedData->encContentInfo.keysize;
- else
- return 0;
-}
-
diff --git a/security/nss/lib/pkcs7/p7create.c b/security/nss/lib/pkcs7/p7create.c
deleted file mode 100644
index 665d8495c..000000000
--- a/security/nss/lib/pkcs7/p7create.c
+++ /dev/null
@@ -1,1320 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * PKCS7 creation.
- *
- * $Id$
- */
-
-#include "p7local.h"
-
-#include "cert.h"
-#include "secasn1.h"
-#include "secitem.h"
-#include "secoid.h"
-#include "secpkcs5.h"
-#include "pk11func.h"
-#include "prtime.h"
-#include "secerr.h"
-
-static SECStatus
-sec_pkcs7_init_content_info (SEC_PKCS7ContentInfo *cinfo, PRArenaPool *poolp,
- SECOidTag kind, PRBool detached)
-{
- void *thing;
- int version;
- SECItem *versionp;
- SECStatus rv;
-
- PORT_Assert (cinfo != NULL && poolp != NULL);
- if (cinfo == NULL || poolp == NULL)
- return SECFailure;
-
- cinfo->contentTypeTag = SECOID_FindOIDByTag (kind);
- PORT_Assert (cinfo->contentTypeTag
- && cinfo->contentTypeTag->offset == kind);
-
- rv = SECITEM_CopyItem (poolp, &(cinfo->contentType),
- &(cinfo->contentTypeTag->oid));
- if (rv != SECSuccess)
- return rv;
-
- if (detached)
- return SECSuccess;
-
- switch (kind) {
- default:
- case SEC_OID_PKCS7_DATA:
- thing = PORT_ArenaZAlloc (poolp, sizeof(SECItem));
- cinfo->content.data = (SECItem*)thing;
- versionp = NULL;
- version = -1;
- break;
- case SEC_OID_PKCS7_DIGESTED_DATA:
- thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7DigestedData));
- cinfo->content.digestedData = (SEC_PKCS7DigestedData*)thing;
- versionp = &(cinfo->content.digestedData->version);
- version = SEC_PKCS7_DIGESTED_DATA_VERSION;
- break;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EncryptedData));
- cinfo->content.encryptedData = (SEC_PKCS7EncryptedData*)thing;
- versionp = &(cinfo->content.encryptedData->version);
- version = SEC_PKCS7_ENCRYPTED_DATA_VERSION;
- break;
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EnvelopedData));
- cinfo->content.envelopedData =
- (SEC_PKCS7EnvelopedData*)thing;
- versionp = &(cinfo->content.envelopedData->version);
- version = SEC_PKCS7_ENVELOPED_DATA_VERSION;
- break;
- case SEC_OID_PKCS7_SIGNED_DATA:
- thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7SignedData));
- cinfo->content.signedData =
- (SEC_PKCS7SignedData*)thing;
- versionp = &(cinfo->content.signedData->version);
- version = SEC_PKCS7_SIGNED_DATA_VERSION;
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- thing = PORT_ArenaZAlloc(poolp,sizeof(SEC_PKCS7SignedAndEnvelopedData));
- cinfo->content.signedAndEnvelopedData =
- (SEC_PKCS7SignedAndEnvelopedData*)thing;
- versionp = &(cinfo->content.signedAndEnvelopedData->version);
- version = SEC_PKCS7_SIGNED_AND_ENVELOPED_DATA_VERSION;
- break;
- }
-
- if (thing == NULL)
- return SECFailure;
-
- if (versionp != NULL) {
- SECItem *dummy;
-
- PORT_Assert (version >= 0);
- dummy = SEC_ASN1EncodeInteger (poolp, versionp, version);
- if (dummy == NULL)
- return SECFailure;
- PORT_Assert (dummy == versionp);
- }
-
- return SECSuccess;
-}
-
-
-static SEC_PKCS7ContentInfo *
-sec_pkcs7_create_content_info (SECOidTag kind, PRBool detached,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg)
-{
- SEC_PKCS7ContentInfo *cinfo;
- PRArenaPool *poolp;
- SECStatus rv;
-
- poolp = PORT_NewArena (1024); /* XXX what is right value? */
- if (poolp == NULL)
- return NULL;
-
- cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo));
- if (cinfo == NULL) {
- PORT_FreeArena (poolp, PR_FALSE);
- return NULL;
- }
-
- cinfo->poolp = poolp;
- cinfo->pwfn = pwfn;
- cinfo->pwfn_arg = pwfn_arg;
- cinfo->created = PR_TRUE;
- cinfo->refCount = 1;
-
- rv = sec_pkcs7_init_content_info (cinfo, poolp, kind, detached);
- if (rv != SECSuccess) {
- PORT_FreeArena (poolp, PR_FALSE);
- return NULL;
- }
-
- return cinfo;
-}
-
-
-/*
- * Add a signer to a PKCS7 thing, verifying the signature cert first.
- * Any error returns SECFailure.
- *
- * XXX Right now this only adds the *first* signer. It fails if you try
- * to add a second one -- this needs to be fixed.
- */
-static SECStatus
-sec_pkcs7_add_signer (SEC_PKCS7ContentInfo *cinfo,
- CERTCertificate * cert,
- SECCertUsage certusage,
- CERTCertDBHandle * certdb,
- SECOidTag digestalgtag,
- SECItem * digestdata)
-{
- SEC_PKCS7SignerInfo *signerinfo, **signerinfos, ***signerinfosp;
- SECAlgorithmID *digestalg, **digestalgs, ***digestalgsp;
- SECItem *digest, **digests, ***digestsp;
- SECItem * dummy;
- void * mark;
- SECStatus rv;
- SECOidTag kind;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- case SEC_OID_PKCS7_SIGNED_DATA:
- {
- SEC_PKCS7SignedData *sdp;
-
- sdp = cinfo->content.signedData;
- digestalgsp = &(sdp->digestAlgorithms);
- digestsp = &(sdp->digests);
- signerinfosp = &(sdp->signerInfos);
- }
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saedp;
-
- saedp = cinfo->content.signedAndEnvelopedData;
- digestalgsp = &(saedp->digestAlgorithms);
- digestsp = &(saedp->digests);
- signerinfosp = &(saedp->signerInfos);
- }
- break;
- default:
- return SECFailure; /* XXX set an error? */
- }
-
- /*
- * XXX I think that CERT_VerifyCert should do this if *it* is passed
- * a NULL database.
- */
- if (certdb == NULL) {
- certdb = CERT_GetDefaultCertDB();
- if (certdb == NULL)
- return SECFailure; /* XXX set an error? */
- }
-
- if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(),
- cinfo->pwfn_arg, NULL) != SECSuccess)
- {
- /* XXX Did CERT_VerifyCert set an error? */
- return SECFailure;
- }
-
- /*
- * XXX This is the check that we do not already have a signer.
- * This is not what we really want -- we want to allow this
- * and *add* the new signer.
- */
- PORT_Assert (*signerinfosp == NULL
- && *digestalgsp == NULL && *digestsp == NULL);
- if (*signerinfosp != NULL || *digestalgsp != NULL || *digestsp != NULL)
- return SECFailure;
-
- mark = PORT_ArenaMark (cinfo->poolp);
-
- signerinfo = (SEC_PKCS7SignerInfo*)PORT_ArenaZAlloc (cinfo->poolp,
- sizeof(SEC_PKCS7SignerInfo));
- if (signerinfo == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
-
- dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &signerinfo->version,
- SEC_PKCS7_SIGNER_INFO_VERSION);
- if (dummy == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
- PORT_Assert (dummy == &signerinfo->version);
-
- signerinfo->cert = CERT_DupCertificate (cert);
- if (signerinfo->cert == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
-
- signerinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert);
- if (signerinfo->issuerAndSN == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
-
- rv = SECOID_SetAlgorithmID (cinfo->poolp, &signerinfo->digestAlg,
- digestalgtag, NULL);
- if (rv != SECSuccess) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
-
- /*
- * Okay, now signerinfo is all set. We just need to put it and its
- * companions (another copy of the digest algorithm, and the digest
- * itself if given) into the main structure.
- *
- * XXX If we are handling more than one signer, the following code
- * needs to look through the digest algorithms already specified
- * and see if the same one is there already. If it is, it does not
- * need to be added again. Also, if it is there *and* the digest
- * is not null, then the digest given should match the digest already
- * specified -- if not, that is an error. Finally, the new signerinfo
- * should be *added* to the set already found.
- */
-
- signerinfos = (SEC_PKCS7SignerInfo**)PORT_ArenaAlloc (cinfo->poolp,
- 2 * sizeof(SEC_PKCS7SignerInfo *));
- if (signerinfos == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
- signerinfos[0] = signerinfo;
- signerinfos[1] = NULL;
-
- digestalg = PORT_ArenaZAlloc (cinfo->poolp, sizeof(SECAlgorithmID));
- digestalgs = PORT_ArenaAlloc (cinfo->poolp, 2 * sizeof(SECAlgorithmID *));
- if (digestalg == NULL || digestalgs == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
- rv = SECOID_SetAlgorithmID (cinfo->poolp, digestalg, digestalgtag, NULL);
- if (rv != SECSuccess) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
- digestalgs[0] = digestalg;
- digestalgs[1] = NULL;
-
- if (digestdata != NULL) {
- digest = (SECItem*)PORT_ArenaAlloc (cinfo->poolp, sizeof(SECItem));
- digests = (SECItem**)PORT_ArenaAlloc (cinfo->poolp,
- 2 * sizeof(SECItem *));
- if (digest == NULL || digests == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
- rv = SECITEM_CopyItem (cinfo->poolp, digest, digestdata);
- if (rv != SECSuccess) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
- digests[0] = digest;
- digests[1] = NULL;
- } else {
- digests = NULL;
- }
-
- *signerinfosp = signerinfos;
- *digestalgsp = digestalgs;
- *digestsp = digests;
-
- PORT_ArenaUnmark(cinfo->poolp, mark);
- return SECSuccess;
-}
-
-
-/*
- * Helper function for creating an empty signedData.
- */
-static SEC_PKCS7ContentInfo *
-sec_pkcs7_create_signed_data (SECKEYGetPasswordKey pwfn, void *pwfn_arg)
-{
- SEC_PKCS7ContentInfo *cinfo;
- SEC_PKCS7SignedData *sigd;
- SECStatus rv;
-
- cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_SIGNED_DATA, PR_FALSE,
- pwfn, pwfn_arg);
- if (cinfo == NULL)
- return NULL;
-
- sigd = cinfo->content.signedData;
- PORT_Assert (sigd != NULL);
-
- /*
- * XXX Might we want to allow content types other than data?
- * If so, via what interface?
- */
- rv = sec_pkcs7_init_content_info (&(sigd->contentInfo), cinfo->poolp,
- SEC_OID_PKCS7_DATA, PR_TRUE);
- if (rv != SECSuccess) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- return NULL;
- }
-
- return cinfo;
-}
-
-
-/*
- * Start a PKCS7 signing context.
- *
- * "cert" is the cert that will be used to sign the data. It will be
- * checked for validity.
- *
- * "certusage" describes the signing usage (e.g. certUsageEmailSigner)
- * XXX Maybe SECCertUsage should be split so that our caller just says
- * "email" and *we* add the "signing" part -- otherwise our caller
- * could be lying about the usage; we do not want to allow encryption
- * certs for signing or vice versa.
- *
- * "certdb" is the cert database to use for verifying the cert.
- * It can be NULL if a default database is available (like in the client).
- *
- * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
- *
- * "digest" is the actual digest of the data. It must be provided in
- * the case of detached data or NULL if the content will be included.
- *
- * The return value can be passed to functions which add things to
- * it like attributes, then eventually to SEC_PKCS7Encode() or to
- * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
- * SEC_PKCS7DestroyContentInfo().
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-SEC_PKCS7ContentInfo *
-SEC_PKCS7CreateSignedData (CERTCertificate *cert,
- SECCertUsage certusage,
- CERTCertDBHandle *certdb,
- SECOidTag digestalg,
- SECItem *digest,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg)
-{
- SEC_PKCS7ContentInfo *cinfo;
- SECStatus rv;
-
- cinfo = sec_pkcs7_create_signed_data (pwfn, pwfn_arg);
- if (cinfo == NULL)
- return NULL;
-
- rv = sec_pkcs7_add_signer (cinfo, cert, certusage, certdb,
- digestalg, digest);
- if (rv != SECSuccess) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- return NULL;
- }
-
- return cinfo;
-}
-
-
-static SEC_PKCS7Attribute *
-sec_pkcs7_create_attribute (PRArenaPool *poolp, SECOidTag oidtag,
- SECItem *value, PRBool encoded)
-{
- SEC_PKCS7Attribute *attr;
- SECItem **values;
- void *mark;
-
- PORT_Assert (poolp != NULL);
- mark = PORT_ArenaMark (poolp);
-
- attr = (SEC_PKCS7Attribute*)PORT_ArenaAlloc (poolp,
- sizeof(SEC_PKCS7Attribute));
- if (attr == NULL)
- goto loser;
-
- attr->typeTag = SECOID_FindOIDByTag (oidtag);
- if (attr->typeTag == NULL)
- goto loser;
-
- if (SECITEM_CopyItem (poolp, &(attr->type),
- &(attr->typeTag->oid)) != SECSuccess)
- goto loser;
-
- values = (SECItem**)PORT_ArenaAlloc (poolp, 2 * sizeof(SECItem *));
- if (values == NULL)
- goto loser;
-
- if (value != NULL) {
- SECItem *copy;
-
- copy = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
- if (copy == NULL)
- goto loser;
-
- if (SECITEM_CopyItem (poolp, copy, value) != SECSuccess)
- goto loser;
-
- value = copy;
- }
-
- values[0] = value;
- values[1] = NULL;
- attr->values = values;
- attr->encoded = encoded;
-
- PORT_ArenaUnmark (poolp, mark);
- return attr;
-
-loser:
- PORT_Assert (mark != NULL);
- PORT_ArenaRelease (poolp, mark);
- return NULL;
-}
-
-
-static SECStatus
-sec_pkcs7_add_attribute (SEC_PKCS7ContentInfo *cinfo,
- SEC_PKCS7Attribute ***attrsp,
- SEC_PKCS7Attribute *attr)
-{
- SEC_PKCS7Attribute **attrs;
- SECItem *ct_value;
- void *mark;
-
- PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
- if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
- return SECFailure;
-
- attrs = *attrsp;
- if (attrs != NULL) {
- int count;
-
- /*
- * We already have some attributes, and just need to add this
- * new one.
- */
-
- /*
- * We should already have the *required* attributes, which were
- * created/added at the same time the first attribute was added.
- */
- PORT_Assert (sec_PKCS7FindAttribute (attrs,
- SEC_OID_PKCS9_CONTENT_TYPE,
- PR_FALSE) != NULL);
- PORT_Assert (sec_PKCS7FindAttribute (attrs,
- SEC_OID_PKCS9_MESSAGE_DIGEST,
- PR_FALSE) != NULL);
-
- for (count = 0; attrs[count] != NULL; count++)
- ;
- attrs = (SEC_PKCS7Attribute**)PORT_ArenaGrow (cinfo->poolp, attrs,
- (count + 1) * sizeof(SEC_PKCS7Attribute *),
- (count + 2) * sizeof(SEC_PKCS7Attribute *));
- if (attrs == NULL)
- return SECFailure;
-
- attrs[count] = attr;
- attrs[count+1] = NULL;
- *attrsp = attrs;
-
- return SECSuccess;
- }
-
- /*
- * This is the first time an attribute is going in.
- * We need to create and add the required attributes, and then
- * we will also add in the one our caller gave us.
- */
-
- /*
- * There are 2 required attributes, plus the one our caller wants
- * to add, plus we always end with a NULL one. Thus, four slots.
- */
- attrs = (SEC_PKCS7Attribute**)PORT_ArenaAlloc (cinfo->poolp,
- 4 * sizeof(SEC_PKCS7Attribute *));
- if (attrs == NULL)
- return SECFailure;
-
- mark = PORT_ArenaMark (cinfo->poolp);
-
- /*
- * First required attribute is the content type of the data
- * being signed.
- */
- ct_value = &(cinfo->content.signedData->contentInfo.contentType);
- attrs[0] = sec_pkcs7_create_attribute (cinfo->poolp,
- SEC_OID_PKCS9_CONTENT_TYPE,
- ct_value, PR_FALSE);
- /*
- * Second required attribute is the message digest of the data
- * being signed; we leave the value NULL for now (just create
- * the place for it to go), and the encoder will fill it in later.
- */
- attrs[1] = sec_pkcs7_create_attribute (cinfo->poolp,
- SEC_OID_PKCS9_MESSAGE_DIGEST,
- NULL, PR_FALSE);
- if (attrs[0] == NULL || attrs[1] == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
-
- attrs[2] = attr;
- attrs[3] = NULL;
- *attrsp = attrs;
-
- PORT_ArenaUnmark (cinfo->poolp, mark);
- return SECSuccess;
-}
-
-
-/*
- * Add the signing time to the authenticated (i.e. signed) attributes
- * of "cinfo". This is expected to be included in outgoing signed
- * messages for email (S/MIME) but is likely useful in other situations.
- *
- * This should only be added once; a second call will either do
- * nothing or replace an old signing time with a newer one.
- *
- * XXX This will probably just shove the current time into "cinfo"
- * but it will not actually get signed until the entire item is
- * processed for encoding. Is this (expected to be small) delay okay?
- *
- * "cinfo" should be of type signedData (the only kind of pkcs7 data
- * that is allowed authenticated attributes); SECFailure will be returned
- * if it is not.
- */
-SECStatus
-SEC_PKCS7AddSigningTime (SEC_PKCS7ContentInfo *cinfo)
-{
- SEC_PKCS7SignerInfo **signerinfos;
- SEC_PKCS7Attribute *attr;
- SECItem stime;
- SECStatus rv;
- int si;
-
- PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
- if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
- return SECFailure;
-
- signerinfos = cinfo->content.signedData->signerInfos;
-
- /* There has to be a signer, or it makes no sense. */
- if (signerinfos == NULL || signerinfos[0] == NULL)
- return SECFailure;
-
- rv = DER_TimeToUTCTime (&stime, PR_Now());
- if (rv != SECSuccess)
- return rv;
-
- attr = sec_pkcs7_create_attribute (cinfo->poolp,
- SEC_OID_PKCS9_SIGNING_TIME,
- &stime, PR_FALSE);
- SECITEM_FreeItem (&stime, PR_FALSE);
-
- if (attr == NULL)
- return SECFailure;
-
- rv = SECSuccess;
- for (si = 0; signerinfos[si] != NULL; si++) {
- SEC_PKCS7Attribute *oattr;
-
- oattr = sec_PKCS7FindAttribute (signerinfos[si]->authAttr,
- SEC_OID_PKCS9_SIGNING_TIME, PR_FALSE);
- PORT_Assert (oattr == NULL);
- if (oattr != NULL)
- continue; /* XXX or would it be better to replace it? */
-
- rv = sec_pkcs7_add_attribute (cinfo, &(signerinfos[si]->authAttr),
- attr);
- if (rv != SECSuccess)
- break; /* could try to continue, but may as well give up now */
- }
-
- return rv;
-}
-
-
-/*
- * Add the specified attribute to the authenticated (i.e. signed) attributes
- * of "cinfo" -- "oidtag" describes the attribute and "value" is the
- * value to be associated with it. NOTE! "value" must already be encoded;
- * no interpretation of "oidtag" is done. Also, it is assumed that this
- * signedData has only one signer -- if we ever need to add attributes
- * when there is more than one signature, we need a way to specify *which*
- * signature should get the attribute.
- *
- * XXX Technically, a signed attribute can have multiple values; if/when
- * we ever need to support an attribute which takes multiple values, we
- * either need to change this interface or create an AddSignedAttributeValue
- * which can be called subsequently, and would then append a value.
- *
- * "cinfo" should be of type signedData (the only kind of pkcs7 data
- * that is allowed authenticated attributes); SECFailure will be returned
- * if it is not.
- */
-SECStatus
-SEC_PKCS7AddSignedAttribute (SEC_PKCS7ContentInfo *cinfo,
- SECOidTag oidtag,
- SECItem *value)
-{
- SEC_PKCS7SignerInfo **signerinfos;
- SEC_PKCS7Attribute *attr;
-
- PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
- if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
- return SECFailure;
-
- signerinfos = cinfo->content.signedData->signerInfos;
-
- /*
- * No signature or more than one means no deal.
- */
- if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
- return SECFailure;
-
- attr = sec_pkcs7_create_attribute (cinfo->poolp, oidtag, value, PR_TRUE);
- if (attr == NULL)
- return SECFailure;
-
- return sec_pkcs7_add_attribute (cinfo, &(signerinfos[0]->authAttr), attr);
-}
-
-
-/*
- * Mark that the signer certificates and their issuing chain should
- * be included in the encoded data. This is expected to be used
- * in outgoing signed messages for email (S/MIME).
- *
- * "certdb" is the cert database to use for finding the chain.
- * It can be NULL, meaning use the default database.
- *
- * "cinfo" should be of type signedData or signedAndEnvelopedData;
- * SECFailure will be returned if it is not.
- */
-SECStatus
-SEC_PKCS7IncludeCertChain (SEC_PKCS7ContentInfo *cinfo,
- CERTCertDBHandle *certdb)
-{
- SECOidTag kind;
- SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- case SEC_OID_PKCS7_SIGNED_DATA:
- signerinfos = cinfo->content.signedData->signerInfos;
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
- break;
- default:
- return SECFailure; /* XXX set an error? */
- }
-
- if (signerinfos == NULL) /* no signer, no certs? */
- return SECFailure; /* XXX set an error? */
-
- if (certdb == NULL) {
- certdb = CERT_GetDefaultCertDB();
- if (certdb == NULL) {
- PORT_SetError (SEC_ERROR_BAD_DATABASE);
- return SECFailure;
- }
- }
-
- /* XXX Should it be an error if we find no signerinfo or no certs? */
- while ((signerinfo = *signerinfos++) != NULL) {
- if (signerinfo->cert != NULL)
- /* get the cert chain. don't send the root to avoid contamination
- * of old clients with a new root that they don't trust
- */
- signerinfo->certList = CERT_CertChainFromCert (signerinfo->cert,
- certUsageEmailSigner,
- PR_FALSE);
- }
-
- return SECSuccess;
-}
-
-
-/*
- * Helper function to add a certificate chain for inclusion in the
- * bag of certificates in a signedData.
- */
-static SECStatus
-sec_pkcs7_add_cert_chain (SEC_PKCS7ContentInfo *cinfo,
- CERTCertificate *cert,
- CERTCertDBHandle *certdb)
-{
- SECOidTag kind;
- CERTCertificateList *certlist, **certlists, ***certlistsp;
- int count;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- case SEC_OID_PKCS7_SIGNED_DATA:
- {
- SEC_PKCS7SignedData *sdp;
-
- sdp = cinfo->content.signedData;
- certlistsp = &(sdp->certLists);
- }
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saedp;
-
- saedp = cinfo->content.signedAndEnvelopedData;
- certlistsp = &(saedp->certLists);
- }
- break;
- default:
- return SECFailure; /* XXX set an error? */
- }
-
- if (certdb == NULL) {
- certdb = CERT_GetDefaultCertDB();
- if (certdb == NULL) {
- PORT_SetError (SEC_ERROR_BAD_DATABASE);
- return SECFailure;
- }
- }
-
- certlist = CERT_CertChainFromCert (cert, certUsageEmailSigner, PR_FALSE);
- if (certlist == NULL)
- return SECFailure;
-
- certlists = *certlistsp;
- if (certlists == NULL) {
- count = 0;
- certlists = (CERTCertificateList**)PORT_ArenaAlloc (cinfo->poolp,
- 2 * sizeof(CERTCertificateList *));
- } else {
- for (count = 0; certlists[count] != NULL; count++)
- ;
- PORT_Assert (count); /* should be at least one already */
- certlists = (CERTCertificateList**)PORT_ArenaGrow (cinfo->poolp,
- certlists,
- (count + 1) * sizeof(CERTCertificateList *),
- (count + 2) * sizeof(CERTCertificateList *));
- }
-
- if (certlists == NULL) {
- CERT_DestroyCertificateList (certlist);
- return SECFailure;
- }
-
- certlists[count] = certlist;
- certlists[count + 1] = NULL;
-
- *certlistsp = certlists;
-
- return SECSuccess;
-}
-
-
-/*
- * Helper function to add a certificate for inclusion in the bag of
- * certificates in a signedData.
- */
-static SECStatus
-sec_pkcs7_add_certificate (SEC_PKCS7ContentInfo *cinfo,
- CERTCertificate *cert)
-{
- SECOidTag kind;
- CERTCertificate **certs, ***certsp;
- int count;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- case SEC_OID_PKCS7_SIGNED_DATA:
- {
- SEC_PKCS7SignedData *sdp;
-
- sdp = cinfo->content.signedData;
- certsp = &(sdp->certs);
- }
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saedp;
-
- saedp = cinfo->content.signedAndEnvelopedData;
- certsp = &(saedp->certs);
- }
- break;
- default:
- return SECFailure; /* XXX set an error? */
- }
-
- cert = CERT_DupCertificate (cert);
- if (cert == NULL)
- return SECFailure;
-
- certs = *certsp;
- if (certs == NULL) {
- count = 0;
- certs = (CERTCertificate**)PORT_ArenaAlloc (cinfo->poolp,
- 2 * sizeof(CERTCertificate *));
- } else {
- for (count = 0; certs[count] != NULL; count++)
- ;
- PORT_Assert (count); /* should be at least one already */
- certs = (CERTCertificate**)PORT_ArenaGrow (cinfo->poolp, certs,
- (count + 1) * sizeof(CERTCertificate *),
- (count + 2) * sizeof(CERTCertificate *));
- }
-
- if (certs == NULL) {
- CERT_DestroyCertificate (cert);
- return SECFailure;
- }
-
- certs[count] = cert;
- certs[count + 1] = NULL;
-
- *certsp = certs;
-
- return SECSuccess;
-}
-
-
-/*
- * Create a PKCS7 certs-only container.
- *
- * "cert" is the (first) cert that will be included.
- *
- * "include_chain" specifies whether the entire chain for "cert" should
- * be included.
- *
- * "certdb" is the cert database to use for finding the chain.
- * It can be NULL in when "include_chain" is false, or when meaning
- * use the default database.
- *
- * More certs and chains can be added via AddCertificate and AddCertChain.
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-SEC_PKCS7ContentInfo *
-SEC_PKCS7CreateCertsOnly (CERTCertificate *cert,
- PRBool include_chain,
- CERTCertDBHandle *certdb)
-{
- SEC_PKCS7ContentInfo *cinfo;
- SECStatus rv;
-
- cinfo = sec_pkcs7_create_signed_data (NULL, NULL);
- if (cinfo == NULL)
- return NULL;
-
- if (include_chain)
- rv = sec_pkcs7_add_cert_chain (cinfo, cert, certdb);
- else
- rv = sec_pkcs7_add_certificate (cinfo, cert);
-
- if (rv != SECSuccess) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- return NULL;
- }
-
- return cinfo;
-}
-
-
-/*
- * Add "cert" and its entire chain to the set of certs included in "cinfo".
- *
- * "certdb" is the cert database to use for finding the chain.
- * It can be NULL, meaning use the default database.
- *
- * "cinfo" should be of type signedData or signedAndEnvelopedData;
- * SECFailure will be returned if it is not.
- */
-SECStatus
-SEC_PKCS7AddCertChain (SEC_PKCS7ContentInfo *cinfo,
- CERTCertificate *cert,
- CERTCertDBHandle *certdb)
-{
- SECOidTag kind;
-
- kind = SEC_PKCS7ContentType (cinfo);
- if (kind != SEC_OID_PKCS7_SIGNED_DATA
- && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA)
- return SECFailure; /* XXX set an error? */
-
- return sec_pkcs7_add_cert_chain (cinfo, cert, certdb);
-}
-
-
-/*
- * Add "cert" to the set of certs included in "cinfo".
- *
- * "cinfo" should be of type signedData or signedAndEnvelopedData;
- * SECFailure will be returned if it is not.
- */
-SECStatus
-SEC_PKCS7AddCertificate (SEC_PKCS7ContentInfo *cinfo, CERTCertificate *cert)
-{
- SECOidTag kind;
-
- kind = SEC_PKCS7ContentType (cinfo);
- if (kind != SEC_OID_PKCS7_SIGNED_DATA
- && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA)
- return SECFailure; /* XXX set an error? */
-
- return sec_pkcs7_add_certificate (cinfo, cert);
-}
-
-
-static SECStatus
-sec_pkcs7_init_encrypted_content_info (SEC_PKCS7EncryptedContentInfo *enccinfo,
- PRArenaPool *poolp,
- SECOidTag kind, PRBool detached,
- SECOidTag encalg, int keysize)
-{
- SECStatus rv;
-
- PORT_Assert (enccinfo != NULL && poolp != NULL);
- if (enccinfo == NULL || poolp == NULL)
- return SECFailure;
-
- /*
- * XXX Some day we may want to allow for other kinds. That needs
- * more work and modifications to the creation interface, etc.
- * For now, allow but notice callers who pass in other kinds.
- * They are responsible for creating the inner type and encoding,
- * if it is other than DATA.
- */
- PORT_Assert (kind == SEC_OID_PKCS7_DATA);
-
- enccinfo->contentTypeTag = SECOID_FindOIDByTag (kind);
- PORT_Assert (enccinfo->contentTypeTag
- && enccinfo->contentTypeTag->offset == kind);
-
- rv = SECITEM_CopyItem (poolp, &(enccinfo->contentType),
- &(enccinfo->contentTypeTag->oid));
- if (rv != SECSuccess)
- return rv;
-
- /* Save keysize and algorithm for later. */
- enccinfo->keysize = keysize;
- enccinfo->encalg = encalg;
-
- return SECSuccess;
-}
-
-
-/*
- * Add a recipient to a PKCS7 thing, verifying their cert first.
- * Any error returns SECFailure.
- */
-static SECStatus
-sec_pkcs7_add_recipient (SEC_PKCS7ContentInfo *cinfo,
- CERTCertificate *cert,
- SECCertUsage certusage,
- CERTCertDBHandle *certdb)
-{
- SECOidTag kind;
- SEC_PKCS7RecipientInfo *recipientinfo, **recipientinfos, ***recipientinfosp;
- SECItem *dummy;
- void *mark;
- int count;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- {
- SEC_PKCS7EnvelopedData *edp;
-
- edp = cinfo->content.envelopedData;
- recipientinfosp = &(edp->recipientInfos);
- }
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saedp;
-
- saedp = cinfo->content.signedAndEnvelopedData;
- recipientinfosp = &(saedp->recipientInfos);
- }
- break;
- default:
- return SECFailure; /* XXX set an error? */
- }
-
- /*
- * XXX I think that CERT_VerifyCert should do this if *it* is passed
- * a NULL database.
- */
- if (certdb == NULL) {
- certdb = CERT_GetDefaultCertDB();
- if (certdb == NULL)
- return SECFailure; /* XXX set an error? */
- }
-
- if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(),
- cinfo->pwfn_arg, NULL) != SECSuccess)
- {
- /* XXX Did CERT_VerifyCert set an error? */
- return SECFailure;
- }
-
- mark = PORT_ArenaMark (cinfo->poolp);
-
- recipientinfo = (SEC_PKCS7RecipientInfo*)PORT_ArenaZAlloc (cinfo->poolp,
- sizeof(SEC_PKCS7RecipientInfo));
- if (recipientinfo == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
-
- dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &recipientinfo->version,
- SEC_PKCS7_RECIPIENT_INFO_VERSION);
- if (dummy == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
- PORT_Assert (dummy == &recipientinfo->version);
-
- recipientinfo->cert = CERT_DupCertificate (cert);
- if (recipientinfo->cert == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
-
- recipientinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert);
- if (recipientinfo->issuerAndSN == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
-
- /*
- * Okay, now recipientinfo is all set. We just need to put it into
- * the main structure.
- *
- * If this is the first recipient, allocate a new recipientinfos array;
- * otherwise, reallocate the array, making room for the new entry.
- */
- recipientinfos = *recipientinfosp;
- if (recipientinfos == NULL) {
- count = 0;
- recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaAlloc (
- cinfo->poolp,
- 2 * sizeof(SEC_PKCS7RecipientInfo *));
- } else {
- for (count = 0; recipientinfos[count] != NULL; count++)
- ;
- PORT_Assert (count); /* should be at least one already */
- recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaGrow (
- cinfo->poolp, recipientinfos,
- (count + 1) * sizeof(SEC_PKCS7RecipientInfo *),
- (count + 2) * sizeof(SEC_PKCS7RecipientInfo *));
- }
-
- if (recipientinfos == NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- return SECFailure;
- }
-
- recipientinfos[count] = recipientinfo;
- recipientinfos[count + 1] = NULL;
-
- *recipientinfosp = recipientinfos;
-
- PORT_ArenaUnmark (cinfo->poolp, mark);
- return SECSuccess;
-}
-
-
-/*
- * Start a PKCS7 enveloping context.
- *
- * "cert" is the cert for the recipient. It will be checked for validity.
- *
- * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
- * XXX Maybe SECCertUsage should be split so that our caller just says
- * "email" and *we* add the "recipient" part -- otherwise our caller
- * could be lying about the usage; we do not want to allow encryption
- * certs for signing or vice versa.
- *
- * "certdb" is the cert database to use for verifying the cert.
- * It can be NULL if a default database is available (like in the client).
- *
- * "encalg" specifies the bulk encryption algorithm to use (e.g. SEC_OID_RC2).
- *
- * "keysize" specifies the bulk encryption key size, in bits.
- *
- * The return value can be passed to functions which add things to
- * it like more recipients, then eventually to SEC_PKCS7Encode() or to
- * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
- * SEC_PKCS7DestroyContentInfo().
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-extern SEC_PKCS7ContentInfo *
-SEC_PKCS7CreateEnvelopedData (CERTCertificate *cert,
- SECCertUsage certusage,
- CERTCertDBHandle *certdb,
- SECOidTag encalg,
- int keysize,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg)
-{
- SEC_PKCS7ContentInfo *cinfo;
- SEC_PKCS7EnvelopedData *envd;
- SECStatus rv;
-
- cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENVELOPED_DATA,
- PR_FALSE, pwfn, pwfn_arg);
- if (cinfo == NULL)
- return NULL;
-
- rv = sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);
- if (rv != SECSuccess) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- return NULL;
- }
-
- envd = cinfo->content.envelopedData;
- PORT_Assert (envd != NULL);
-
- /*
- * XXX Might we want to allow content types other than data?
- * If so, via what interface?
- */
- rv = sec_pkcs7_init_encrypted_content_info (&(envd->encContentInfo),
- cinfo->poolp,
- SEC_OID_PKCS7_DATA, PR_FALSE,
- encalg, keysize);
- if (rv != SECSuccess) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- return NULL;
- }
-
- /* XXX Anything more to do here? */
-
- return cinfo;
-}
-
-
-/*
- * Add another recipient to an encrypted message.
- *
- * "cinfo" should be of type envelopedData or signedAndEnvelopedData;
- * SECFailure will be returned if it is not.
- *
- * "cert" is the cert for the recipient. It will be checked for validity.
- *
- * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
- * XXX Maybe SECCertUsage should be split so that our caller just says
- * "email" and *we* add the "recipient" part -- otherwise our caller
- * could be lying about the usage; we do not want to allow encryption
- * certs for signing or vice versa.
- *
- * "certdb" is the cert database to use for verifying the cert.
- * It can be NULL if a default database is available (like in the client).
- */
-SECStatus
-SEC_PKCS7AddRecipient (SEC_PKCS7ContentInfo *cinfo,
- CERTCertificate *cert,
- SECCertUsage certusage,
- CERTCertDBHandle *certdb)
-{
- return sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);
-}
-
-
-/*
- * Create an empty PKCS7 data content info.
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-SEC_PKCS7ContentInfo *
-SEC_PKCS7CreateData (void)
-{
- return sec_pkcs7_create_content_info (SEC_OID_PKCS7_DATA, PR_FALSE,
- NULL, NULL);
-}
-
-
-/*
- * Create an empty PKCS7 encrypted content info.
- *
- * "algorithm" specifies the bulk encryption algorithm to use.
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-SEC_PKCS7ContentInfo *
-SEC_PKCS7CreateEncryptedData (SECOidTag algorithm, int keysize,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg)
-{
- SEC_PKCS7ContentInfo *cinfo;
- SECAlgorithmID *algid;
- SEC_PKCS7EncryptedData *enc_data;
- SECStatus rv;
-
- cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENCRYPTED_DATA,
- PR_FALSE, pwfn, pwfn_arg);
- if (cinfo == NULL)
- return NULL;
-
- enc_data = cinfo->content.encryptedData;
- algid = &(enc_data->encContentInfo.contentEncAlg);
-
- switch (algorithm) {
- case SEC_OID_RC2_CBC:
- case SEC_OID_DES_EDE3_CBC:
- case SEC_OID_DES_CBC:
- rv = SECOID_SetAlgorithmID (cinfo->poolp, algid, algorithm, NULL);
- break;
- default:
- {
- /*
- * Assume password-based-encryption. At least, try that.
- */
- SECAlgorithmID *pbe_algid;
- pbe_algid = PK11_CreatePBEAlgorithmID (algorithm, 1, NULL);
- if (pbe_algid == NULL) {
- rv = SECFailure;
- } else {
- rv = SECOID_CopyAlgorithmID (cinfo->poolp, algid, pbe_algid);
- SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
- }
- }
- break;
- }
-
- if (rv != SECSuccess) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- return NULL;
- }
-
- rv = sec_pkcs7_init_encrypted_content_info (&(enc_data->encContentInfo),
- cinfo->poolp,
- SEC_OID_PKCS7_DATA, PR_FALSE,
- algorithm, keysize);
- if (rv != SECSuccess) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- return NULL;
- }
-
- return cinfo;
-}
-
diff --git a/security/nss/lib/pkcs7/p7decode.c b/security/nss/lib/pkcs7/p7decode.c
deleted file mode 100644
index 0eee743c2..000000000
--- a/security/nss/lib/pkcs7/p7decode.c
+++ /dev/null
@@ -1,2087 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * PKCS7 decoding, verification.
- *
- * $Id$
- */
-
-#include "p7local.h"
-
-#include "cert.h"
- /* XXX do not want to have to include */
-#include "certdb.h" /* certdb.h -- the trust stuff needed by */
- /* the add certificate code needs to get */
- /* rewritten/abstracted and then this */
- /* include should be removed! */
-#include "cdbhdl.h"
-#include "cryptohi.h"
-#include "key.h"
-#include "secasn1.h"
-#include "secitem.h"
-#include "secoid.h"
-#include "pk11func.h"
-#include "prtime.h"
-#include "secerr.h"
-
-
-struct sec_pkcs7_decoder_worker {
- int depth;
- int digcnt;
- void **digcxs;
- SECHashObject **digobjs;
- sec_PKCS7CipherObject *decryptobj;
- PRBool saw_contents;
-};
-
-struct SEC_PKCS7DecoderContextStr {
- SEC_ASN1DecoderContext *dcx;
- SEC_PKCS7ContentInfo *cinfo;
- SEC_PKCS7DecoderContentCallback cb;
- void *cb_arg;
- SECKEYGetPasswordKey pwfn;
- void *pwfn_arg;
- struct sec_pkcs7_decoder_worker worker;
- PRArenaPool *tmp_poolp;
- int error;
- SEC_PKCS7GetDecryptKeyCallback dkcb;
- void *dkcb_arg;
- SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb;
-};
-
-/*
- * Handle one worker, decrypting and digesting the data as necessary.
- *
- * XXX If/when we support nested contents, this probably needs to be
- * revised somewhat to get passed the content-info (which unfortunately
- * can be two different types depending on whether it is encrypted or not)
- * corresponding to the given worker.
- */
-static void
-sec_pkcs7_decoder_work_data (SEC_PKCS7DecoderContext *p7dcx,
- struct sec_pkcs7_decoder_worker *worker,
- const unsigned char *data, unsigned long len,
- PRBool final)
-{
- unsigned char *buf = NULL;
- SECStatus rv;
- int i;
-
- /*
- * We should really have data to process, or we should be trying
- * to finish/flush the last block. (This is an overly paranoid
- * check since all callers are in this file and simple inspection
- * proves they do it right. But it could find a bug in future
- * modifications/development, that is why it is here.)
- */
- PORT_Assert ((data != NULL && len) || final);
-
- /*
- * Decrypt this chunk.
- *
- * XXX If we get an error, we do not want to do the digest or callback,
- * but we want to keep decoding. Or maybe we want to stop decoding
- * altogether if there is a callback, because obviously we are not
- * sending the data back and they want to know that.
- */
- if (worker->decryptobj != NULL) {
- /* XXX the following lengths should all be longs? */
- unsigned int inlen; /* length of data being decrypted */
- unsigned int outlen; /* length of decrypted data */
- unsigned int buflen; /* length available for decrypted data */
- SECItem *plain;
-
- inlen = len;
- buflen = sec_PKCS7DecryptLength (worker->decryptobj, inlen, final);
- if (buflen == 0) {
- if (inlen == 0) /* no input and no output */
- return;
- /*
- * No output is expected, but the input data may be buffered
- * so we still have to call Decrypt.
- */
- rv = sec_PKCS7Decrypt (worker->decryptobj, NULL, NULL, 0,
- data, inlen, final);
- if (rv != SECSuccess) {
- p7dcx->error = PORT_GetError();
- return; /* XXX indicate error? */
- }
- return;
- }
-
- if (p7dcx->cb != NULL) {
- buf = (unsigned char *) PORT_Alloc (buflen);
- plain = NULL;
- } else {
- unsigned long oldlen;
-
- /*
- * XXX This assumes one level of content only.
- * See comment above about nested content types.
- * XXX Also, it should work for signedAndEnvelopedData, too!
- */
- plain = &(p7dcx->cinfo->
- content.envelopedData->encContentInfo.plainContent);
-
- oldlen = plain->len;
- if (oldlen == 0) {
- buf = (unsigned char*)PORT_ArenaAlloc (p7dcx->cinfo->poolp,
- buflen);
- } else {
- buf = (unsigned char*)PORT_ArenaGrow (p7dcx->cinfo->poolp,
- plain->data,
- oldlen, oldlen + buflen);
- if (buf != NULL)
- buf += oldlen;
- }
- plain->data = buf;
- }
- if (buf == NULL) {
- p7dcx->error = SEC_ERROR_NO_MEMORY;
- return; /* XXX indicate error? */
- }
- rv = sec_PKCS7Decrypt (worker->decryptobj, buf, &outlen, buflen,
- data, inlen, final);
- if (rv != SECSuccess) {
- p7dcx->error = PORT_GetError();
- return; /* XXX indicate error? */
- }
- if (plain != NULL) {
- PORT_Assert (final || outlen == buflen);
- plain->len += outlen;
- }
- data = buf;
- len = outlen;
- }
-
- /*
- * Update the running digests.
- */
- if (len) {
- for (i = 0; i < worker->digcnt; i++) {
- (* worker->digobjs[i]->update) (worker->digcxs[i], data, len);
- }
- }
-
- /*
- * Pass back the contents bytes, and free the temporary buffer.
- */
- if (p7dcx->cb != NULL) {
- if (len)
- (* p7dcx->cb) (p7dcx->cb_arg, (const char *)data, len);
- if (worker->decryptobj != NULL) {
- PORT_Assert (buf != NULL);
- PORT_Free (buf);
- }
- }
-}
-
-static void
-sec_pkcs7_decoder_filter (void *arg, const char *data, unsigned long len,
- int depth, SEC_ASN1EncodingPart data_kind)
-{
- SEC_PKCS7DecoderContext *p7dcx;
- struct sec_pkcs7_decoder_worker *worker;
-
- /*
- * Since we do not handle any nested contents, the only bytes we
- * are really interested in are the actual contents bytes (not
- * the identifier, length, or end-of-contents bytes). If we were
- * handling nested types we would probably need to do something
- * smarter based on depth and data_kind.
- */
- if (data_kind != SEC_ASN1_Contents)
- return;
-
- /*
- * The ASN.1 decoder should not even call us with a length of 0.
- * Just being paranoid.
- */
- PORT_Assert (len);
- if (len == 0)
- return;
-
- p7dcx = (SEC_PKCS7DecoderContext*)arg;
-
- /*
- * Handling nested contents would mean that there is a chain
- * of workers -- one per each level of content. The following
- * would start with the first worker and loop over them.
- */
- worker = &(p7dcx->worker);
-
- worker->saw_contents = PR_TRUE;
-
- sec_pkcs7_decoder_work_data (p7dcx, worker,
- (const unsigned char *) data, len, PR_FALSE);
-}
-
-
-/*
- * Create digest contexts for each algorithm in "digestalgs".
- * No algorithms is not an error, we just do not do anything.
- * An error (like trouble allocating memory), marks the error
- * in "p7dcx" and returns SECFailure, which means that our caller
- * should just give up altogether.
- */
-static SECStatus
-sec_pkcs7_decoder_start_digests (SEC_PKCS7DecoderContext *p7dcx, int depth,
- SECAlgorithmID **digestalgs)
-{
- SECAlgorithmID *algid;
- SECOidData *oiddata;
- SECHashObject *digobj;
- void *digcx;
- int i, digcnt;
-
- if (digestalgs == NULL)
- return SECSuccess;
-
- /*
- * Count the algorithms.
- */
- digcnt = 0;
- while (digestalgs[digcnt] != NULL)
- digcnt++;
-
- /*
- * No algorithms means no work to do.
- * This is not expected, so cause an assert.
- * But if it does happen, just act as if there were
- * no algorithms specified.
- */
- PORT_Assert (digcnt != 0);
- if (digcnt == 0)
- return SECSuccess;
-
- p7dcx->worker.digcxs = (void**)PORT_ArenaAlloc (p7dcx->tmp_poolp,
- digcnt * sizeof (void *));
- p7dcx->worker.digobjs = (SECHashObject**)PORT_ArenaAlloc (p7dcx->tmp_poolp,
- digcnt * sizeof (SECHashObject *));
- if (p7dcx->worker.digcxs == NULL || p7dcx->worker.digobjs == NULL) {
- p7dcx->error = SEC_ERROR_NO_MEMORY;
- return SECFailure;
- }
-
- p7dcx->worker.depth = depth;
- p7dcx->worker.digcnt = 0;
-
- /*
- * Create a digest context for each algorithm.
- */
- for (i = 0; i < digcnt; i++) {
- algid = digestalgs[i];
- oiddata = SECOID_FindOID(&(algid->algorithm));
- if (oiddata == NULL) {
- digobj = NULL;
- } else {
- switch (oiddata->offset) {
- case SEC_OID_MD2:
- digobj = &SECHashObjects[HASH_AlgMD2];
- break;
- case SEC_OID_MD5:
- digobj = &SECHashObjects[HASH_AlgMD5];
- break;
- case SEC_OID_SHA1:
- digobj = &SECHashObjects[HASH_AlgSHA1];
- break;
- default:
- digobj = NULL;
- break;
- }
- }
-
- /*
- * Skip any algorithm we do not even recognize; obviously,
- * this could be a problem, but if it is critical then the
- * result will just be that the signature does not verify.
- * We do not necessarily want to error out here, because
- * the particular algorithm may not actually be important,
- * but we cannot know that until later.
- */
- if (digobj == NULL) {
- p7dcx->worker.digcnt--;
- continue;
- }
-
- digcx = (* digobj->create)();
- if (digcx != NULL) {
- (* digobj->begin) (digcx);
- p7dcx->worker.digobjs[p7dcx->worker.digcnt] = digobj;
- p7dcx->worker.digcxs[p7dcx->worker.digcnt] = digcx;
- p7dcx->worker.digcnt++;
- }
- }
-
- if (p7dcx->worker.digcnt != 0)
- SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
- sec_pkcs7_decoder_filter,
- p7dcx,
- (PRBool)(p7dcx->cb != NULL));
- return SECSuccess;
-}
-
-
-/*
- * Close out all of the digest contexts, storing the results in "digestsp".
- */
-static SECStatus
-sec_pkcs7_decoder_finish_digests (SEC_PKCS7DecoderContext *p7dcx,
- PRArenaPool *poolp,
- SECItem ***digestsp)
-{
- struct sec_pkcs7_decoder_worker *worker;
- SECHashObject *digobj;
- void *digcx;
- SECItem **digests, *digest;
- int i;
- void *mark;
-
- /*
- * XXX Handling nested contents would mean that there is a chain
- * of workers -- one per each level of content. The following
- * would want to find the last worker in the chain.
- */
- worker = &(p7dcx->worker);
-
- /*
- * If no digests, then we have nothing to do.
- */
- if (worker->digcnt == 0)
- return SECSuccess;
-
- /*
- * No matter what happens after this, we want to stop filtering.
- * XXX If we handle nested contents, we only want to stop filtering
- * if we are finishing off the *last* worker.
- */
- SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
-
- /*
- * If we ended up with no contents, just destroy each
- * digest context -- they are meaningless and potentially
- * confusing, because their presence would imply some content
- * was digested.
- */
- if (! worker->saw_contents) {
- for (i = 0; i < worker->digcnt; i++) {
- digcx = worker->digcxs[i];
- digobj = worker->digobjs[i];
- (* digobj->destroy) (digcx, PR_TRUE);
- }
- return SECSuccess;
- }
-
- mark = PORT_ArenaMark (poolp);
-
- /*
- * Close out each digest context, saving digest away.
- */
- digests =
- (SECItem**)PORT_ArenaAlloc (poolp,(worker->digcnt+1)*sizeof(SECItem *));
- digest = (SECItem*)PORT_ArenaAlloc (poolp, worker->digcnt*sizeof(SECItem));
- if (digests == NULL || digest == NULL) {
- p7dcx->error = PORT_GetError();
- PORT_ArenaRelease (poolp, mark);
- return SECFailure;
- }
-
- for (i = 0; i < worker->digcnt; i++, digest++) {
- digcx = worker->digcxs[i];
- digobj = worker->digobjs[i];
-
- digest->data = (unsigned char*)PORT_ArenaAlloc (poolp, digobj->length);
- if (digest->data == NULL) {
- p7dcx->error = PORT_GetError();
- PORT_ArenaRelease (poolp, mark);
- return SECFailure;
- }
-
- digest->len = digobj->length;
- (* digobj->end) (digcx, digest->data, &(digest->len), digest->len);
- (* digobj->destroy) (digcx, PR_TRUE);
-
- digests[i] = digest;
- }
- digests[i] = NULL;
- *digestsp = digests;
-
- PORT_ArenaUnmark (poolp, mark);
- return SECSuccess;
-}
-
-/*
- * XXX Need comment explaining following helper function (which is used
- * by sec_pkcs7_decoder_start_decrypt).
- */
-extern const SEC_ASN1Template SEC_SMIMEKEAParamTemplateAllParams[];
-
-static PK11SymKey *
-sec_pkcs7_decoder_get_recipient_key (SEC_PKCS7DecoderContext *p7dcx,
- SEC_PKCS7RecipientInfo **recipientinfos,
- SEC_PKCS7EncryptedContentInfo *enccinfo)
-{
- SEC_PKCS7RecipientInfo *ri;
- CERTCertificate *cert = NULL;
- SECKEYPrivateKey *privkey = NULL;
- PK11SymKey *bulkkey;
- SECOidTag keyalgtag, bulkalgtag, encalgtag;
- PK11SlotInfo *slot;
- int i, bulkLength = 0;
-
- if (recipientinfos == NULL || recipientinfos[0] == NULL) {
- p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
- goto no_key_found;
- }
-
- cert = PK11_FindCertAndKeyByRecipientList(&slot,recipientinfos,&ri,
- &privkey, p7dcx->pwfn_arg);
- if (cert == NULL) {
- p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
- goto no_key_found;
- }
-
- ri->cert = cert; /* so we can find it later */
- PORT_Assert(privkey != NULL);
-
- keyalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
- encalgtag = SECOID_GetAlgorithmTag (&(ri->keyEncAlg));
- if ((encalgtag != SEC_OID_NETSCAPE_SMIME_KEA) && (keyalgtag != encalgtag)) {
- p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH;
- goto no_key_found;
- }
- bulkalgtag = SECOID_GetAlgorithmTag (&(enccinfo->contentEncAlg));
-
- switch (encalgtag) {
- case SEC_OID_PKCS1_RSA_ENCRYPTION:
- bulkkey = PK11_PubUnwrapSymKey (privkey, &ri->encKey,
- PK11_AlgtagToMechanism (bulkalgtag),
- CKA_DECRYPT, 0);
- if (bulkkey == NULL) {
- p7dcx->error = PORT_GetError();
- PORT_SetError(0);
- goto no_key_found;
- }
- break;
- /* ### mwelch -- KEA */
- case SEC_OID_NETSCAPE_SMIME_KEA:
- {
- SECStatus err;
- CK_MECHANISM_TYPE bulkType;
- PK11SymKey *tek;
- SECKEYPublicKey *senderPubKey;
- SEC_PKCS7SMIMEKEAParameters keaParams;
-
- (void) memset(&keaParams, 0, sizeof(keaParams));
-
- /* Decode the KEA algorithm parameters. */
- err = SEC_ASN1DecodeItem(NULL,
- &keaParams,
- SEC_SMIMEKEAParamTemplateAllParams,
- &(ri->keyEncAlg.parameters));
- if (err != SECSuccess)
- {
- p7dcx->error = err;
- PORT_SetError(0);
- goto no_key_found;
- }
-
-
- /* We just got key data, no key structure. So, we
- create one. */
- senderPubKey =
- PK11_MakeKEAPubKey(keaParams.originatorKEAKey.data,
- keaParams.originatorKEAKey.len);
- if (senderPubKey == NULL)
- {
- p7dcx->error = PORT_GetError();
- PORT_SetError(0);
- goto no_key_found;
- }
-
- /* Generate the TEK (token exchange key) which we use
- to unwrap the bulk encryption key. */
- tek = PK11_PubDerive(privkey, senderPubKey,
- PR_FALSE,
- &keaParams.originatorRA,
- NULL,
- CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
- CKA_WRAP, 0, p7dcx->pwfn_arg);
- SECKEY_DestroyPublicKey(senderPubKey);
-
- if (tek == NULL)
- {
- p7dcx->error = PORT_GetError();
- PORT_SetError(0);
- goto no_key_found;
- }
-
- /* Now that we have the TEK, unwrap the bulk key
- with which to decrypt the message. We have to
- do one of two different things depending on
- whether Skipjack was used for bulk encryption
- of the message. */
- bulkType = PK11_AlgtagToMechanism (bulkalgtag);
- switch(bulkType)
- {
- case CKM_SKIPJACK_CBC64:
- case CKM_SKIPJACK_ECB64:
- case CKM_SKIPJACK_OFB64:
- case CKM_SKIPJACK_CFB64:
- case CKM_SKIPJACK_CFB32:
- case CKM_SKIPJACK_CFB16:
- case CKM_SKIPJACK_CFB8:
- /* Skipjack is being used as the bulk encryption algorithm.*/
- /* Unwrap the bulk key. */
- bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP,
- NULL, &ri->encKey,
- CKM_SKIPJACK_CBC64,
- CKA_DECRYPT, 0);
- break;
- default:
- /* Skipjack was not used for bulk encryption of this
- message. Use Skipjack CBC64, with the nonSkipjackIV
- part of the KEA key parameters, to decrypt
- the bulk key. If we got a parameter indicating that the
- bulk key size is different than the encrypted key size,
- pass in the real key size. */
-
- /* Check for specified bulk key length (unspecified implies
- that the bulk key length is the same as encrypted length) */
- if (keaParams.bulkKeySize.len > 0)
- {
- p7dcx->error = SEC_ASN1DecodeItem(NULL, &bulkLength,
- SEC_IntegerTemplate,
- &keaParams.bulkKeySize);
- }
-
- if (p7dcx->error != SECSuccess)
- goto no_key_found;
-
- bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_CBC64,
- &keaParams.nonSkipjackIV,
- &ri->encKey,
- bulkType,
- CKA_DECRYPT, bulkLength);
- }
-
-
- if (bulkkey == NULL)
- {
- p7dcx->error = PORT_GetError();
- PORT_SetError(0);
- goto no_key_found;
- }
- break;
- }
- default:
- p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG;
- goto no_key_found;
- }
-
- return bulkkey;
-
-no_key_found:
- if (privkey != NULL)
- SECKEY_DestroyPrivateKey (privkey);
-
- return NULL;
-}
-
-/*
- * XXX The following comment is old -- the function used to only handle
- * EnvelopedData or SignedAndEnvelopedData but now handles EncryptedData
- * as well (and it had all of the code of the helper function above
- * built into it), though the comment was left as is. Fix it...
- *
- * We are just about to decode the content of an EnvelopedData.
- * Set up a decryption context so we can decrypt as we go.
- * Presumably we are one of the recipients listed in "recipientinfos".
- * (XXX And if we are not, or if we have trouble, what should we do?
- * It would be nice to let the decoding still work. Maybe it should
- * be an error if there is a content callback, but not an error otherwise?)
- * The encryption key and related information can be found in "enccinfo".
- */
-static SECStatus
-sec_pkcs7_decoder_start_decrypt (SEC_PKCS7DecoderContext *p7dcx, int depth,
- SEC_PKCS7RecipientInfo **recipientinfos,
- SEC_PKCS7EncryptedContentInfo *enccinfo,
- PK11SymKey **copy_key_for_signature)
-{
- PK11SymKey *bulkkey = NULL;
- sec_PKCS7CipherObject *decryptobj;
-
- /*
- * If a callback is supplied to retrieve the encryption key,
- * for instance, for Encrypted Content infos, then retrieve
- * the bulkkey from the callback. Otherwise, assume that
- * we are processing Enveloped or SignedAndEnveloped data
- * content infos.
- *
- * XXX Put an assert here?
- */
- if (SEC_PKCS7ContentType(p7dcx->cinfo) == SEC_OID_PKCS7_ENCRYPTED_DATA) {
- if (p7dcx->dkcb != NULL) {
- bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg,
- &(enccinfo->contentEncAlg));
- }
- enccinfo->keysize = 0;
- } else {
- bulkkey = sec_pkcs7_decoder_get_recipient_key (p7dcx, recipientinfos,
- enccinfo);
- if (bulkkey == NULL) goto no_decryption;
- enccinfo->keysize = PK11_GetKeyStrength(bulkkey,
- &(enccinfo->contentEncAlg));
-
- }
-
- /*
- * XXX I think following should set error in p7dcx and clear set error
- * (as used to be done here, or as is done in get_receipient_key above.
- */
- if(bulkkey == NULL) {
- goto no_decryption;
- }
-
- /*
- * We want to make sure decryption is allowed. This is done via
- * a callback specified in SEC_PKCS7DecoderStart().
- */
- if (p7dcx->decrypt_allowed_cb) {
- if ((*p7dcx->decrypt_allowed_cb) (&(enccinfo->contentEncAlg),
- bulkkey) == PR_FALSE) {
- p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
- goto no_decryption;
- }
- } else {
- p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
- goto no_decryption;
- }
-
- /*
- * When decrypting a signedAndEnvelopedData, the signature also has
- * to be decrypted with the bulk encryption key; to avoid having to
- * get it all over again later (and do another potentially expensive
- * RSA operation), copy it for later signature verification to use.
- */
- if (copy_key_for_signature != NULL)
- *copy_key_for_signature = PK11_ReferenceSymKey (bulkkey);
-
- /*
- * Now we have the bulk encryption key (in bulkkey) and the
- * the algorithm (in enccinfo->contentEncAlg). Using those,
- * create a decryption context.
- */
- decryptobj = sec_PKCS7CreateDecryptObject (bulkkey,
- &(enccinfo->contentEncAlg));
-
- /*
- * For PKCS5 Encryption Algorithms, the bulkkey is actually a different
- * structure. Therefore, we need to set the bulkkey to the actual key
- * prior to freeing it.
- */
- if ( SEC_PKCS5IsAlgorithmPBEAlg(&(enccinfo->contentEncAlg)) && bulkkey ) {
- SEC_PKCS5KeyAndPassword *keyPwd = (SEC_PKCS5KeyAndPassword *)bulkkey;
- bulkkey = keyPwd->key;
- }
-
- /*
- * We are done with (this) bulkkey now.
- */
- PK11_FreeSymKey (bulkkey);
-
- if (decryptobj == NULL) {
- p7dcx->error = PORT_GetError();
- PORT_SetError(0);
- goto no_decryption;
- }
-
- SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
- sec_pkcs7_decoder_filter,
- p7dcx,
- (PRBool)(p7dcx->cb != NULL));
-
- p7dcx->worker.depth = depth;
- p7dcx->worker.decryptobj = decryptobj;
-
- return SECSuccess;
-
-no_decryption:
- /*
- * For some reason (error set already, if appropriate), we cannot
- * decrypt the content. I am not sure what exactly is the right
- * thing to do here; in some cases we want to just stop, and in
- * others we want to let the decoding finish even though we cannot
- * decrypt the content. My current thinking is that if the caller
- * set up a content callback, then they are really interested in
- * getting (decrypted) content, and if they cannot they will want
- * to know about it. However, if no callback was specified, then
- * maybe it is not important that the decryption failed.
- */
- if (p7dcx->cb != NULL)
- return SECFailure;
- else
- return SECSuccess; /* Let the decoding continue. */
-}
-
-
-static SECStatus
-sec_pkcs7_decoder_finish_decrypt (SEC_PKCS7DecoderContext *p7dcx,
- PRArenaPool *poolp,
- SEC_PKCS7EncryptedContentInfo *enccinfo)
-{
- struct sec_pkcs7_decoder_worker *worker;
-
- /*
- * XXX Handling nested contents would mean that there is a chain
- * of workers -- one per each level of content. The following
- * would want to find the last worker in the chain.
- */
- worker = &(p7dcx->worker);
-
- /*
- * If no decryption context, then we have nothing to do.
- */
- if (worker->decryptobj == NULL)
- return SECSuccess;
-
- /*
- * No matter what happens after this, we want to stop filtering.
- * XXX If we handle nested contents, we only want to stop filtering
- * if we are finishing off the *last* worker.
- */
- SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
-
- /*
- * Handle the last block.
- */
- sec_pkcs7_decoder_work_data (p7dcx, worker, NULL, 0, PR_TRUE);
-
- /*
- * All done, destroy it.
- */
- sec_PKCS7DestroyDecryptObject (worker->decryptobj);
-
- return SECSuccess;
-}
-
-
-static void
-sec_pkcs7_decoder_notify (void *arg, PRBool before, void *dest, int depth)
-{
- SEC_PKCS7DecoderContext *p7dcx;
- SEC_PKCS7ContentInfo *cinfo;
- SEC_PKCS7SignedData *sigd;
- SEC_PKCS7EnvelopedData *envd;
- SEC_PKCS7SignedAndEnvelopedData *saed;
- SEC_PKCS7EncryptedData *encd;
- SEC_PKCS7DigestedData *digd;
- PRBool after;
- SECStatus rv;
-
- /*
- * Just to make the code easier to read, create an "after" variable
- * that is equivalent to "not before".
- * (This used to be just the statement "after = !before", but that
- * causes a warning on the mac; to avoid that, we do it the long way.)
- */
- if (before)
- after = PR_FALSE;
- else
- after = PR_TRUE;
-
- p7dcx = (SEC_PKCS7DecoderContext*)arg;
- cinfo = p7dcx->cinfo;
-
- if (cinfo->contentTypeTag == NULL) {
- if (after && dest == &(cinfo->contentType))
- cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
- return;
- }
-
- switch (cinfo->contentTypeTag->offset) {
- case SEC_OID_PKCS7_SIGNED_DATA:
- sigd = cinfo->content.signedData;
- if (sigd == NULL)
- break;
-
- if (sigd->contentInfo.contentTypeTag == NULL) {
- if (after && dest == &(sigd->contentInfo.contentType))
- sigd->contentInfo.contentTypeTag =
- SECOID_FindOID(&(sigd->contentInfo.contentType));
- break;
- }
-
- /*
- * We only set up a filtering digest if the content is
- * plain DATA; anything else needs more work because a
- * second pass is required to produce a DER encoding from
- * an input that can be BER encoded. (This is a requirement
- * of PKCS7 that is unfortunate, but there you have it.)
- *
- * XXX Also, since we stop here if this is not DATA, the
- * inner content is not getting processed at all. Someday
- * we may want to fix that.
- */
- if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) {
- /* XXX Set an error in p7dcx->error */
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
- break;
- }
-
- /*
- * Just before the content, we want to set up a digest context
- * for each digest algorithm listed, and start a filter which
- * will run all of the contents bytes through that digest.
- */
- if (before && dest == &(sigd->contentInfo.content)) {
- rv = sec_pkcs7_decoder_start_digests (p7dcx, depth,
- sigd->digestAlgorithms);
- if (rv != SECSuccess)
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
-
- break;
- }
-
- /*
- * XXX To handle nested types, here is where we would want
- * to check for inner boundaries that need handling.
- */
-
- /*
- * Are we done?
- */
- if (after && dest == &(sigd->contentInfo.content)) {
- /*
- * Close out the digest contexts. We ignore any error
- * because we are stopping anyway; the error status left
- * behind in p7dcx will be seen by outer functions.
- */
- (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp,
- &(sigd->digests));
-
- /*
- * XXX To handle nested contents, we would need to remove
- * the worker from the chain (and free it).
- */
-
- /*
- * Stop notify.
- */
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
- }
- break;
-
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- envd = cinfo->content.envelopedData;
- if (envd == NULL)
- break;
-
- if (envd->encContentInfo.contentTypeTag == NULL) {
- if (after && dest == &(envd->encContentInfo.contentType))
- envd->encContentInfo.contentTypeTag =
- SECOID_FindOID(&(envd->encContentInfo.contentType));
- break;
- }
-
- /*
- * Just before the content, we want to set up a decryption
- * context, and start a filter which will run all of the
- * contents bytes through it to determine the plain content.
- */
- if (before && dest == &(envd->encContentInfo.encContent)) {
- rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth,
- envd->recipientInfos,
- &(envd->encContentInfo),
- NULL);
- if (rv != SECSuccess)
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
-
- break;
- }
-
- /*
- * Are we done?
- */
- if (after && dest == &(envd->encContentInfo.encContent)) {
- /*
- * Close out the decryption context. We ignore any error
- * because we are stopping anyway; the error status left
- * behind in p7dcx will be seen by outer functions.
- */
- (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
- &(envd->encContentInfo));
-
- /*
- * XXX To handle nested contents, we would need to remove
- * the worker from the chain (and free it).
- */
-
- /*
- * Stop notify.
- */
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
- }
- break;
-
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- saed = cinfo->content.signedAndEnvelopedData;
- if (saed == NULL)
- break;
-
- if (saed->encContentInfo.contentTypeTag == NULL) {
- if (after && dest == &(saed->encContentInfo.contentType))
- saed->encContentInfo.contentTypeTag =
- SECOID_FindOID(&(saed->encContentInfo.contentType));
- break;
- }
-
- /*
- * Just before the content, we want to set up a decryption
- * context *and* digest contexts, and start a filter which
- * will run all of the contents bytes through both.
- */
- if (before && dest == &(saed->encContentInfo.encContent)) {
- rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth,
- saed->recipientInfos,
- &(saed->encContentInfo),
- &(saed->sigKey));
- if (rv == SECSuccess)
- rv = sec_pkcs7_decoder_start_digests (p7dcx, depth,
- saed->digestAlgorithms);
- if (rv != SECSuccess)
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
-
- break;
- }
-
- /*
- * Are we done?
- */
- if (after && dest == &(saed->encContentInfo.encContent)) {
- /*
- * Close out the decryption and digests contexts.
- * We ignore any errors because we are stopping anyway;
- * the error status left behind in p7dcx will be seen by
- * outer functions.
- *
- * Note that the decrypt stuff must be called first;
- * it may have a last buffer to do which in turn has
- * to be added to the digest.
- */
- (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
- &(saed->encContentInfo));
- (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp,
- &(saed->digests));
-
- /*
- * XXX To handle nested contents, we would need to remove
- * the worker from the chain (and free it).
- */
-
- /*
- * Stop notify.
- */
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
- }
- break;
-
- case SEC_OID_PKCS7_DIGESTED_DATA:
- digd = cinfo->content.digestedData;
-
- /*
- * XXX Want to do the digest or not? Maybe future enhancement...
- */
- if (before && dest == &(digd->contentInfo.content.data)) {
- SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, sec_pkcs7_decoder_filter,
- p7dcx,
- (PRBool)(p7dcx->cb != NULL));
- break;
- }
-
- /*
- * Are we done?
- */
- if (after && dest == &(digd->contentInfo.content.data)) {
- SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
- }
- break;
-
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- encd = cinfo->content.encryptedData;
-
- /*
- * XXX If the decryption key callback is set, we want to start
- * the decryption. If the callback is not set, we will treat the
- * content as plain data, since we do not have the key.
- *
- * Is this the proper thing to do?
- */
- if (before && dest == &(encd->encContentInfo.encContent)) {
- /*
- * Start the encryption process if the decryption key callback
- * is present. Otherwise, treat the content like plain data.
- */
- rv = SECSuccess;
- if (p7dcx->dkcb != NULL) {
- rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, NULL,
- &(encd->encContentInfo),
- NULL);
- }
-
- if (rv != SECSuccess)
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
-
- break;
- }
-
- /*
- * Are we done?
- */
- if (after && dest == &(encd->encContentInfo.encContent)) {
- /*
- * Close out the decryption context. We ignore any error
- * because we are stopping anyway; the error status left
- * behind in p7dcx will be seen by outer functions.
- */
- (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
- &(encd->encContentInfo));
-
- /*
- * Stop notify.
- */
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
- }
- break;
-
- case SEC_OID_PKCS7_DATA:
- /*
- * If a output callback has been specified, we want to set the filter
- * to call the callback. This is taken care of in
- * sec_pkcs7_decoder_start_decrypt() or
- * sec_pkcs7_decoder_start_digests() for the other content types.
- */
-
- if (before && dest == &(cinfo->content.data)) {
-
- /*
- * Set the filter proc up.
- */
- SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
- sec_pkcs7_decoder_filter,
- p7dcx,
- (PRBool)(p7dcx->cb != NULL));
- break;
- }
-
- if (after && dest == &(cinfo->content.data)) {
- /*
- * Time to clean up after ourself, stop the Notify and Filter
- * procedures.
- */
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
- SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
- }
- break;
-
- default:
- SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
- break;
- }
-}
-
-
-SEC_PKCS7DecoderContext *
-SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg,
- SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
- void *decrypt_key_cb_arg,
- SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
-{
- SEC_PKCS7DecoderContext *p7dcx;
- SEC_ASN1DecoderContext *dcx;
- SEC_PKCS7ContentInfo *cinfo;
- PRArenaPool *poolp;
-
- poolp = PORT_NewArena (1024); /* XXX what is right value? */
- if (poolp == NULL)
- return NULL;
-
- cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo));
- if (cinfo == NULL) {
- PORT_FreeArena (poolp, PR_FALSE);
- return NULL;
- }
-
- cinfo->poolp = poolp;
- cinfo->pwfn = pwfn;
- cinfo->pwfn_arg = pwfn_arg;
- cinfo->created = PR_FALSE;
- cinfo->refCount = 1;
-
- p7dcx =
- (SEC_PKCS7DecoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7DecoderContext));
- if (p7dcx == NULL) {
- PORT_FreeArena (poolp, PR_FALSE);
- return NULL;
- }
-
- p7dcx->tmp_poolp = PORT_NewArena (1024); /* XXX what is right value? */
- if (p7dcx->tmp_poolp == NULL) {
- PORT_Free (p7dcx);
- PORT_FreeArena (poolp, PR_FALSE);
- return NULL;
- }
-
- dcx = SEC_ASN1DecoderStart (poolp, cinfo, sec_PKCS7ContentInfoTemplate);
- if (dcx == NULL) {
- PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE);
- PORT_Free (p7dcx);
- PORT_FreeArena (poolp, PR_FALSE);
- return NULL;
- }
-
- SEC_ASN1DecoderSetNotifyProc (dcx, sec_pkcs7_decoder_notify, p7dcx);
-
- p7dcx->dcx = dcx;
- p7dcx->cinfo = cinfo;
- p7dcx->cb = cb;
- p7dcx->cb_arg = cb_arg;
- p7dcx->pwfn = pwfn;
- p7dcx->pwfn_arg = pwfn_arg;
- p7dcx->dkcb = decrypt_key_cb;
- p7dcx->dkcb_arg = decrypt_key_cb_arg;
- p7dcx->decrypt_allowed_cb = decrypt_allowed_cb;
-
- return p7dcx;
-}
-
-
-/*
- * Do the next chunk of PKCS7 decoding. If there is a problem, set
- * an error and return a failure status. Note that in the case of
- * an error, this routine is still prepared to be called again and
- * again in case that is the easiest route for our caller to take.
- * We simply detect it and do not do anything except keep setting
- * that error in case our caller has not noticed it yet...
- */
-SECStatus
-SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
- const char *buf, unsigned long len)
-{
- if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) {
- PORT_Assert (p7dcx->error == 0);
- if (p7dcx->error == 0) {
- if (SEC_ASN1DecoderUpdate (p7dcx->dcx, buf, len) != SECSuccess) {
- p7dcx->error = PORT_GetError();
- PORT_Assert (p7dcx->error);
- if (p7dcx->error == 0)
- p7dcx->error = -1;
- }
- }
- }
-
- if (p7dcx->error) {
- if (p7dcx->dcx != NULL) {
- (void) SEC_ASN1DecoderFinish (p7dcx->dcx);
- p7dcx->dcx = NULL;
- }
- if (p7dcx->cinfo != NULL) {
- SEC_PKCS7DestroyContentInfo (p7dcx->cinfo);
- p7dcx->cinfo = NULL;
- }
- PORT_SetError (p7dcx->error);
- return SECFailure;
- }
-
- return SECSuccess;
-}
-
-
-SEC_PKCS7ContentInfo *
-SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx)
-{
- SEC_PKCS7ContentInfo *cinfo;
-
- cinfo = p7dcx->cinfo;
- if (p7dcx->dcx != NULL) {
- if (SEC_ASN1DecoderFinish (p7dcx->dcx) != SECSuccess) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- cinfo = NULL;
- }
- }
- PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE);
- PORT_Free (p7dcx);
- return cinfo;
-}
-
-
-SEC_PKCS7ContentInfo *
-SEC_PKCS7DecodeItem(SECItem *p7item,
- SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg,
- SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
- void *decrypt_key_cb_arg,
- SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
-{
- SEC_PKCS7DecoderContext *p7dcx;
-
- p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb,
- decrypt_key_cb_arg, decrypt_allowed_cb);
- (void) SEC_PKCS7DecoderUpdate(p7dcx, (char *) p7item->data, p7item->len);
- return SEC_PKCS7DecoderFinish(p7dcx);
-}
-
-
-/*
- * If the thing contains any certs or crls return true; false otherwise.
- */
-PRBool
-SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo)
-{
- SECOidTag kind;
- SECItem **certs;
- CERTSignedCrl **crls;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- default:
- case SEC_OID_PKCS7_DATA:
- case SEC_OID_PKCS7_DIGESTED_DATA:
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- return PR_FALSE;
- case SEC_OID_PKCS7_SIGNED_DATA:
- certs = cinfo->content.signedData->rawCerts;
- crls = cinfo->content.signedData->crls;
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- certs = cinfo->content.signedAndEnvelopedData->rawCerts;
- crls = cinfo->content.signedAndEnvelopedData->crls;
- break;
- }
-
- /*
- * I know this could be collapsed, but I was in a mood to be explicit.
- */
- if (certs != NULL && certs[0] != NULL)
- return PR_TRUE;
- else if (crls != NULL && crls[0] != NULL)
- return PR_TRUE;
- else
- return PR_FALSE;
-}
-
-/* return the content length...could use GetContent, however we
- * need the encrypted content length
- */
-PRBool
-SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen)
-{
- SECItem *item = NULL;
-
- if(cinfo == NULL) {
- return PR_TRUE;
- }
-
- switch(SEC_PKCS7ContentType(cinfo))
- {
- case SEC_OID_PKCS7_DATA:
- item = cinfo->content.data;
- break;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- item = &cinfo->content.encryptedData->encContentInfo.encContent;
- break;
- default:
- /* add other types */
- return PR_FALSE;
- }
-
- if(!item) {
- return PR_TRUE;
- } else if(item->len <= minLen) {
- return PR_TRUE;
- }
-
- return PR_FALSE;
-}
-
-
-PRBool
-SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo)
-{
- SECOidTag kind;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- default:
- case SEC_OID_PKCS7_DATA:
- case SEC_OID_PKCS7_DIGESTED_DATA:
- case SEC_OID_PKCS7_SIGNED_DATA:
- return PR_FALSE;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- return PR_TRUE;
- }
-}
-
-
-/*
- * If the PKCS7 content has a signature (not just *could* have a signature)
- * return true; false otherwise. This can/should be called before calling
- * VerifySignature, which will always indicate failure if no signature is
- * present, but that does not mean there even was a signature!
- * Note that the content itself can be empty (detached content was sent
- * another way); it is the presence of the signature that matters.
- */
-PRBool
-SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo)
-{
- SECOidTag kind;
- SEC_PKCS7SignerInfo **signerinfos;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- default:
- case SEC_OID_PKCS7_DATA:
- case SEC_OID_PKCS7_DIGESTED_DATA:
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- return PR_FALSE;
- case SEC_OID_PKCS7_SIGNED_DATA:
- signerinfos = cinfo->content.signedData->signerInfos;
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
- break;
- }
-
- /*
- * I know this could be collapsed; but I kind of think it will get
- * more complicated before I am finished, so...
- */
- if (signerinfos != NULL && signerinfos[0] != NULL)
- return PR_TRUE;
- else
- return PR_FALSE;
-}
-
-
-/*
- * SEC_PKCS7ContentVerifySignature
- * Look at a PKCS7 contentInfo and check if the signature is good.
- * The digest was either calculated earlier (and is stored in the
- * contentInfo itself) or is passed in via "detached_digest".
- *
- * The verification checks that the signing cert is valid and trusted
- * for the purpose specified by "certusage".
- *
- * In addition, if "keepcerts" is true, add any new certificates found
- * into our local database.
- *
- * XXX Each place which returns PR_FALSE should be sure to have a good
- * error set for inspection by the caller. Alternatively, we could create
- * an enumeration of success and each type of failure and return that
- * instead of a boolean. For now, the default in a bad situation is to
- * set the error to SEC_ERROR_PKCS7_BAD_SIGNATURE. But this should be
- * reviewed; better (more specific) errors should be possible (to distinguish
- * a signature failure from a badly-formed pkcs7 signedData, for example).
- * Some of the errors should probably just be SEC_ERROR_BAD_SIGNATURE,
- * but that has a less helpful error string associated with it right now;
- * if/when that changes, review and change these as needed.
- *
- * XXX This is broken wrt signedAndEnvelopedData. In that case, the
- * message digest is doubly encrypted -- first encrypted with the signer
- * private key but then again encrypted with the bulk encryption key used
- * to encrypt the content. So before we can pass the digest to VerifyDigest,
- * we need to decrypt it with the bulk encryption key. Also, in this case,
- * there should be NO authenticatedAttributes (signerinfo->authAttr should
- * be NULL).
- */
-static PRBool
-sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo,
- SECCertUsage certusage,
- SECItem *detached_digest,
- HASH_HashType digest_type,
- PRBool keepcerts)
-{
- SECAlgorithmID **digestalgs, *bulkid;
- SECItem *digest;
- SECItem **digests;
- SECItem **rawcerts;
- CERTSignedCrl **crls;
- SEC_PKCS7SignerInfo **signerinfos, *signerinfo;
- CERTCertificate *cert, **certs;
- PRBool goodsig;
- CERTCertDBHandle local_certdb, *certdb, *defaultdb;
- SECOidData *algiddata;
- int i, certcount;
- SECKEYPublicKey *publickey;
- SECItem *content_type;
- PK11SymKey *sigkey;
- SECItem *utc_stime;
- int64 stime;
- SECStatus rv;
-
- /*
- * Everything needed in order to "goto done" safely.
- */
- goodsig = PR_FALSE;
- certcount = 0;
- cert = NULL;
- certs = NULL;
- certdb = NULL;
- defaultdb = CERT_GetDefaultCertDB();
- publickey = NULL;
-
- if (! SEC_PKCS7ContentIsSigned(cinfo)) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- PORT_Assert (cinfo->contentTypeTag != NULL);
-
- switch (cinfo->contentTypeTag->offset) {
- default:
- case SEC_OID_PKCS7_DATA:
- case SEC_OID_PKCS7_DIGESTED_DATA:
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- /* Could only get here if SEC_PKCS7ContentIsSigned is broken. */
- PORT_Assert (0);
- case SEC_OID_PKCS7_SIGNED_DATA:
- {
- SEC_PKCS7SignedData *sdp;
-
- sdp = cinfo->content.signedData;
- digestalgs = sdp->digestAlgorithms;
- digests = sdp->digests;
- rawcerts = sdp->rawCerts;
- crls = sdp->crls;
- signerinfos = sdp->signerInfos;
- content_type = &(sdp->contentInfo.contentType);
- sigkey = NULL;
- bulkid = NULL;
- }
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saedp;
-
- saedp = cinfo->content.signedAndEnvelopedData;
- digestalgs = saedp->digestAlgorithms;
- digests = saedp->digests;
- rawcerts = saedp->rawCerts;
- crls = saedp->crls;
- signerinfos = saedp->signerInfos;
- content_type = &(saedp->encContentInfo.contentType);
- sigkey = saedp->sigKey;
- bulkid = &(saedp->encContentInfo.contentEncAlg);
- }
- break;
- }
-
- if ((signerinfos == NULL) || (signerinfos[0] == NULL)) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- /*
- * XXX Need to handle multiple signatures; checking them is easy,
- * but what should be the semantics here (like, return value)?
- */
- if (signerinfos[1] != NULL) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- signerinfo = signerinfos[0];
-
- /*
- * XXX I would like to just pass the issuerAndSN, along with the rawcerts
- * and crls, to some function that did all of this certificate stuff
- * (open/close the database if necessary, verifying the certs, etc.)
- * and gave me back a cert pointer if all was good.
- */
- certdb = defaultdb;
- if (certdb == NULL) {
- if (CERT_OpenCertDBFilename (&local_certdb, NULL,
- (PRBool)!keepcerts) != SECSuccess)
- goto done;
- certdb = &local_certdb;
- }
-
- certcount = 0;
- if (rawcerts != NULL) {
- for (; rawcerts[certcount] != NULL; certcount++) {
- /* just counting */
- }
- }
-
- /*
- * Note that the result of this is that each cert in "certs"
- * needs to be destroyed.
- */
- rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs,
- keepcerts, PR_FALSE, NULL);
- if ( rv != SECSuccess ) {
- goto done;
- }
-
- /*
- * This cert will also need to be freed, but since we save it
- * in signerinfo for later, we do not want to destroy it when
- * we leave this function -- we let the clean-up of the entire
- * cinfo structure later do the destroy of this cert.
- */
- cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN);
- if (cert == NULL) {
- goto done;
- }
-
- signerinfo->cert = cert;
-
- /*
- * Get and convert the signing time; if available, it will be used
- * both on the cert verification and for importing the sender
- * email profile.
- */
- utc_stime = SEC_PKCS7GetSigningTime (cinfo);
- if (utc_stime != NULL) {
- if (DER_UTCTimeToTime (&stime, utc_stime) != SECSuccess)
- utc_stime = NULL; /* conversion failed, so pretend none */
- }
-
- /*
- * XXX This uses the signing time, if available. Additionally, we
- * might want to, if there is no signing time, get the message time
- * from the mail header itself, and use that. That would require
- * a change to our interface though, and for S/MIME callers to pass
- * in a time (and for non-S/MIME callers to pass in nothing, or
- * maybe make them pass in the current time, always?).
- */
- if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage,
- utc_stime != NULL ? stime : PR_Now(),
- cinfo->pwfn_arg, NULL) != SECSuccess)
- {
- /*
- * XXX Give the user an option to check the signature anyway?
- * If we want to do this, need to give a way to leave and display
- * some dialog and get the answer and come back through (or do
- * the rest of what we do below elsewhere, maybe by putting it
- * in a function that we call below and could call from a dialog
- * finish handler).
- */
- goto savecert;
- }
-
- publickey = CERT_ExtractPublicKey (cert);
- if (publickey == NULL)
- goto done;
-
- /*
- * XXX No! If digests is empty, see if we can create it now by
- * digesting the contents. This is necessary if we want to allow
- * somebody to do a simple decode (without filtering, etc.) and
- * then later call us here to do the verification.
- * OR, we can just specify that the interface to this routine
- * *requires* that the digest(s) be done before calling and either
- * stashed in the struct itself or passed in explicitly (as would
- * be done for detached contents).
- */
- if ((digests == NULL || digests[0] == NULL)
- && (detached_digest == NULL || detached_digest->data == NULL))
- goto done;
-
- /*
- * Find and confirm digest algorithm.
- */
- algiddata = SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
-
- if (detached_digest != NULL) {
- switch (digest_type) {
- default:
- case HASH_AlgNULL:
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- case HASH_AlgMD2:
- PORT_Assert (detached_digest->len == MD2_LENGTH);
- if (algiddata->offset != SEC_OID_MD2) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
- break;
- case HASH_AlgMD5:
- PORT_Assert (detached_digest->len == MD5_LENGTH);
- if (algiddata->offset != SEC_OID_MD5) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
- break;
- case HASH_AlgSHA1:
- PORT_Assert (detached_digest->len == SHA1_LENGTH);
- if (algiddata->offset != SEC_OID_SHA1) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
- break;
- }
- digest = detached_digest;
- } else {
- PORT_Assert (digestalgs != NULL && digestalgs[0] != NULL);
- if (digestalgs == NULL || digestalgs[0] == NULL) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- /*
- * pick digest matching signerinfo->digestAlg from digests
- */
- if (algiddata == NULL) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
- for (i = 0; digestalgs[i] != NULL; i++) {
- if (SECOID_FindOID (&(digestalgs[i]->algorithm)) == algiddata)
- break;
- }
- if (digestalgs[i] == NULL) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- digest = digests[i];
- }
-
- /*
- * XXX This may not be the right set of algorithms to check.
- * I'd prefer to trust that just calling VFY_Verify{Data,Digest}
- * would do the right thing (and set an error if it could not);
- * then additional algorithms could be handled by that code
- * and we would Just Work. So this check should just be removed,
- * but not until the VFY code is better at setting errors.
- */
- algiddata = SECOID_FindOID (&(signerinfo->digestEncAlg.algorithm));
- if (algiddata == NULL ||
- ((algiddata->offset != SEC_OID_PKCS1_RSA_ENCRYPTION) &&
- (algiddata->offset != SEC_OID_ANSIX9_DSA_SIGNATURE))) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- if (signerinfo->authAttr != NULL) {
- SEC_PKCS7Attribute *attr;
- SECItem *value;
- SECItem encoded_attrs;
-
- /*
- * We have a sigkey only for signedAndEnvelopedData, which is
- * not supposed to have any authenticated attributes.
- */
- if (sigkey != NULL) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- /*
- * PKCS #7 says that if there are any authenticated attributes,
- * then there must be one for content type which matches the
- * content type of the content being signed, and there must
- * be one for message digest which matches our message digest.
- * So check these things first.
- * XXX Might be nice to have a compare-attribute-value function
- * which could collapse the following nicely.
- */
- attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
- SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
- value = sec_PKCS7AttributeValue (attr);
- if (value == NULL || value->len != content_type->len) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
- if (PORT_Memcmp (value->data, content_type->data, value->len) != 0) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
- SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
- value = sec_PKCS7AttributeValue (attr);
- if (value == NULL || value->len != digest->len) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
- if (PORT_Memcmp (value->data, digest->data, value->len) != 0) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- /*
- * Okay, we met the constraints of the basic attributes.
- * Now check the signature, which is based on a digest of
- * the DER-encoded authenticated attributes. So, first we
- * encode and then we digest/verify.
- */
- encoded_attrs.data = NULL;
- encoded_attrs.len = 0;
- if (sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,
- &(signerinfo->authAttr)) == NULL)
- goto done;
-
- if (encoded_attrs.data == NULL || encoded_attrs.len == 0) {
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- goodsig = (PRBool)(VFY_VerifyData (encoded_attrs.data,
- encoded_attrs.len,
- publickey, &(signerinfo->encDigest),
- SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg)),
- cinfo->pwfn_arg) == SECSuccess);
- PORT_Free (encoded_attrs.data);
- } else {
- SECItem *sig;
- SECItem holder;
- SECStatus rv;
-
- /*
- * No authenticated attributes.
- * The signature is based on the plain message digest.
- */
-
- sig = &(signerinfo->encDigest);
- if (sig->len == 0) { /* bad signature */
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- goto done;
- }
-
- if (sigkey != NULL) {
- sec_PKCS7CipherObject *decryptobj;
- unsigned int buflen;
-
- /*
- * For signedAndEnvelopedData, we first must decrypt the encrypted
- * digest with the bulk encryption key. The result is the normal
- * encrypted digest (aka the signature).
- */
- decryptobj = sec_PKCS7CreateDecryptObject (sigkey, bulkid);
- if (decryptobj == NULL)
- goto done;
-
- buflen = sec_PKCS7DecryptLength (decryptobj, sig->len, PR_TRUE);
- PORT_Assert (buflen);
- if (buflen == 0) { /* something is wrong */
- sec_PKCS7DestroyDecryptObject (decryptobj);
- goto done;
- }
-
- holder.data = (unsigned char*)PORT_Alloc (buflen);
- if (holder.data == NULL) {
- sec_PKCS7DestroyDecryptObject (decryptobj);
- goto done;
- }
-
- rv = sec_PKCS7Decrypt (decryptobj, holder.data, &holder.len, buflen,
- sig->data, sig->len, PR_TRUE);
- if (rv != SECSuccess) {
- sec_PKCS7DestroyDecryptObject (decryptobj);
- goto done;
- }
-
- sig = &holder;
- }
-
- goodsig = (PRBool)(VFY_VerifyDigest (digest, publickey, sig,
- SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg)),
- cinfo->pwfn_arg)
- == SECSuccess);
-
- if (sigkey != NULL) {
- PORT_Assert (sig == &holder);
- PORT_ZFree (holder.data, holder.len);
- }
- }
-
- if (! goodsig) {
- /*
- * XXX Change the generic error into our specific one, because
- * in that case we get a better explanation out of the Security
- * Advisor. This is really a bug in our error strings (the
- * "generic" error has a lousy/wrong message associated with it
- * which assumes the signature verification was done for the
- * purposes of checking the issuer signature on a certificate)
- * but this is at least an easy workaround and/or in the
- * Security Advisor, which specifically checks for the error
- * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
- * in that case but does not similarly check for
- * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would
- * probably say the wrong thing in the case that it *was* the
- * certificate signature check that failed during the cert
- * verification done above. Our error handling is really a mess.
- */
- if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
- PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
- }
-
-savecert:
- /*
- * Only save the smime profile if we are checking an email message and
- * the cert has an email address in it.
- */
- if ( ( cert->emailAddr != NULL ) &&
- ( ( certusage == certUsageEmailSigner ) ||
- ( certusage == certUsageEmailRecipient ) ) ) {
- SECItem *profile = NULL;
- int save_error;
-
- /*
- * Remember the current error set because we do not care about
- * anything set by the functions we are about to call.
- */
- save_error = PORT_GetError();
-
- if (goodsig && (signerinfo->authAttr != NULL)) {
- /*
- * If the signature is good, then we can save the S/MIME profile,
- * if we have one.
- */
- SEC_PKCS7Attribute *attr;
-
- attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
- SEC_OID_PKCS9_SMIME_CAPABILITIES,
- PR_TRUE);
- profile = sec_PKCS7AttributeValue (attr);
- }
-
- rv = CERT_SaveSMimeProfile (cert, profile, utc_stime);
-
- /*
- * Restore the saved error in case the calls above set a new
- * one that we do not actually care about.
- */
- PORT_SetError (save_error);
-
- /*
- * XXX Failure is not indicated anywhere -- the signature
- * verification itself is unaffected by whether or not the
- * profile was successfully saved.
- */
- }
-
-
-done:
-
- /*
- * See comment above about why we do not want to destroy cert
- * itself here.
- */
-
- if (certs != NULL)
- CERT_DestroyCertArray (certs, certcount);
-
- if (defaultdb == NULL && certdb != NULL)
- CERT_ClosePermCertDB (certdb);
-
- if (publickey != NULL)
- SECKEY_DestroyPublicKey (publickey);
-
- return goodsig;
-}
-
-/*
- * SEC_PKCS7VerifySignature
- * Look at a PKCS7 contentInfo and check if the signature is good.
- * The verification checks that the signing cert is valid and trusted
- * for the purpose specified by "certusage".
- *
- * In addition, if "keepcerts" is true, add any new certificates found
- * into our local database.
- */
-PRBool
-SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
- SECCertUsage certusage,
- PRBool keepcerts)
-{
- return sec_pkcs7_verify_signature (cinfo, certusage,
- NULL, HASH_AlgNULL, keepcerts);
-}
-
-/*
- * SEC_PKCS7VerifyDetachedSignature
- * Look at a PKCS7 contentInfo and check if the signature matches
- * a passed-in digest (calculated, supposedly, from detached contents).
- * The verification checks that the signing cert is valid and trusted
- * for the purpose specified by "certusage".
- *
- * In addition, if "keepcerts" is true, add any new certificates found
- * into our local database.
- */
-PRBool
-SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
- SECCertUsage certusage,
- SECItem *detached_digest,
- HASH_HashType digest_type,
- PRBool keepcerts)
-{
- return sec_pkcs7_verify_signature (cinfo, certusage,
- detached_digest, digest_type,
- keepcerts);
-}
-
-
-/*
- * Return the asked-for portion of the name of the signer of a PKCS7
- * signed object.
- *
- * Returns a pointer to allocated memory, which must be freed.
- * A NULL return value is an error.
- */
-
-#define sec_common_name 1
-#define sec_email_address 2
-
-static char *
-sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector)
-{
- SECOidTag kind;
- SEC_PKCS7SignerInfo **signerinfos;
- CERTCertificate *signercert;
- char *container;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- default:
- case SEC_OID_PKCS7_DATA:
- case SEC_OID_PKCS7_DIGESTED_DATA:
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- PORT_Assert (0);
- return NULL;
- case SEC_OID_PKCS7_SIGNED_DATA:
- {
- SEC_PKCS7SignedData *sdp;
-
- sdp = cinfo->content.signedData;
- signerinfos = sdp->signerInfos;
- }
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saedp;
-
- saedp = cinfo->content.signedAndEnvelopedData;
- signerinfos = saedp->signerInfos;
- }
- break;
- }
-
- if (signerinfos == NULL || signerinfos[0] == NULL)
- return NULL;
-
- signercert = signerinfos[0]->cert;
-
- /*
- * No cert there; see if we can find one by calling verify ourselves.
- */
- if (signercert == NULL) {
- /*
- * The cert usage does not matter in this case, because we do not
- * actually care about the verification itself, but we have to pick
- * some valid usage to pass in.
- */
- (void) sec_pkcs7_verify_signature (cinfo, certUsageEmailSigner,
- NULL, HASH_AlgNULL, PR_FALSE);
- signercert = signerinfos[0]->cert;
- if (signercert == NULL)
- return NULL;
- }
-
- switch (selector) {
- case sec_common_name:
- container = CERT_GetCommonName (&signercert->subject);
- break;
- case sec_email_address:
- if(signercert->emailAddr) {
- container = PORT_Strdup(signercert->emailAddr);
- } else {
- container = NULL;
- }
- break;
- default:
- PORT_Assert (0);
- container = NULL;
- break;
- }
-
- return container;
-}
-
-char *
-SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo)
-{
- return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name);
-}
-
-char *
-SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo)
-{
- return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address);
-}
-
-
-/*
- * Return the signing time, in UTCTime format, of a PKCS7 contentInfo.
- */
-SECItem *
-SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo)
-{
- SEC_PKCS7SignerInfo **signerinfos;
- SEC_PKCS7Attribute *attr;
-
- if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
- return NULL;
-
- signerinfos = cinfo->content.signedData->signerInfos;
-
- /*
- * No signature, or more than one, means no deal.
- */
- if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
- return NULL;
-
- attr = sec_PKCS7FindAttribute (signerinfos[0]->authAttr,
- SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
- return sec_PKCS7AttributeValue (attr);
-}
diff --git a/security/nss/lib/pkcs7/p7encode.c b/security/nss/lib/pkcs7/p7encode.c
deleted file mode 100644
index b45d2d916..000000000
--- a/security/nss/lib/pkcs7/p7encode.c
+++ /dev/null
@@ -1,1329 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * PKCS7 encoding.
- *
- * $Id$
- */
-
-#include "p7local.h"
-
-#include "cert.h"
-#include "cryptohi.h"
-#include "keyhi.h"
-#include "secasn1.h"
-#include "secoid.h"
-#include "secitem.h"
-#include "pk11func.h"
-#include "secerr.h"
-
-struct sec_pkcs7_encoder_output {
- SEC_PKCS7EncoderOutputCallback outputfn;
- void *outputarg;
-};
-
-struct SEC_PKCS7EncoderContextStr {
- SEC_ASN1EncoderContext *ecx;
- SEC_PKCS7ContentInfo *cinfo;
- struct sec_pkcs7_encoder_output output;
- sec_PKCS7CipherObject *encryptobj;
- SECHashObject *digestobj;
- void *digestcx;
-};
-
-
-/*
- * The little output function that the ASN.1 encoder calls to hand
- * us bytes which we in turn hand back to our caller (via the callback
- * they gave us).
- */
-static void
-sec_pkcs7_encoder_out(void *arg, const char *buf, unsigned long len,
- int depth, SEC_ASN1EncodingPart data_kind)
-{
- struct sec_pkcs7_encoder_output *output;
-
- output = (struct sec_pkcs7_encoder_output*)arg;
- output->outputfn (output->outputarg, buf, len);
-}
-
-static sec_PKCS7CipherObject *
-sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo,
- PK11SymKey *orig_bulkkey)
-{
- SECOidTag kind;
- sec_PKCS7CipherObject *encryptobj;
- SEC_PKCS7RecipientInfo **recipientinfos, *ri;
- SEC_PKCS7EncryptedContentInfo *enccinfo;
- SEC_PKCS7SMIMEKEAParameters keaParams;
- SECKEYPublicKey *publickey = NULL;
- SECKEYPrivateKey *ourPrivKey = NULL;
- PK11SymKey *bulkkey;
- void *mark, *wincx;
- int i;
- PRArenaPool *arena = NULL;
- unsigned char zero = 0;
-
- /* Get the context in case we need it below. */
- wincx = cinfo->pwfn_arg;
-
- /* Clear keaParams, since cleanup code checks the lengths */
- (void) memset(&keaParams, 0, sizeof(keaParams));
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- default:
- case SEC_OID_PKCS7_DATA:
- case SEC_OID_PKCS7_DIGESTED_DATA:
- case SEC_OID_PKCS7_SIGNED_DATA:
- recipientinfos = NULL;
- enccinfo = NULL;
- break;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- {
- SEC_PKCS7EncryptedData *encdp;
-
- /* To do EncryptedData we *must* be given a bulk key. */
- PORT_Assert (orig_bulkkey != NULL);
- if (orig_bulkkey == NULL) {
- /* XXX error? */
- return NULL;
- }
-
- encdp = cinfo->content.encryptedData;
- recipientinfos = NULL;
- enccinfo = &(encdp->encContentInfo);
- }
- break;
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- {
- SEC_PKCS7EnvelopedData *envdp;
-
- envdp = cinfo->content.envelopedData;
- recipientinfos = envdp->recipientInfos;
- enccinfo = &(envdp->encContentInfo);
- }
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saedp;
-
- saedp = cinfo->content.signedAndEnvelopedData;
- recipientinfos = saedp->recipientInfos;
- enccinfo = &(saedp->encContentInfo);
- }
- break;
- }
-
- if (enccinfo == NULL)
- return NULL;
-
- bulkkey = orig_bulkkey;
- if (bulkkey == NULL) {
- CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg);
- PK11SlotInfo *slot;
-
-
- slot = PK11_GetBestSlot(type,cinfo->pwfn_arg);
- if (slot == NULL) {
- return NULL;
- }
- bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8,
- cinfo->pwfn_arg);
- PK11_FreeSlot(slot);
- if (bulkkey == NULL) {
- return NULL;
- }
- }
-
- encryptobj = NULL;
- mark = PORT_ArenaMark (cinfo->poolp);
-
- /*
- * Encrypt the bulk key with the public key of each recipient.
- */
- for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) {
- CERTCertificate *cert;
- SECOidTag certalgtag, encalgtag;
- SECStatus rv;
- int data_len;
- SECItem *params = NULL;
-
- cert = ri->cert;
- PORT_Assert (cert != NULL);
- if (cert == NULL)
- continue;
-
- /*
- * XXX Want an interface that takes a cert and some data and
- * fills in an algorithmID and encrypts the data with the public
- * key from the cert. Or, give me two interfaces -- one which
- * gets the algorithm tag from a cert (I should not have to go
- * down into the subjectPublicKeyInfo myself) and another which
- * takes a public key and algorithm tag and data and encrypts
- * the data. Or something like that. The point is that all
- * of the following hardwired RSA and KEA stuff should be done
- * elsewhere.
- */
-
- certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
-
- switch (certalgtag) {
- case SEC_OID_PKCS1_RSA_ENCRYPTION:
- encalgtag = certalgtag;
- publickey = CERT_ExtractPublicKey (cert);
- if (publickey == NULL) goto loser;
-
- data_len = SECKEY_PublicKeyStrength(publickey);
- ri->encKey.data =
- (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len);
- ri->encKey.len = data_len;
- if (ri->encKey.data == NULL) goto loser;
-
- rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey,
- bulkkey,&ri->encKey);
-
- SECKEY_DestroyPublicKey(publickey);
- publickey = NULL;
- if (rv != SECSuccess) goto loser;
- params = NULL; /* paranoia */
- break;
- /* ### mwelch -- KEA */
- case SEC_OID_MISSI_KEA_DSS_OLD:
- case SEC_OID_MISSI_KEA_DSS:
- case SEC_OID_MISSI_KEA:
- {
-#define SMIME_FORTEZZA_RA_LENGTH 128
-#define SMIME_FORTEZZA_IV_LENGTH 24
-#define SMIME_FORTEZZA_MAX_KEY_SIZE 256
- SECStatus err;
- PK11SymKey *tek;
- CERTCertificate *ourCert;
- SECKEYPublicKey *ourPubKey;
- SECKEATemplateSelector whichKEA;
-
- /* We really want to show our KEA tag as the
- key exchange algorithm tag. */
- encalgtag = SEC_OID_NETSCAPE_SMIME_KEA;
-
- /* Get the public key of the recipient. */
- publickey = CERT_ExtractPublicKey(cert);
- if (publickey == NULL) goto loser;
-
- /* Find our own cert, and extract its keys. */
- ourCert = PK11_FindBestKEAMatch(cert,wincx);
- if (ourCert == NULL) goto loser;
-
- arena = PORT_NewArena(1024);
- if (arena == NULL) goto loser;
-
- ourPubKey = CERT_ExtractPublicKey(ourCert);
- if (ourPubKey == NULL)
- {
- CERT_DestroyCertificate(ourCert);
- goto loser;
- }
-
- /* While we're here, copy the public key into the outgoing
- * KEA parameters. */
- SECITEM_CopyItem(arena, &(keaParams.originatorKEAKey),
- &(ourPubKey->u.fortezza.KEAKey));
- SECKEY_DestroyPublicKey(ourPubKey);
- ourPubKey = NULL;
-
- /* Extract our private key in order to derive the
- * KEA key. */
- ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
- CERT_DestroyCertificate(ourCert); /* we're done with this */
- if (!ourPrivKey) goto loser;
-
- /* Prepare raItem with 128 bytes (filled with zeros). */
- keaParams.originatorRA.data =
- (unsigned char*)PORT_ArenaAlloc(arena,SMIME_FORTEZZA_RA_LENGTH);
- keaParams.originatorRA.len = SMIME_FORTEZZA_RA_LENGTH;
-
-
- /* Generate the TEK (token exchange key) which we use
- * to wrap the bulk encryption key. (raItem) will be
- * filled with a random seed which we need to send to
- * the recipient. */
- tek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
- &keaParams.originatorRA, NULL,
- CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
- CKA_WRAP, 0, wincx);
-
- SECKEY_DestroyPublicKey(publickey);
- SECKEY_DestroyPrivateKey(ourPrivKey);
- publickey = NULL;
- ourPrivKey = NULL;
-
- if (!tek)
- goto loser;
-
- ri->encKey.data = (unsigned char*)PORT_ArenaAlloc(cinfo->poolp,
- SMIME_FORTEZZA_MAX_KEY_SIZE);
- ri->encKey.len = SMIME_FORTEZZA_MAX_KEY_SIZE;
-
- if (ri->encKey.data == NULL)
- {
- PK11_FreeSymKey(tek);
- goto loser;
- }
-
- /* Wrap the bulk key. What we do with the resulting data
- depends on whether we're using Skipjack to wrap the key. */
- switch(PK11_AlgtagToMechanism(enccinfo->encalg))
- {
- case CKM_SKIPJACK_CBC64:
- case CKM_SKIPJACK_ECB64:
- case CKM_SKIPJACK_OFB64:
- case CKM_SKIPJACK_CFB64:
- case CKM_SKIPJACK_CFB32:
- case CKM_SKIPJACK_CFB16:
- case CKM_SKIPJACK_CFB8:
- /* do SKIPJACK, we use the wrap mechanism */
- err = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL,
- tek, bulkkey, &ri->encKey);
- whichKEA = SECKEAUsesSkipjack;
- break;
- default:
- /* Not SKIPJACK, we encrypt the raw key data */
- keaParams.nonSkipjackIV .data =
- (unsigned char*)PORT_ArenaAlloc(arena,
- SMIME_FORTEZZA_IV_LENGTH);
- keaParams.nonSkipjackIV.len = SMIME_FORTEZZA_IV_LENGTH;
- err = PK11_WrapSymKey(CKM_SKIPJACK_CBC64,
- &keaParams.nonSkipjackIV,
- tek, bulkkey, &ri->encKey);
- if (err != SECSuccess)
- goto loser;
-
- if (ri->encKey.len != PK11_GetKeyLength(bulkkey))
- {
- /* The size of the encrypted key is not the same as
- that of the original bulk key, presumably due to
- padding. Encode and store the real size of the
- bulk key. */
- if (SEC_ASN1EncodeInteger(arena,
- &keaParams.bulkKeySize,
- PK11_GetKeyLength(bulkkey))
- == NULL)
- err = (SECStatus)PORT_GetError();
- else
- /* use full template for encoding */
- whichKEA = SECKEAUsesNonSkipjackWithPaddedEncKey;
- }
- else
- /* enc key length == bulk key length */
- whichKEA = SECKEAUsesNonSkipjack;
- break;
- }
-
- PK11_FreeSymKey(tek);
- if (err != SECSuccess)
- goto loser;
-
- /* Encode the KEA parameters into the recipient info. */
- params = SEC_ASN1EncodeItem(arena,NULL, &keaParams,
- sec_pkcs7_get_kea_template(whichKEA));
- if (params == NULL) goto loser;
- break;
- }
- default:
- PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
- goto loser;
- }
-
- rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag,
- params);
- if (rv != SECSuccess)
- goto loser;
- if (arena) PORT_FreeArena(arena,PR_FALSE);
- arena = NULL;
- }
-
- encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey,
- enccinfo->encalg,
- &(enccinfo->contentEncAlg));
- if (encryptobj != NULL) {
- PORT_ArenaUnmark (cinfo->poolp, mark);
- mark = NULL; /* good one; do not want to release */
- }
- /* fallthru */
-
-loser:
- if (arena) {
- PORT_FreeArena(arena, PR_FALSE);
- }
- if (publickey) {
- SECKEY_DestroyPublicKey(publickey);
- }
- if (ourPrivKey) {
- SECKEY_DestroyPrivateKey(ourPrivKey);
- }
- if (mark != NULL) {
- PORT_ArenaRelease (cinfo->poolp, mark);
- }
- if (orig_bulkkey == NULL) {
- if (bulkkey) PK11_FreeSymKey(bulkkey);
- }
-
- return encryptobj;
-}
-
-
-static void
-sec_pkcs7_encoder_notify (void *arg, PRBool before, void *dest, int depth)
-{
- SEC_PKCS7EncoderContext *p7ecx;
- SEC_PKCS7ContentInfo *cinfo;
- SECOidTag kind;
- PRBool before_content;
-
- /*
- * We want to notice just before the content field. After fields are
- * not interesting to us.
- */
- if (!before)
- return;
-
- p7ecx = (SEC_PKCS7EncoderContext*)arg;
- cinfo = p7ecx->cinfo;
-
- before_content = PR_FALSE;
-
- /*
- * Watch for the content field, at which point we want to instruct
- * the ASN.1 encoder to start taking bytes from the buffer.
- *
- * XXX The following assumes the inner content type is data;
- * if/when we want to handle fully nested types, this will have
- * to recurse until reaching the innermost data content.
- */
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- default:
- case SEC_OID_PKCS7_DATA:
- if (dest == &(cinfo->content.data))
- before_content = PR_TRUE;
- break;
-
- case SEC_OID_PKCS7_DIGESTED_DATA:
- {
- SEC_PKCS7DigestedData *digd;
-
- digd = cinfo->content.digestedData;
- if (digd == NULL)
- break;
-
- if (dest == &(digd->contentInfo.content))
- before_content = PR_TRUE;
- }
- break;
-
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- {
- SEC_PKCS7EncryptedData *encd;
-
- encd = cinfo->content.encryptedData;
- if (encd == NULL)
- break;
-
- if (dest == &(encd->encContentInfo.encContent))
- before_content = PR_TRUE;
- }
- break;
-
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- {
- SEC_PKCS7EnvelopedData *envd;
-
- envd = cinfo->content.envelopedData;
- if (envd == NULL)
- break;
-
- if (dest == &(envd->encContentInfo.encContent))
- before_content = PR_TRUE;
- }
- break;
-
- case SEC_OID_PKCS7_SIGNED_DATA:
- {
- SEC_PKCS7SignedData *sigd;
-
- sigd = cinfo->content.signedData;
- if (sigd == NULL)
- break;
-
- if (dest == &(sigd->contentInfo.content))
- before_content = PR_TRUE;
- }
- break;
-
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saed;
-
- saed = cinfo->content.signedAndEnvelopedData;
- if (saed == NULL)
- break;
-
- if (dest == &(saed->encContentInfo.encContent))
- before_content = PR_TRUE;
- }
- break;
- }
-
- if (before_content) {
- /*
- * This will cause the next SEC_ASN1EncoderUpdate to take the
- * contents bytes from the passed-in buffer.
- */
- SEC_ASN1EncoderSetTakeFromBuf (p7ecx->ecx);
- /*
- * And that is all we needed this notify function for.
- */
- SEC_ASN1EncoderClearNotifyProc (p7ecx->ecx);
- }
-}
-
-
-static SEC_PKCS7EncoderContext *
-sec_pkcs7_encoder_start_contexts (SEC_PKCS7ContentInfo *cinfo,
- PK11SymKey *bulkkey)
-{
- SEC_PKCS7EncoderContext *p7ecx;
- SECOidTag kind;
- PRBool encrypt;
- SECItem **digests;
- SECAlgorithmID *digestalg, **digestalgs;
-
- p7ecx =
- (SEC_PKCS7EncoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7EncoderContext));
- if (p7ecx == NULL)
- return NULL;
-
- digests = NULL;
- digestalg = NULL;
- digestalgs = NULL;
- encrypt = PR_FALSE;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- default:
- case SEC_OID_PKCS7_DATA:
- break;
- case SEC_OID_PKCS7_DIGESTED_DATA:
- digestalg = &(cinfo->content.digestedData->digestAlg);
- break;
- case SEC_OID_PKCS7_SIGNED_DATA:
- digests = cinfo->content.signedData->digests;
- digestalgs = cinfo->content.signedData->digestAlgorithms;
- break;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- encrypt = PR_TRUE;
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- digests = cinfo->content.signedAndEnvelopedData->digests;
- digestalgs = cinfo->content.signedAndEnvelopedData->digestAlgorithms;
- encrypt = PR_TRUE;
- break;
- }
-
- if (encrypt) {
- p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt (cinfo, bulkkey);
- if (p7ecx->encryptobj == NULL) {
- PORT_Free (p7ecx);
- return NULL;
- }
- }
-
- if (digestalgs != NULL) {
- if (digests != NULL) {
- /* digests already created (probably for detached data) */
- digestalg = NULL;
- } else {
- /*
- * XXX Some day we should handle multiple digests; for now,
- * assume only one will be done.
- */
- PORT_Assert (digestalgs[0] != NULL && digestalgs[1] == NULL);
- digestalg = digestalgs[0];
- }
- }
-
- if (digestalg != NULL) {
- SECOidData *oiddata;
-
- oiddata = SECOID_FindOID (&(digestalg->algorithm));
- if (oiddata != NULL) {
- switch (oiddata->offset) {
- case SEC_OID_MD2:
- p7ecx->digestobj = &SECHashObjects[HASH_AlgMD2];
- break;
- case SEC_OID_MD5:
- p7ecx->digestobj = &SECHashObjects[HASH_AlgMD5];
- break;
- case SEC_OID_SHA1:
- p7ecx->digestobj = &SECHashObjects[HASH_AlgSHA1];
- break;
- default:
- /* XXX right error? */
- PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
- break;
- }
- }
- if (p7ecx->digestobj != NULL) {
- p7ecx->digestcx = (* p7ecx->digestobj->create) ();
- if (p7ecx->digestcx == NULL)
- p7ecx->digestobj = NULL;
- else
- (* p7ecx->digestobj->begin) (p7ecx->digestcx);
- }
- if (p7ecx->digestobj == NULL) {
- if (p7ecx->encryptobj != NULL)
- sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
- PORT_Free (p7ecx);
- return NULL;
- }
- }
-
- p7ecx->cinfo = cinfo;
- return p7ecx;
-}
-
-
-SEC_PKCS7EncoderContext *
-SEC_PKCS7EncoderStart (SEC_PKCS7ContentInfo *cinfo,
- SEC_PKCS7EncoderOutputCallback outputfn,
- void *outputarg,
- PK11SymKey *bulkkey)
-{
- SEC_PKCS7EncoderContext *p7ecx;
- SECStatus rv;
-
- p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
- if (p7ecx == NULL)
- return NULL;
-
- p7ecx->output.outputfn = outputfn;
- p7ecx->output.outputarg = outputarg;
-
- /*
- * Initialize the BER encoder.
- */
- p7ecx->ecx = SEC_ASN1EncoderStart (cinfo, sec_PKCS7ContentInfoTemplate,
- sec_pkcs7_encoder_out, &(p7ecx->output));
- if (p7ecx->ecx == NULL) {
- PORT_Free (p7ecx);
- return NULL;
- }
-
- /*
- * Indicate that we are streaming. We will be streaming until we
- * get past the contents bytes.
- */
- SEC_ASN1EncoderSetStreaming (p7ecx->ecx);
-
- /*
- * The notify function will watch for the contents field.
- */
- SEC_ASN1EncoderSetNotifyProc (p7ecx->ecx, sec_pkcs7_encoder_notify, p7ecx);
-
- /*
- * This will encode everything up to the content bytes. (The notify
- * function will then cause the encoding to stop there.) Then our
- * caller can start passing contents bytes to our Update, which we
- * will pass along.
- */
- rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
- if (rv != SECSuccess) {
- PORT_Free (p7ecx);
- return NULL;
- }
-
- return p7ecx;
-}
-
-
-/*
- * XXX If/when we support nested contents, this needs to be revised.
- */
-static SECStatus
-sec_pkcs7_encoder_work_data (SEC_PKCS7EncoderContext *p7ecx, SECItem *dest,
- const unsigned char *data, unsigned long len,
- PRBool final)
-{
- unsigned char *buf = NULL;
- SECStatus rv;
-
-
- rv = SECSuccess; /* may as well be optimistic */
-
- /*
- * We should really have data to process, or we should be trying
- * to finish/flush the last block. (This is an overly paranoid
- * check since all callers are in this file and simple inspection
- * proves they do it right. But it could find a bug in future
- * modifications/development, that is why it is here.)
- */
- PORT_Assert ((data != NULL && len) || final);
-
- /*
- * Update the running digest.
- * XXX This needs modification if/when we handle multiple digests.
- */
- if (len && p7ecx->digestobj != NULL) {
- (* p7ecx->digestobj->update) (p7ecx->digestcx, data, len);
- }
-
- /*
- * Encrypt this chunk.
- */
- if (p7ecx->encryptobj != NULL) {
- /* XXX the following lengths should all be longs? */
- unsigned int inlen; /* length of data being encrypted */
- unsigned int outlen; /* length of encrypted data */
- unsigned int buflen; /* length available for encrypted data */
-
- inlen = len;
- buflen = sec_PKCS7EncryptLength (p7ecx->encryptobj, inlen, final);
- if (buflen == 0) {
- /*
- * No output is expected, but the input data may be buffered
- * so we still have to call Encrypt.
- */
- rv = sec_PKCS7Encrypt (p7ecx->encryptobj, NULL, NULL, 0,
- data, inlen, final);
- if (final) {
- len = 0;
- goto done;
- }
- return rv;
- }
-
- if (dest != NULL)
- buf = (unsigned char*)PORT_ArenaAlloc(p7ecx->cinfo->poolp, buflen);
- else
- buf = (unsigned char*)PORT_Alloc (buflen);
-
- if (buf == NULL) {
- rv = SECFailure;
- } else {
- rv = sec_PKCS7Encrypt (p7ecx->encryptobj, buf, &outlen, buflen,
- data, inlen, final);
- data = buf;
- len = outlen;
- }
- if (rv != SECSuccess) {
- if (final)
- goto done;
- return rv;
- }
- }
-
- if (p7ecx->ecx != NULL) {
- /*
- * Encode the contents bytes.
- */
- if(len) {
- rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, (const char *)data, len);
- }
- }
-
-done:
- if (p7ecx->encryptobj != NULL) {
- if (final)
- sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
- if (dest != NULL) {
- dest->data = buf;
- dest->len = len;
- } else if (buf != NULL) {
- PORT_Free (buf);
- }
- }
-
- if (final && p7ecx->digestobj != NULL) {
- SECItem *digest, **digests, ***digestsp;
- unsigned char *digdata;
- SECOidTag kind;
-
- kind = SEC_PKCS7ContentType (p7ecx->cinfo);
- switch (kind) {
- default:
- PORT_Assert (0);
- return SECFailure;
- case SEC_OID_PKCS7_DIGESTED_DATA:
- digest = &(p7ecx->cinfo->content.digestedData->digest);
- digestsp = NULL;
- break;
- case SEC_OID_PKCS7_SIGNED_DATA:
- digest = NULL;
- digestsp = &(p7ecx->cinfo->content.signedData->digests);
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- digest = NULL;
- digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests);
- break;
- }
-
- digdata = (unsigned char*)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
- p7ecx->digestobj->length);
- if (digdata == NULL)
- return SECFailure;
-
- if (digestsp != NULL) {
- PORT_Assert (digest == NULL);
-
- digest = (SECItem*)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
- sizeof(SECItem));
- digests = (SECItem**)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
- 2 * sizeof(SECItem *));
- if (digests == NULL || digest == NULL)
- return SECFailure;
-
- digests[0] = digest;
- digests[1] = NULL;
-
- *digestsp = digests;
- }
-
- PORT_Assert (digest != NULL);
-
- digest->data = digdata;
- digest->len = p7ecx->digestobj->length;
-
- (* p7ecx->digestobj->end) (p7ecx->digestcx, digest->data,
- &(digest->len), digest->len);
- (* p7ecx->digestobj->destroy) (p7ecx->digestcx, PR_TRUE);
- }
-
- return rv;
-}
-
-
-SECStatus
-SEC_PKCS7EncoderUpdate (SEC_PKCS7EncoderContext *p7ecx,
- const char *data, unsigned long len)
-{
- /* XXX Error handling needs help. Return what? Do "Finish" on failure? */
- return sec_pkcs7_encoder_work_data (p7ecx, NULL,
- (const unsigned char *)data, len,
- PR_FALSE);
-}
-
-
-/*
- * XXX I would *really* like to not have to do this, but the current
- * signing interface gives me little choice.
- */
-static SECOidTag
-sec_pkcs7_pick_sign_alg (SECOidTag hashalg, SECOidTag encalg)
-{
- switch (encalg) {
- case SEC_OID_PKCS1_RSA_ENCRYPTION:
- switch (hashalg) {
- case SEC_OID_MD2:
- return SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
- case SEC_OID_MD5:
- return SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
- case SEC_OID_SHA1:
- return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
- default:
- return SEC_OID_UNKNOWN;
- }
- case SEC_OID_ANSIX9_DSA_SIGNATURE:
- case SEC_OID_MISSI_KEA_DSS:
- case SEC_OID_MISSI_DSS:
- switch (hashalg) {
- case SEC_OID_SHA1:
- return SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
- default:
- return SEC_OID_UNKNOWN;
- }
- default:
- break;
- }
-
- return encalg; /* maybe it is already the right algid */
-}
-
-
-static SECStatus
-sec_pkcs7_encoder_sig_and_certs (SEC_PKCS7ContentInfo *cinfo,
- SECKEYGetPasswordKey pwfn, void *pwfnarg)
-{
- SECOidTag kind;
- CERTCertificate **certs;
- CERTCertificateList **certlists;
- SECAlgorithmID **digestalgs;
- SECItem **digests;
- SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
- SECItem **rawcerts, ***rawcertsp;
- PRArenaPool *poolp;
- int certcount;
- int ci, cli, rci, si;
-
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- default:
- case SEC_OID_PKCS7_DATA:
- case SEC_OID_PKCS7_DIGESTED_DATA:
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- certs = NULL;
- certlists = NULL;
- digestalgs = NULL;
- digests = NULL;
- signerinfos = NULL;
- rawcertsp = NULL;
- break;
- case SEC_OID_PKCS7_SIGNED_DATA:
- {
- SEC_PKCS7SignedData *sdp;
-
- sdp = cinfo->content.signedData;
- certs = sdp->certs;
- certlists = sdp->certLists;
- digestalgs = sdp->digestAlgorithms;
- digests = sdp->digests;
- signerinfos = sdp->signerInfos;
- rawcertsp = &(sdp->rawCerts);
- }
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- {
- SEC_PKCS7SignedAndEnvelopedData *saedp;
-
- saedp = cinfo->content.signedAndEnvelopedData;
- certs = saedp->certs;
- certlists = saedp->certLists;
- digestalgs = saedp->digestAlgorithms;
- digests = saedp->digests;
- signerinfos = saedp->signerInfos;
- rawcertsp = &(saedp->rawCerts);
- }
- break;
- }
-
- if (certs == NULL && certlists == NULL && signerinfos == NULL)
- return SECSuccess; /* nothing for us to do! */
-
- poolp = cinfo->poolp;
- certcount = 0;
-
- if (signerinfos != NULL) {
- SECOidTag digestalgtag;
- int di;
- SECStatus rv;
- CERTCertificate *cert;
- SECKEYPrivateKey *privkey;
- SECItem signature;
- SECOidTag signalgtag;
-
- PORT_Assert (digestalgs != NULL && digests != NULL);
-
- /*
- * If one fails, we bail right then. If we want to continue and
- * try to do subsequent signatures, this loop, and the departures
- * from it, will need to be reworked.
- */
- for (si = 0; signerinfos[si] != NULL; si++) {
-
- signerinfo = signerinfos[si];
-
- /* find right digest */
- digestalgtag = SECOID_GetAlgorithmTag (&(signerinfo->digestAlg));
- for (di = 0; digestalgs[di] != NULL; di++) {
- /* XXX Should I be comparing more than the tag? */
- if (digestalgtag == SECOID_GetAlgorithmTag (digestalgs[di]))
- break;
- }
- if (digestalgs[di] == NULL) {
- /* XXX oops; do what? set an error? */
- return SECFailure;
- }
- PORT_Assert (digests[di] != NULL);
-
- cert = signerinfo->cert;
- privkey = PK11_FindKeyByAnyCert (cert, pwfnarg);
- if (privkey == NULL)
- return SECFailure;
-
- /*
- * XXX I think there should be a cert-level interface for this,
- * so that I do not have to know about subjectPublicKeyInfo...
- */
- signalgtag = SECOID_GetAlgorithmTag (&(cert->subjectPublicKeyInfo.algorithm));
-
- /* Fortezza MISSI have weird signature formats. Map them
- * to standard DSA formats */
- signalgtag = PK11_FortezzaMapSig(signalgtag);
-
- if (signerinfo->authAttr != NULL) {
- SEC_PKCS7Attribute *attr;
- SECItem encoded_attrs;
- SECItem *dummy;
-
- /*
- * First, find and fill in the message digest attribute.
- */
- attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
- SEC_OID_PKCS9_MESSAGE_DIGEST,
- PR_TRUE);
- PORT_Assert (attr != NULL);
- if (attr == NULL) {
- SECKEY_DestroyPrivateKey (privkey);
- return SECFailure;
- }
-
- /*
- * XXX The second half of the following assertion prevents
- * the encoder from being called twice on the same content.
- * Either just remove the second half the assertion, or
- * change the code to check if the value already there is
- * the same as digests[di], whichever seems more right.
- */
- PORT_Assert (attr->values != NULL && attr->values[0] == NULL);
- attr->values[0] = digests[di];
-
- /*
- * Before encoding, reorder the attributes so that when they
- * are encoded, they will be conforming DER, which is required
- * to have a specific order and that is what must be used for
- * the hash/signature. We do this here, rather than building
- * it into EncodeAttributes, because we do not want to do
- * such reordering on incoming messages (which also uses
- * EncodeAttributes) or our old signatures (and other "broken"
- * implementations) will not verify. So, we want to guarantee
- * that we send out good DER encodings of attributes, but not
- * to expect to receive them.
- */
- rv = sec_PKCS7ReorderAttributes (signerinfo->authAttr);
- if (rv != SECSuccess) {
- SECKEY_DestroyPrivateKey (privkey);
- return SECFailure;
- }
-
- encoded_attrs.data = NULL;
- encoded_attrs.len = 0;
- dummy = sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,
- &(signerinfo->authAttr));
- if (dummy == NULL) {
- SECKEY_DestroyPrivateKey (privkey);
- return SECFailure;
- }
-
- rv = SEC_SignData (&signature,
- encoded_attrs.data, encoded_attrs.len,
- privkey,
- sec_pkcs7_pick_sign_alg (digestalgtag,
- signalgtag));
- SECITEM_FreeItem (&encoded_attrs, PR_FALSE);
- } else {
- rv = SGN_Digest (privkey, digestalgtag, &signature,
- digests[di]);
- }
-
- SECKEY_DestroyPrivateKey (privkey);
-
- if (rv != SECSuccess)
- return rv;
-
- rv = SECITEM_CopyItem (poolp, &(signerinfo->encDigest), &signature);
- if (rv != SECSuccess)
- return rv;
-
- SECITEM_FreeItem (&signature, PR_FALSE);
-
- rv = SECOID_SetAlgorithmID (poolp, &(signerinfo->digestEncAlg),
- signalgtag, NULL);
- if (rv != SECSuccess)
- return SECFailure;
-
- /*
- * Count the cert chain for this signer.
- */
- if (signerinfo->certList != NULL)
- certcount += signerinfo->certList->len;
- }
- }
-
- if (certs != NULL) {
- for (ci = 0; certs[ci] != NULL; ci++)
- certcount++;
- }
-
- if (certlists != NULL) {
- for (cli = 0; certlists[cli] != NULL; cli++)
- certcount += certlists[cli]->len;
- }
-
- if (certcount == 0)
- return SECSuccess; /* signing done; no certs */
-
- /*
- * Combine all of the certs and cert chains into rawcerts.
- * Note: certcount is an upper bound; we may not need that many slots
- * but we will allocate anyway to avoid having to do another pass.
- * (The temporary space saving is not worth it.)
- */
- rawcerts = (SECItem**)PORT_ArenaAlloc (poolp,
- (certcount + 1) * sizeof(SECItem *));
- if (rawcerts == NULL)
- return SECFailure;
-
- /*
- * XXX Want to check for duplicates and not add *any* cert that is
- * already in the set. This will be more important when we start
- * dealing with larger sets of certs, dual-key certs (signing and
- * encryption), etc. For the time being we can slide by...
- */
- rci = 0;
- if (signerinfos != NULL) {
- for (si = 0; signerinfos[si] != NULL; si++) {
- signerinfo = signerinfos[si];
- for (ci = 0; ci < signerinfo->certList->len; ci++)
- rawcerts[rci++] = &(signerinfo->certList->certs[ci]);
- }
-
- }
-
- if (certs != NULL) {
- for (ci = 0; certs[ci] != NULL; ci++)
- rawcerts[rci++] = &(certs[ci]->derCert);
- }
-
- if (certlists != NULL) {
- for (cli = 0; certlists[cli] != NULL; cli++) {
- for (ci = 0; ci < certlists[cli]->len; ci++)
- rawcerts[rci++] = &(certlists[cli]->certs[ci]);
- }
- }
-
- rawcerts[rci] = NULL;
- *rawcertsp = rawcerts;
-
- return SECSuccess;
-}
-
-
-SECStatus
-SEC_PKCS7EncoderFinish (SEC_PKCS7EncoderContext *p7ecx,
- SECKEYGetPasswordKey pwfn, void *pwfnarg)
-{
- SECStatus rv;
-
- /*
- * Flush out any remaining data.
- */
- rv = sec_pkcs7_encoder_work_data (p7ecx, NULL, NULL, 0, PR_TRUE);
-
- /*
- * Turn off streaming stuff.
- */
- SEC_ASN1EncoderClearTakeFromBuf (p7ecx->ecx);
- SEC_ASN1EncoderClearStreaming (p7ecx->ecx);
-
- if (rv != SECSuccess)
- goto loser;
-
- rv = sec_pkcs7_encoder_sig_and_certs (p7ecx->cinfo, pwfn, pwfnarg);
- if (rv != SECSuccess)
- goto loser;
-
- rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
-
-loser:
- SEC_ASN1EncoderFinish (p7ecx->ecx);
- PORT_Free (p7ecx);
- return rv;
-}
-
-
-/*
- * After this routine is called, the entire PKCS7 contentInfo is ready
- * to be encoded. This is used internally, but can also be called from
- * elsewhere for those who want to be able to just have pointers to
- * the ASN1 template for pkcs7 contentInfo built into their own encodings.
- */
-SECStatus
-SEC_PKCS7PrepareForEncode (SEC_PKCS7ContentInfo *cinfo,
- PK11SymKey *bulkkey,
- SECKEYGetPasswordKey pwfn,
- void *pwfnarg)
-{
- SEC_PKCS7EncoderContext *p7ecx;
- SECItem *content, *enc_content;
- SECStatus rv;
-
- p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
- if (p7ecx == NULL)
- return SECFailure;
-
- content = SEC_PKCS7GetContent (cinfo);
-
- if (p7ecx->encryptobj != NULL) {
- SECOidTag kind;
- SEC_PKCS7EncryptedContentInfo *enccinfo;
-
- kind = SEC_PKCS7ContentType (p7ecx->cinfo);
- switch (kind) {
- default:
- PORT_Assert (0);
- rv = SECFailure;
- goto loser;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- enccinfo = &(p7ecx->cinfo->content.encryptedData->encContentInfo);
- break;
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- enccinfo = &(p7ecx->cinfo->content.envelopedData->encContentInfo);
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- enccinfo = &(p7ecx->cinfo->content.signedAndEnvelopedData->encContentInfo);
- break;
- }
- enc_content = &(enccinfo->encContent);
- } else {
- enc_content = NULL;
- }
-
- if (content != NULL && content->data != NULL && content->len) {
- rv = sec_pkcs7_encoder_work_data (p7ecx, enc_content,
- content->data, content->len, PR_TRUE);
- if (rv != SECSuccess)
- goto loser;
- }
-
- rv = sec_pkcs7_encoder_sig_and_certs (cinfo, pwfn, pwfnarg);
-
-loser:
- PORT_Free (p7ecx);
- return rv;
-}
-
-
-/*
- * Encode a PKCS7 object, in one shot. All necessary components
- * of the object must already be specified. Either the data has
- * already been included (via SetContent), or the data is detached,
- * or there is no data at all (certs-only).
- *
- * "cinfo" specifies the object to be encoded.
- *
- * "outputfn" is where the encoded bytes will be passed.
- *
- * "outputarg" is an opaque argument to the above callback.
- *
- * "bulkkey" specifies the bulk encryption key to use. This argument
- * can be NULL if no encryption is being done, or if the bulk key should
- * be generated internally (usually the case for EnvelopedData but never
- * for EncryptedData, which *must* provide a bulk encryption key).
- *
- * "pwfn" is a callback for getting the password which protects the
- * private key of the signer. This argument can be NULL if it is known
- * that no signing is going to be done.
- *
- * "pwfnarg" is an opaque argument to the above callback.
- */
-SECStatus
-SEC_PKCS7Encode (SEC_PKCS7ContentInfo *cinfo,
- SEC_PKCS7EncoderOutputCallback outputfn,
- void *outputarg,
- PK11SymKey *bulkkey,
- SECKEYGetPasswordKey pwfn,
- void *pwfnarg)
-{
- SECStatus rv;
-
- rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
- if (rv == SECSuccess) {
- struct sec_pkcs7_encoder_output outputcx;
-
- outputcx.outputfn = outputfn;
- outputcx.outputarg = outputarg;
-
- rv = SEC_ASN1Encode (cinfo, sec_PKCS7ContentInfoTemplate,
- sec_pkcs7_encoder_out, &outputcx);
- }
-
- return rv;
-}
-
-
-/*
- * Encode a PKCS7 object, in one shot. All necessary components
- * of the object must already be specified. Either the data has
- * already been included (via SetContent), or the data is detached,
- * or there is no data at all (certs-only). The output, rather than
- * being passed to an output function as is done above, is all put
- * into a SECItem.
- *
- * "pool" specifies a pool from which to allocate the result.
- * It can be NULL, in which case memory is allocated generically.
- *
- * "dest" specifies a SECItem in which to put the result data.
- * It can be NULL, in which case the entire item is allocated, too.
- *
- * "cinfo" specifies the object to be encoded.
- *
- * "bulkkey" specifies the bulk encryption key to use. This argument
- * can be NULL if no encryption is being done, or if the bulk key should
- * be generated internally (usually the case for EnvelopedData but never
- * for EncryptedData, which *must* provide a bulk encryption key).
- *
- * "pwfn" is a callback for getting the password which protects the
- * private key of the signer. This argument can be NULL if it is known
- * that no signing is going to be done.
- *
- * "pwfnarg" is an opaque argument to the above callback.
- */
-SECItem *
-SEC_PKCS7EncodeItem (PRArenaPool *pool,
- SECItem *dest,
- SEC_PKCS7ContentInfo *cinfo,
- PK11SymKey *bulkkey,
- SECKEYGetPasswordKey pwfn,
- void *pwfnarg)
-{
- SECStatus rv;
-
- rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
- if (rv != SECSuccess)
- return NULL;
-
- return SEC_ASN1EncodeItem (pool, dest, cinfo, sec_PKCS7ContentInfoTemplate);
-}
-
diff --git a/security/nss/lib/pkcs7/p7local.c b/security/nss/lib/pkcs7/p7local.c
deleted file mode 100644
index d3e58be50..000000000
--- a/security/nss/lib/pkcs7/p7local.c
+++ /dev/null
@@ -1,1431 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * Support routines for PKCS7 implementation, none of which are exported.
- * This file should only contain things that are needed by both the
- * encoding/creation side *and* the decoding/decryption side. Anything
- * else should be static routines in the appropriate file.
- *
- * $Id$
- */
-
-#include "p7local.h"
-
-#include "cryptohi.h"
-#include "secasn1.h"
-#include "secoid.h"
-#include "secitem.h"
-#include "pk11func.h"
-#include "secpkcs5.h"
-#include "secerr.h"
-
-/*
- * -------------------------------------------------------------------
- * Cipher stuff.
- */
-
-typedef SECStatus (*sec_pkcs7_cipher_function) (void *,
- unsigned char *,
- unsigned *,
- unsigned int,
- const unsigned char *,
- unsigned int);
-typedef SECStatus (*sec_pkcs7_cipher_destroy) (void *, PRBool);
-
-#define BLOCK_SIZE 4096
-
-struct sec_pkcs7_cipher_object {
- void *cx;
- sec_pkcs7_cipher_function doit;
- sec_pkcs7_cipher_destroy destroy;
- PRBool encrypt;
- int block_size;
- int pad_size;
- int pending_count;
- unsigned char pending_buf[BLOCK_SIZE];
-};
-
-/*
- * Create a cipher object to do decryption, based on the given bulk
- * encryption key and algorithm identifier (which may include an iv).
- *
- * XXX This interface, or one similar, would be really nice available
- * in general... I tried to keep the pkcs7-specific stuff (mostly
- * having to do with padding) out of here.
- *
- * XXX Once both are working, it might be nice to combine this and the
- * function below (for starting up encryption) into one routine, and just
- * have two simple cover functions which call it.
- */
-sec_PKCS7CipherObject *
-sec_PKCS7CreateDecryptObject (PK11SymKey *key, SECAlgorithmID *algid)
-{
- sec_PKCS7CipherObject *result;
- SECOidTag algtag;
- void *ciphercx;
- CK_MECHANISM_TYPE mechanism;
- SECItem *param;
- PK11SlotInfo *slot;
-
- result = (struct sec_pkcs7_cipher_object*)
- PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
- if (result == NULL)
- return NULL;
-
- ciphercx = NULL;
- algtag = SECOID_GetAlgorithmTag (algid);
-
- if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
- CK_MECHANISM pbeMech, cryptoMech;
- SECItem *pbeParams, *pwitem;
- SEC_PKCS5KeyAndPassword *keyPwd;
-
- keyPwd = (SEC_PKCS5KeyAndPassword *)key;
- key = keyPwd->key;
- pwitem = keyPwd->pwitem;
-
- pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
- pbeParams = PK11_ParamFromAlgid(algid);
- if (!pbeParams) {
- PORT_Free(result);
- return NULL;
- }
-
- pbeMech.pParameter = pbeParams->data;
- pbeMech.ulParameterLen = pbeParams->len;
- if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, pwitem,
- PR_FALSE) != CKR_OK) {
- PORT_Free(result);
- SECITEM_ZfreeItem(pbeParams, PR_TRUE);
- return NULL;
- }
- SECITEM_ZfreeItem(pbeParams, PR_TRUE);
-
- param = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
- if(!param) {
- PORT_Free(result);
- return NULL;
- }
- param->data = (unsigned char *)cryptoMech.pParameter;
- param->len = cryptoMech.ulParameterLen;
- mechanism = cryptoMech.mechanism;
- } else {
- mechanism = PK11_AlgtagToMechanism(algtag);
- param = PK11_ParamFromAlgid(algid);
- if (param == NULL) {
- PORT_Free(result);
- return NULL;
- }
- }
-
- result->pad_size = PK11_GetBlockSize(mechanism,param);
- slot = PK11_GetSlotFromKey(key);
- result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
- PK11_FreeSlot(slot);
- ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_DECRYPT, key, param);
- SECITEM_FreeItem(param,PR_TRUE);
- if (ciphercx == NULL) {
- PORT_Free (result);
- return NULL;
- }
-
- result->cx = ciphercx;
- result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp;
- result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
- result->encrypt = PR_FALSE;
- result->pending_count = 0;
-
- return result;
-}
-
-/*
- * Create a cipher object to do encryption, based on the given bulk
- * encryption key and algorithm tag. Fill in the algorithm identifier
- * (which may include an iv) appropriately.
- *
- * XXX This interface, or one similar, would be really nice available
- * in general... I tried to keep the pkcs7-specific stuff (mostly
- * having to do with padding) out of here.
- *
- * XXX Once both are working, it might be nice to combine this and the
- * function above (for starting up decryption) into one routine, and just
- * have two simple cover functions which call it.
- */
-sec_PKCS7CipherObject *
-sec_PKCS7CreateEncryptObject (PRArenaPool *poolp, PK11SymKey *key,
- SECOidTag algtag, SECAlgorithmID *algid)
-{
- sec_PKCS7CipherObject *result;
- void *ciphercx;
- SECItem *param;
- SECStatus rv;
- CK_MECHANISM_TYPE mechanism;
- PRBool needToEncodeAlgid = PR_FALSE;
- PK11SlotInfo *slot;
-
- result = (struct sec_pkcs7_cipher_object*)
- PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
- if (result == NULL)
- return NULL;
-
- ciphercx = NULL;
- if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
- CK_MECHANISM pbeMech, cryptoMech;
- SECItem *pbeParams;
- SEC_PKCS5KeyAndPassword *keyPwd;
-
- PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM));
- PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM));
-
- pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
- pbeParams = PK11_ParamFromAlgid(algid);
- if(!pbeParams) {
- PORT_Free(result);
- return NULL;
- }
- keyPwd = (SEC_PKCS5KeyAndPassword *)key;
- key = keyPwd->key;
-
- pbeMech.pParameter = pbeParams->data;
- pbeMech.ulParameterLen = pbeParams->len;
- if(PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech,
- keyPwd->pwitem, PR_FALSE) != CKR_OK) {
- PORT_Free(result);
- SECITEM_ZfreeItem(pbeParams, PR_TRUE);
- return NULL;
- }
- SECITEM_ZfreeItem(pbeParams, PR_TRUE);
-
- param = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
- if(!param) {
- PORT_Free(result);
- return NULL;
- }
- param->data = (unsigned char *)cryptoMech.pParameter;
- param->len = cryptoMech.ulParameterLen;
- mechanism = cryptoMech.mechanism;
- } else {
- mechanism = PK11_AlgtagToMechanism(algtag);
- param = PK11_GenerateNewParam(mechanism,key);
- if (param == NULL) {
- PORT_Free(result);
- return NULL;
- }
- needToEncodeAlgid = PR_TRUE;
- }
-
- result->pad_size = PK11_GetBlockSize(mechanism,param);
- slot = PK11_GetSlotFromKey(key);
- result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
- PK11_FreeSlot(slot);
- ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT,
- key, param);
- if (ciphercx == NULL) {
- PORT_Free (result);
- SECITEM_FreeItem(param,PR_TRUE);
- return NULL;
- }
-
- /*
- * These are placed after the CreateContextBySymKey() because some
- * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
- * Don't move it from here.
- */
- if (needToEncodeAlgid) {
- rv = PK11_ParamToAlgid(algtag,param,poolp,algid);
- if(rv != SECSuccess) {
- return NULL;
- }
- }
- SECITEM_FreeItem(param,PR_TRUE);
-
- result->cx = ciphercx;
- result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp;
- result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
- result->encrypt = PR_TRUE;
- result->pending_count = 0;
-
- return result;
-}
-
-
-/*
- * Destroy the cipher object.
- */
-static void
-sec_pkcs7_destroy_cipher (sec_PKCS7CipherObject *obj)
-{
- (* obj->destroy) (obj->cx, PR_TRUE);
- PORT_Free (obj);
-}
-
-void
-sec_PKCS7DestroyDecryptObject (sec_PKCS7CipherObject *obj)
-{
- PORT_Assert (obj != NULL);
- if (obj == NULL)
- return;
- PORT_Assert (! obj->encrypt);
- sec_pkcs7_destroy_cipher (obj);
-}
-
-void
-sec_PKCS7DestroyEncryptObject (sec_PKCS7CipherObject *obj)
-{
- PORT_Assert (obj != NULL);
- if (obj == NULL)
- return;
- PORT_Assert (obj->encrypt);
- sec_pkcs7_destroy_cipher (obj);
-}
-
-
-/*
- * XXX I think all of the following lengths should be longs instead
- * of ints, but our current crypto interface uses ints, so I did too.
- */
-
-
-/*
- * What will be the output length of the next call to decrypt?
- * Result can be used to perform memory allocations. Note that the amount
- * is exactly accurate only when not doing a block cipher or when final
- * is false, otherwise it is an upper bound on the amount because until
- * we see the data we do not know how many padding bytes there are
- * (always between 1 and bsize).
- *
- * Note that this can return zero, which does not mean that the decrypt
- * operation can be skipped! (It simply means that there are not enough
- * bytes to make up an entire block; the bytes will be reserved until
- * there are enough to encrypt/decrypt at least one block.) However,
- * if zero is returned it *does* mean that no output buffer need be
- * passed in to the subsequent decrypt operation, as no output bytes
- * will be stored.
- */
-unsigned int
-sec_PKCS7DecryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
- PRBool final)
-{
- int blocks, block_size;
-
- PORT_Assert (! obj->encrypt);
-
- block_size = obj->block_size;
-
- /*
- * If this is not a block cipher, then we always have the same
- * number of output bytes as we had input bytes.
- */
- if (block_size == 0)
- return input_len;
-
- /*
- * On the final call, we will always use up all of the pending
- * bytes plus all of the input bytes, *but*, there will be padding
- * at the end and we cannot predict how many bytes of padding we
- * will end up removing. The amount given here is actually known
- * to be at least 1 byte too long (because we know we will have
- * at least 1 byte of padding), but seemed clearer/better to me.
- */
- if (final)
- return obj->pending_count + input_len;
-
- /*
- * Okay, this amount is exactly what we will output on the
- * next cipher operation. We will always hang onto the last
- * 1 - block_size bytes for non-final operations. That is,
- * we will do as many complete blocks as we can *except* the
- * last block (complete or partial). (This is because until
- * we know we are at the end, we cannot know when to interpret
- * and removing the padding byte(s), which are guaranteed to
- * be there.)
- */
- blocks = (obj->pending_count + input_len - 1) / block_size;
- return blocks * block_size;
-}
-
-/*
- * What will be the output length of the next call to encrypt?
- * Result can be used to perform memory allocations.
- *
- * Note that this can return zero, which does not mean that the encrypt
- * operation can be skipped! (It simply means that there are not enough
- * bytes to make up an entire block; the bytes will be reserved until
- * there are enough to encrypt/decrypt at least one block.) However,
- * if zero is returned it *does* mean that no output buffer need be
- * passed in to the subsequent encrypt operation, as no output bytes
- * will be stored.
- */
-unsigned int
-sec_PKCS7EncryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
- PRBool final)
-{
- int blocks, block_size;
- int pad_size;
-
- PORT_Assert (obj->encrypt);
-
- block_size = obj->block_size;
- pad_size = obj->pad_size;
-
- /*
- * If this is not a block cipher, then we always have the same
- * number of output bytes as we had input bytes.
- */
- if (block_size == 0)
- return input_len;
-
- /*
- * On the final call, we only send out what we need for
- * remaining bytes plus the padding. (There is always padding,
- * so even if we have an exact number of blocks as input, we
- * will add another full block that is just padding.)
- */
- if (final) {
- if (pad_size == 0) {
- return obj->pending_count + input_len;
- } else {
- blocks = (obj->pending_count + input_len) / pad_size;
- blocks++;
- return blocks*pad_size;
- }
- }
-
- /*
- * Now, count the number of complete blocks of data we have.
- */
- blocks = (obj->pending_count + input_len) / block_size;
-
-
- return blocks * block_size;
-}
-
-
-/*
- * Decrypt a given length of input buffer (starting at "input" and
- * containing "input_len" bytes), placing the decrypted bytes in
- * "output" and storing the output length in "*output_len_p".
- * "obj" is the return value from sec_PKCS7CreateDecryptObject.
- * When "final" is true, this is the last of the data to be decrypted.
- *
- * This is much more complicated than it sounds when the cipher is
- * a block-type, meaning that the decryption function will only
- * operate on whole blocks. But our caller is operating stream-wise,
- * and can pass in any number of bytes. So we need to keep track
- * of block boundaries. We save excess bytes between calls in "obj".
- * We also need to determine which bytes are padding, and remove
- * them from the output. We can only do this step when we know we
- * have the final block of data. PKCS #7 specifies that the padding
- * used for a block cipher is a string of bytes, each of whose value is
- * the same as the length of the padding, and that all data is padded.
- * (Even data that starts out with an exact multiple of blocks gets
- * added to it another block, all of which is padding.)
- */
-SECStatus
-sec_PKCS7Decrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
- unsigned int *output_len_p, unsigned int max_output_len,
- const unsigned char *input, unsigned int input_len,
- PRBool final)
-{
- int blocks, bsize, pcount, padsize;
- unsigned int max_needed, ifraglen, ofraglen, output_len;
- unsigned char *pbuf;
- SECStatus rv;
-
- PORT_Assert (! obj->encrypt);
-
- /*
- * Check that we have enough room for the output. Our caller should
- * already handle this; failure is really an internal error (i.e. bug).
- */
- max_needed = sec_PKCS7DecryptLength (obj, input_len, final);
- PORT_Assert (max_output_len >= max_needed);
- if (max_output_len < max_needed) {
- /* PORT_SetError (XXX); */
- return SECFailure;
- }
-
- /*
- * hardware encryption does not like small decryption sizes here, so we
- * allow both blocking and padding.
- */
- bsize = obj->block_size;
- padsize = obj->pad_size;
-
- /*
- * When no blocking or padding work to do, we can simply call the
- * cipher function and we are done.
- */
- if (bsize == 0) {
- return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
- input, input_len);
- }
-
- pcount = obj->pending_count;
- pbuf = obj->pending_buf;
-
- output_len = 0;
-
- if (pcount) {
- /*
- * Try to fill in an entire block, starting with the bytes
- * we already have saved away.
- */
- while (input_len && pcount < bsize) {
- pbuf[pcount++] = *input++;
- input_len--;
- }
- /*
- * If we have at most a whole block and this is not our last call,
- * then we are done for now. (We do not try to decrypt a lone
- * single block because we cannot interpret the padding bytes
- * until we know we are handling the very last block of all input.)
- */
- if (input_len == 0 && !final) {
- obj->pending_count = pcount;
- if (output_len_p)
- *output_len_p = 0;
- return SECSuccess;
- }
- /*
- * Given the logic above, we expect to have a full block by now.
- * If we do not, there is something wrong, either with our own
- * logic or with (length of) the data given to us.
- */
- PORT_Assert ((padsize == 0) || (pcount % padsize) == 0);
- if ((padsize != 0) && (pcount % padsize) != 0) {
- PORT_Assert (final);
- PORT_SetError (SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
- /*
- * Decrypt the block.
- */
- rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
- pbuf, pcount);
- if (rv != SECSuccess)
- return rv;
-
- /*
- * For now anyway, all of our ciphers have the same number of
- * bytes of output as they do input. If this ever becomes untrue,
- * then sec_PKCS7DecryptLength needs to be made smarter!
- */
- PORT_Assert (ofraglen == pcount);
-
- /*
- * Account for the bytes now in output.
- */
- max_output_len -= ofraglen;
- output_len += ofraglen;
- output += ofraglen;
- }
-
- /*
- * If this is our last call, we expect to have an exact number of
- * blocks left to be decrypted; we will decrypt them all.
- *
- * If not our last call, we always save between 1 and bsize bytes
- * until next time. (We must do this because we cannot be sure
- * that none of the decrypted bytes are padding bytes until we
- * have at least another whole block of data. You cannot tell by
- * looking -- the data could be anything -- you can only tell by
- * context, knowing you are looking at the last block.) We could
- * decrypt a whole block now but it is easier if we just treat it
- * the same way we treat partial block bytes.
- */
- if (final) {
- if (padsize) {
- blocks = input_len / padsize;
- ifraglen = blocks * padsize;
- } else ifraglen = input_len;
- PORT_Assert (ifraglen == input_len);
-
- if (ifraglen != input_len) {
- PORT_SetError (SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
- } else {
- blocks = (input_len - 1) / bsize;
- ifraglen = blocks * bsize;
- PORT_Assert (ifraglen < input_len);
-
- pcount = input_len - ifraglen;
- PORT_Memcpy (pbuf, input + ifraglen, pcount);
- obj->pending_count = pcount;
- }
-
- if (ifraglen) {
- rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
- input, ifraglen);
- if (rv != SECSuccess)
- return rv;
-
- /*
- * For now anyway, all of our ciphers have the same number of
- * bytes of output as they do input. If this ever becomes untrue,
- * then sec_PKCS7DecryptLength needs to be made smarter!
- */
- PORT_Assert (ifraglen == ofraglen);
- if (ifraglen != ofraglen) {
- PORT_SetError (SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
-
- output_len += ofraglen;
- } else {
- ofraglen = 0;
- }
-
- /*
- * If we just did our very last block, "remove" the padding by
- * adjusting the output length.
- */
- if (final && (padsize != 0)) {
- unsigned int padlen = *(output + ofraglen - 1);
- PORT_Assert (padlen > 0 && padlen <= padsize);
- if (padlen == 0 || padlen > padsize) {
- PORT_SetError (SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
- output_len -= padlen;
- }
-
- PORT_Assert (output_len_p != NULL || output_len == 0);
- if (output_len_p != NULL)
- *output_len_p = output_len;
-
- return SECSuccess;
-}
-
-/*
- * Encrypt a given length of input buffer (starting at "input" and
- * containing "input_len" bytes), placing the encrypted bytes in
- * "output" and storing the output length in "*output_len_p".
- * "obj" is the return value from sec_PKCS7CreateEncryptObject.
- * When "final" is true, this is the last of the data to be encrypted.
- *
- * This is much more complicated than it sounds when the cipher is
- * a block-type, meaning that the encryption function will only
- * operate on whole blocks. But our caller is operating stream-wise,
- * and can pass in any number of bytes. So we need to keep track
- * of block boundaries. We save excess bytes between calls in "obj".
- * We also need to add padding bytes at the end. PKCS #7 specifies
- * that the padding used for a block cipher is a string of bytes,
- * each of whose value is the same as the length of the padding,
- * and that all data is padded. (Even data that starts out with
- * an exact multiple of blocks gets added to it another block,
- * all of which is padding.)
- *
- * XXX I would kind of like to combine this with the function above
- * which does decryption, since they have a lot in common. But the
- * tricky parts about padding and filling blocks would be much
- * harder to read that way, so I left them separate. At least for
- * now until it is clear that they are right.
- */
-SECStatus
-sec_PKCS7Encrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
- unsigned int *output_len_p, unsigned int max_output_len,
- const unsigned char *input, unsigned int input_len,
- PRBool final)
-{
- int blocks, bsize, padlen, pcount, padsize;
- unsigned int max_needed, ifraglen, ofraglen, output_len;
- unsigned char *pbuf;
- SECStatus rv;
-
- PORT_Assert (obj->encrypt);
-
- /*
- * Check that we have enough room for the output. Our caller should
- * already handle this; failure is really an internal error (i.e. bug).
- */
- max_needed = sec_PKCS7EncryptLength (obj, input_len, final);
- PORT_Assert (max_output_len >= max_needed);
- if (max_output_len < max_needed) {
- /* PORT_SetError (XXX); */
- return SECFailure;
- }
-
- bsize = obj->block_size;
- padsize = obj->pad_size;
-
- /*
- * When no blocking and padding work to do, we can simply call the
- * cipher function and we are done.
- */
- if (bsize == 0) {
- return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
- input, input_len);
- }
-
- pcount = obj->pending_count;
- pbuf = obj->pending_buf;
-
- output_len = 0;
-
- if (pcount) {
- /*
- * Try to fill in an entire block, starting with the bytes
- * we already have saved away.
- */
- while (input_len && pcount < bsize) {
- pbuf[pcount++] = *input++;
- input_len--;
- }
- /*
- * If we do not have a full block and we know we will be
- * called again, then we are done for now.
- */
- if (pcount < bsize && !final) {
- obj->pending_count = pcount;
- if (output_len_p != NULL)
- *output_len_p = 0;
- return SECSuccess;
- }
- /*
- * If we have a whole block available, encrypt it.
- */
- if ((padsize == 0) || (pcount % padsize) == 0) {
- rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
- pbuf, pcount);
- if (rv != SECSuccess)
- return rv;
-
- /*
- * For now anyway, all of our ciphers have the same number of
- * bytes of output as they do input. If this ever becomes untrue,
- * then sec_PKCS7EncryptLength needs to be made smarter!
- */
- PORT_Assert (ofraglen == pcount);
-
- /*
- * Account for the bytes now in output.
- */
- max_output_len -= ofraglen;
- output_len += ofraglen;
- output += ofraglen;
-
- pcount = 0;
- }
- }
-
- if (input_len) {
- PORT_Assert (pcount == 0);
-
- blocks = input_len / bsize;
- ifraglen = blocks * bsize;
-
- if (ifraglen) {
- rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
- input, ifraglen);
- if (rv != SECSuccess)
- return rv;
-
- /*
- * For now anyway, all of our ciphers have the same number of
- * bytes of output as they do input. If this ever becomes untrue,
- * then sec_PKCS7EncryptLength needs to be made smarter!
- */
- PORT_Assert (ifraglen == ofraglen);
-
- max_output_len -= ofraglen;
- output_len += ofraglen;
- output += ofraglen;
- }
-
- pcount = input_len - ifraglen;
- PORT_Assert (pcount < bsize);
- if (pcount)
- PORT_Memcpy (pbuf, input + ifraglen, pcount);
- }
-
- if (final) {
- padlen = padsize - (pcount % padsize);
- PORT_Memset (pbuf + pcount, padlen, padlen);
- rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
- pbuf, pcount+padlen);
- if (rv != SECSuccess)
- return rv;
-
- /*
- * For now anyway, all of our ciphers have the same number of
- * bytes of output as they do input. If this ever becomes untrue,
- * then sec_PKCS7EncryptLength needs to be made smarter!
- */
- PORT_Assert (ofraglen == (pcount+padlen));
- output_len += ofraglen;
- } else {
- obj->pending_count = pcount;
- }
-
- PORT_Assert (output_len_p != NULL || output_len == 0);
- if (output_len_p != NULL)
- *output_len_p = output_len;
-
- return SECSuccess;
-}
-
-/*
- * End of cipher stuff.
- * -------------------------------------------------------------------
- */
-
-
-/*
- * -------------------------------------------------------------------
- * XXX The following Attribute stuff really belongs elsewhere.
- * The Attribute type is *not* part of pkcs7 but rather X.501.
- * But for now, since PKCS7 is the only customer of attributes,
- * we define them here. Once there is a use outside of PKCS7,
- * then change the attribute types and functions from internal
- * to external naming convention, and move them elsewhere!
- */
-
-/*
- * Look through a set of attributes and find one that matches the
- * specified object ID. If "only" is true, then make sure that
- * there is not more than one attribute of the same type. Otherwise,
- * just return the first one found. (XXX Does anybody really want
- * that first-found behavior? It was like that when I found it...)
- */
-SEC_PKCS7Attribute *
-sec_PKCS7FindAttribute (SEC_PKCS7Attribute **attrs, SECOidTag oidtag,
- PRBool only)
-{
- SECOidData *oid;
- SEC_PKCS7Attribute *attr1, *attr2;
-
- if (attrs == NULL)
- return NULL;
-
- oid = SECOID_FindOIDByTag(oidtag);
- if (oid == NULL)
- return NULL;
-
- while ((attr1 = *attrs++) != NULL) {
- if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data,
- oid->oid.data,
- oid->oid.len) == 0)
- break;
- }
-
- if (attr1 == NULL)
- return NULL;
-
- if (!only)
- return attr1;
-
- while ((attr2 = *attrs++) != NULL) {
- if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data,
- oid->oid.data,
- oid->oid.len) == 0)
- break;
- }
-
- if (attr2 != NULL)
- return NULL;
-
- return attr1;
-}
-
-
-/*
- * Return the single attribute value, doing some sanity checking first:
- * - Multiple values are *not* expected.
- * - Empty values are *not* expected.
- */
-SECItem *
-sec_PKCS7AttributeValue(SEC_PKCS7Attribute *attr)
-{
- SECItem *value;
-
- if (attr == NULL)
- return NULL;
-
- value = attr->values[0];
-
- if (value == NULL || value->data == NULL || value->len == 0)
- return NULL;
-
- if (attr->values[1] != NULL)
- return NULL;
-
- return value;
-}
-
-static const SEC_ASN1Template *
-sec_attr_choose_attr_value_template(void *src_or_dest, PRBool encoding)
-{
- const SEC_ASN1Template *theTemplate;
- SEC_PKCS7Attribute *attribute;
- SECOidData *oiddata;
- PRBool encoded;
-
- PORT_Assert (src_or_dest != NULL);
- if (src_or_dest == NULL)
- return NULL;
-
- attribute = (SEC_PKCS7Attribute*)src_or_dest;
-
- if (encoding && attribute->encoded)
- return SEC_AnyTemplate;
-
- oiddata = attribute->typeTag;
- if (oiddata == NULL) {
- oiddata = SECOID_FindOID(&attribute->type);
- attribute->typeTag = oiddata;
- }
-
- if (oiddata == NULL) {
- encoded = PR_TRUE;
- theTemplate = SEC_AnyTemplate;
- } else {
- switch (oiddata->offset) {
- default:
- encoded = PR_TRUE;
- theTemplate = SEC_AnyTemplate;
- break;
- case SEC_OID_PKCS9_EMAIL_ADDRESS:
- case SEC_OID_RFC1274_MAIL:
- case SEC_OID_PKCS9_UNSTRUCTURED_NAME:
- encoded = PR_FALSE;
- theTemplate = SEC_IA5StringTemplate;
- break;
- case SEC_OID_PKCS9_CONTENT_TYPE:
- encoded = PR_FALSE;
- theTemplate = SEC_ObjectIDTemplate;
- break;
- case SEC_OID_PKCS9_MESSAGE_DIGEST:
- encoded = PR_FALSE;
- theTemplate = SEC_OctetStringTemplate;
- break;
- case SEC_OID_PKCS9_SIGNING_TIME:
- encoded = PR_FALSE;
- theTemplate = SEC_UTCTimeTemplate;
- break;
- /* XXX Want other types here, too */
- }
- }
-
- if (encoding) {
- /*
- * If we are encoding and we think we have an already-encoded value,
- * then the code which initialized this attribute should have set
- * the "encoded" property to true (and we would have returned early,
- * up above). No devastating error, but that code should be fixed.
- * (It could indicate that the resulting encoded bytes are wrong.)
- */
- PORT_Assert (!encoded);
- } else {
- /*
- * We are decoding; record whether the resulting value is
- * still encoded or not.
- */
- attribute->encoded = encoded;
- }
- return theTemplate;
-}
-
-static SEC_ChooseASN1TemplateFunc sec_attr_chooser
- = sec_attr_choose_attr_value_template;
-
-static const SEC_ASN1Template sec_pkcs7_attribute_template[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7Attribute) },
- { SEC_ASN1_OBJECT_ID,
- offsetof(SEC_PKCS7Attribute,type) },
- { SEC_ASN1_DYNAMIC | SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7Attribute,values),
- &sec_attr_chooser },
- { 0 }
-};
-
-static const SEC_ASN1Template sec_pkcs7_set_of_attribute_template[] = {
- { SEC_ASN1_SET_OF, 0, sec_pkcs7_attribute_template },
-};
-
-/*
- * If you are wondering why this routine does not reorder the attributes
- * first, and might be tempted to make it do so, see the comment by the
- * call to ReorderAttributes in p7encode.c. (Or, see who else calls this
- * and think long and hard about the implications of making it always
- * do the reordering.)
- */
-SECItem *
-sec_PKCS7EncodeAttributes (PRArenaPool *poolp, SECItem *dest, void *src)
-{
- return SEC_ASN1EncodeItem (poolp, dest, src,
- sec_pkcs7_set_of_attribute_template);
-}
-
-/*
- * Make sure that the order of the attributes guarantees valid DER
- * (which must be in lexigraphically ascending order for a SET OF);
- * if reordering is necessary it will be done in place (in attrs).
- */
-SECStatus
-sec_PKCS7ReorderAttributes (SEC_PKCS7Attribute **attrs)
-{
- PRArenaPool *poolp;
- int num_attrs, i, j, pass, besti;
- SECItem **enc_attrs;
- SEC_PKCS7Attribute **new_attrs;
-
- /*
- * I think we should not be called with NULL. But if we are,
- * call it a success anyway, because the order *is* okay.
- */
- PORT_Assert (attrs != NULL);
- if (attrs == NULL)
- return SECSuccess;
-
- /*
- * Count how many attributes we are dealing with here.
- */
- num_attrs = 0;
- while (attrs[num_attrs] != NULL)
- num_attrs++;
-
- /*
- * Again, I think we should have some attributes here.
- * But if we do not, or if there is only one, then call it
- * a success because it also already has a fine order.
- */
- PORT_Assert (num_attrs);
- if (num_attrs == 0 || num_attrs == 1)
- return SECSuccess;
-
- /*
- * Allocate an arena for us to work with, so it is easy to
- * clean up all of the memory (fairly small pieces, really).
- */
- poolp = PORT_NewArena (1024); /* XXX what is right value? */
- if (poolp == NULL)
- return SECFailure; /* no memory; nothing we can do... */
-
- /*
- * Allocate arrays to hold the individual encodings which we will use
- * for comparisons and the reordered attributes as they are sorted.
- */
- enc_attrs=(SECItem**)PORT_ArenaZAlloc(poolp, num_attrs*sizeof(SECItem *));
- new_attrs = (SEC_PKCS7Attribute**)PORT_ArenaZAlloc (poolp,
- num_attrs * sizeof(SEC_PKCS7Attribute *));
- if (enc_attrs == NULL || new_attrs == NULL) {
- PORT_FreeArena (poolp, PR_FALSE);
- return SECFailure;
- }
-
- /*
- * DER encode each individual attribute.
- */
- for (i = 0; i < num_attrs; i++) {
- enc_attrs[i] = SEC_ASN1EncodeItem (poolp, NULL, attrs[i],
- sec_pkcs7_attribute_template);
- if (enc_attrs[i] == NULL) {
- PORT_FreeArena (poolp, PR_FALSE);
- return SECFailure;
- }
- }
-
- /*
- * Now compare and sort them; this is not the most efficient sorting
- * method, but it is just fine for the problem at hand, because the
- * number of attributes is (always) going to be small.
- */
- for (pass = 0; pass < num_attrs; pass++) {
- /*
- * Find the first not-yet-accepted attribute. (Once one is
- * sorted into the other array, it is cleared from enc_attrs.)
- */
- for (i = 0; i < num_attrs; i++) {
- if (enc_attrs[i] != NULL)
- break;
- }
- PORT_Assert (i < num_attrs);
- besti = i;
-
- /*
- * Find the lowest (lexigraphically) encoding. One that is
- * shorter than all the rest is known to be "less" because each
- * attribute is of the same type (a SEQUENCE) and so thus the
- * first octet of each is the same, and the second octet is
- * the length (or the length of the length with the high bit
- * set, followed by the length, which also works out to always
- * order the shorter first). Two (or more) that have the
- * same length need to be compared byte by byte until a mismatch
- * is found.
- */
- for (i = besti + 1; i < num_attrs; i++) {
- if (enc_attrs[i] == NULL) /* slot already handled */
- continue;
-
- if (enc_attrs[i]->len != enc_attrs[besti]->len) {
- if (enc_attrs[i]->len < enc_attrs[besti]->len)
- besti = i;
- continue;
- }
-
- for (j = 0; j < enc_attrs[i]->len; j++) {
- if (enc_attrs[i]->data[j] < enc_attrs[besti]->data[j]) {
- besti = i;
- break;
- }
- }
-
- /*
- * For this not to be true, we would have to have encountered
- * two *identical* attributes, which I think we should not see.
- * So assert if it happens, but even if it does, let it go
- * through; the ordering of the two does not matter.
- */
- PORT_Assert (j < enc_attrs[i]->len);
- }
-
- /*
- * Now we have found the next-lowest one; copy it over and
- * remove it from enc_attrs.
- */
- new_attrs[pass] = attrs[besti];
- enc_attrs[besti] = NULL;
- }
-
- /*
- * Now new_attrs has the attributes in the order we want;
- * copy them back into the attrs array we started with.
- */
- for (i = 0; i < num_attrs; i++)
- attrs[i] = new_attrs[i];
-
- PORT_FreeArena (poolp, PR_FALSE);
- return SECSuccess;
-}
-
-/*
- * End of attribute stuff.
- * -------------------------------------------------------------------
- */
-
-
-/*
- * Templates and stuff. Keep these at the end of the file.
- */
-
-/* forward declaration */
-static const SEC_ASN1Template *
-sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding);
-
-static SEC_ChooseASN1TemplateFunc sec_pkcs7_chooser
- = sec_pkcs7_choose_content_template;
-
-const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7ContentInfo) },
- { SEC_ASN1_OBJECT_ID,
- offsetof(SEC_PKCS7ContentInfo,contentType) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM
- | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SEC_PKCS7ContentInfo,content),
- &sec_pkcs7_chooser },
- { 0 }
-};
-
-/* XXX These names should change from external to internal convention. */
-
-static const SEC_ASN1Template SEC_PKCS7SignerInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7SignerInfo) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7SignerInfo,version) },
- { SEC_ASN1_POINTER,
- offsetof(SEC_PKCS7SignerInfo,issuerAndSN),
- CERT_IssuerAndSNTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7SignerInfo,digestAlg),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SEC_PKCS7SignerInfo,authAttr),
- sec_pkcs7_set_of_attribute_template },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7SignerInfo,digestEncAlg),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7SignerInfo,encDigest) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
- offsetof(SEC_PKCS7SignerInfo,unAuthAttr),
- sec_pkcs7_set_of_attribute_template },
- { 0 }
-};
-
-static const SEC_ASN1Template SEC_PKCS7SignedDataTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7SignedData) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7SignedData,version) },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7SignedData,digestAlgorithms),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7SignedData,contentInfo),
- sec_PKCS7ContentInfoTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SEC_PKCS7SignedData,rawCerts),
- SEC_SetOfAnyTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
- offsetof(SEC_PKCS7SignedData,crls),
- CERT_SetOfSignedCrlTemplate },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7SignedData,signerInfos),
- SEC_PKCS7SignerInfoTemplate },
- { 0 }
-};
-
-static const SEC_ASN1Template SEC_PointerToPKCS7SignedDataTemplate[] = {
- { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedDataTemplate }
-};
-
-static const SEC_ASN1Template SEC_PKCS7RecipientInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7RecipientInfo) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7RecipientInfo,version) },
- { SEC_ASN1_POINTER,
- offsetof(SEC_PKCS7RecipientInfo,issuerAndSN),
- CERT_IssuerAndSNTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7RecipientInfo,keyEncAlg),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7RecipientInfo,encKey) },
- { 0 }
-};
-
-static const SEC_ASN1Template SEC_PKCS7EncryptedContentInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7EncryptedContentInfo) },
- { SEC_ASN1_OBJECT_ID,
- offsetof(SEC_PKCS7EncryptedContentInfo,contentType) },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7EncryptedContentInfo,contentEncAlg),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_MAY_STREAM | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SEC_PKCS7EncryptedContentInfo,encContent),
- SEC_OctetStringTemplate },
- { 0 }
-};
-
-static const SEC_ASN1Template SEC_PKCS7EnvelopedDataTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7EnvelopedData) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7EnvelopedData,version) },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7EnvelopedData,recipientInfos),
- SEC_PKCS7RecipientInfoTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7EnvelopedData,encContentInfo),
- SEC_PKCS7EncryptedContentInfoTemplate },
- { 0 }
-};
-
-static const SEC_ASN1Template SEC_PointerToPKCS7EnvelopedDataTemplate[] = {
- { SEC_ASN1_POINTER, 0, SEC_PKCS7EnvelopedDataTemplate }
-};
-
-static const SEC_ASN1Template SEC_PKCS7SignedAndEnvelopedDataTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7SignedAndEnvelopedData) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,version) },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,recipientInfos),
- SEC_PKCS7RecipientInfoTemplate },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,digestAlgorithms),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,encContentInfo),
- SEC_PKCS7EncryptedContentInfoTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,rawCerts),
- SEC_SetOfAnyTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,crls),
- CERT_SetOfSignedCrlTemplate },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,signerInfos),
- SEC_PKCS7SignerInfoTemplate },
- { 0 }
-};
-
-static const SEC_ASN1Template
-SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate[] = {
- { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedAndEnvelopedDataTemplate }
-};
-
-static const SEC_ASN1Template SEC_PKCS7DigestedDataTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7DigestedData) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7DigestedData,version) },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7DigestedData,digestAlg),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7DigestedData,contentInfo),
- sec_PKCS7ContentInfoTemplate },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7DigestedData,digest) },
- { 0 }
-};
-
-static const SEC_ASN1Template SEC_PointerToPKCS7DigestedDataTemplate[] = {
- { SEC_ASN1_POINTER, 0, SEC_PKCS7DigestedDataTemplate }
-};
-
-static const SEC_ASN1Template SEC_PKCS7EncryptedDataTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7EncryptedData) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7EncryptedData,version) },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7EncryptedData,encContentInfo),
- SEC_PKCS7EncryptedContentInfoTemplate },
- { 0 }
-};
-
-static const SEC_ASN1Template SEC_PointerToPKCS7EncryptedDataTemplate[] = {
- { SEC_ASN1_POINTER, 0, SEC_PKCS7EncryptedDataTemplate }
-};
-
-const SEC_ASN1Template SEC_SMIMEKEAParamTemplateSkipjack[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
- { SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
- { 0 }
-};
-
-const SEC_ASN1Template SEC_SMIMEKEAParamTemplateNoSkipjack[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
- { SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
- { SEC_ASN1_OCTET_STRING | SEC_ASN1_OPTIONAL ,
- offsetof(SEC_PKCS7SMIMEKEAParameters,nonSkipjackIV) },
- { 0 }
-};
-
-const SEC_ASN1Template SEC_SMIMEKEAParamTemplateAllParams[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
- { SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
- { SEC_ASN1_OCTET_STRING | SEC_ASN1_OPTIONAL ,
- offsetof(SEC_PKCS7SMIMEKEAParameters,nonSkipjackIV) },
- { SEC_ASN1_OCTET_STRING | SEC_ASN1_OPTIONAL ,
- offsetof(SEC_PKCS7SMIMEKEAParameters,bulkKeySize) },
- { 0 }
-};
-
-const SEC_ASN1Template*
-sec_pkcs7_get_kea_template(SECKEATemplateSelector whichTemplate)
-{
- const SEC_ASN1Template *returnVal = NULL;
-
- switch(whichTemplate)
- {
- case SECKEAUsesNonSkipjack:
- returnVal = SEC_SMIMEKEAParamTemplateNoSkipjack;
- break;
- case SECKEAUsesSkipjack:
- returnVal = SEC_SMIMEKEAParamTemplateSkipjack;
- break;
- case SECKEAUsesNonSkipjackWithPaddedEncKey:
- default:
- returnVal = SEC_SMIMEKEAParamTemplateAllParams;
- break;
- }
- return returnVal;
-}
-
-static const SEC_ASN1Template *
-sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding)
-{
- const SEC_ASN1Template *theTemplate;
- SEC_PKCS7ContentInfo *cinfo;
- SECOidTag kind;
-
- PORT_Assert (src_or_dest != NULL);
- if (src_or_dest == NULL)
- return NULL;
-
- cinfo = (SEC_PKCS7ContentInfo*)src_or_dest;
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- default:
- theTemplate = SEC_PointerToAnyTemplate;
- break;
- case SEC_OID_PKCS7_DATA:
- theTemplate = SEC_PointerToOctetStringTemplate;
- break;
- case SEC_OID_PKCS7_SIGNED_DATA:
- theTemplate = SEC_PointerToPKCS7SignedDataTemplate;
- break;
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- theTemplate = SEC_PointerToPKCS7EnvelopedDataTemplate;
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- theTemplate = SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate;
- break;
- case SEC_OID_PKCS7_DIGESTED_DATA:
- theTemplate = SEC_PointerToPKCS7DigestedDataTemplate;
- break;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- theTemplate = SEC_PointerToPKCS7EncryptedDataTemplate;
- break;
- }
- return theTemplate;
-}
-
-/*
- * End of templates. Do not add stuff after this; put new code
- * up above the start of the template definitions.
- */
diff --git a/security/nss/lib/pkcs7/p7local.h b/security/nss/lib/pkcs7/p7local.h
deleted file mode 100644
index 80640c930..000000000
--- a/security/nss/lib/pkcs7/p7local.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * Support routines for PKCS7 implementation, none of which are exported.
- * This file should only contain things that are needed by both the
- * encoding/creation side *and* the decoding/decryption side. Anything
- * else should just be static routines in the appropriate file.
- *
- * Do not export this file! If something in here is really needed outside
- * of pkcs7 code, first try to add a PKCS7 interface which will do it for
- * you. If that has a problem, then just move out what you need, changing
- * its name as appropriate!
- *
- * $Id$
- */
-
-#ifndef _P7LOCAL_H_
-#define _P7LOCAL_H_
-
-#include "secpkcs7.h"
-#include "secasn1t.h"
-
-extern const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[];
-
-/* opaque objects */
-typedef struct sec_pkcs7_cipher_object sec_PKCS7CipherObject;
-
-
-/************************************************************************/
-SEC_BEGIN_PROTOS
-
-/*
- * Look through a set of attributes and find one that matches the
- * specified object ID. If "only" is true, then make sure that
- * there is not more than one attribute of the same type. Otherwise,
- * just return the first one found. (XXX Does anybody really want
- * that first-found behavior? It was like that when I found it...)
- */
-extern SEC_PKCS7Attribute *sec_PKCS7FindAttribute (SEC_PKCS7Attribute **attrs,
- SECOidTag oidtag,
- PRBool only);
-/*
- * Return the single attribute value, doing some sanity checking first:
- * - Multiple values are *not* expected.
- * - Empty values are *not* expected.
- */
-extern SECItem *sec_PKCS7AttributeValue (SEC_PKCS7Attribute *attr);
-
-/*
- * Encode a set of attributes (found in "src").
- */
-extern SECItem *sec_PKCS7EncodeAttributes (PRArenaPool *poolp,
- SECItem *dest, void *src);
-
-/*
- * Make sure that the order of the attributes guarantees valid DER
- * (which must be in lexigraphically ascending order for a SET OF);
- * if reordering is necessary it will be done in place (in attrs).
- */
-extern SECStatus sec_PKCS7ReorderAttributes (SEC_PKCS7Attribute **attrs);
-
-
-/*
- * Create a context for decrypting, based on the given key and algorithm.
- */
-extern sec_PKCS7CipherObject *
-sec_PKCS7CreateDecryptObject (PK11SymKey *key, SECAlgorithmID *algid);
-
-/*
- * Create a context for encrypting, based on the given key and algorithm,
- * and fill in the algorithm id.
- */
-extern sec_PKCS7CipherObject *
-sec_PKCS7CreateEncryptObject (PRArenaPool *poolp, PK11SymKey *key,
- SECOidTag algtag, SECAlgorithmID *algid);
-
-/*
- * Destroy the given decryption or encryption object.
- */
-extern void sec_PKCS7DestroyDecryptObject (sec_PKCS7CipherObject *obj);
-extern void sec_PKCS7DestroyEncryptObject (sec_PKCS7CipherObject *obj);
-
-/*
- * What will be the output length of the next call to encrypt/decrypt?
- * Result can be used to perform memory allocations. Note that the amount
- * is exactly accurate only when not doing a block cipher or when final
- * is false, otherwise it is an upper bound on the amount because until
- * we see the data we do not know how many padding bytes there are
- * (always between 1 and the cipher block size).
- *
- * Note that this can return zero, which does not mean that the cipher
- * operation can be skipped! (It simply means that there are not enough
- * bytes to make up an entire block; the bytes will be reserved until
- * there are enough to encrypt/decrypt at least one block.) However,
- * if zero is returned it *does* mean that no output buffer need be
- * passed in to the subsequent cipher operation, as no output bytes
- * will be stored.
- */
-extern unsigned int sec_PKCS7DecryptLength (sec_PKCS7CipherObject *obj,
- unsigned int input_len,
- PRBool final);
-extern unsigned int sec_PKCS7EncryptLength (sec_PKCS7CipherObject *obj,
- unsigned int input_len,
- PRBool final);
-
-/*
- * Decrypt a given length of input buffer (starting at "input" and
- * containing "input_len" bytes), placing the decrypted bytes in
- * "output" and storing the output length in "*output_len_p".
- * "obj" is the return value from sec_PKCS7CreateDecryptObject.
- * When "final" is true, this is the last of the data to be decrypted.
- */
-extern SECStatus sec_PKCS7Decrypt (sec_PKCS7CipherObject *obj,
- unsigned char *output,
- unsigned int *output_len_p,
- unsigned int max_output_len,
- const unsigned char *input,
- unsigned int input_len,
- PRBool final);
-
-/*
- * Encrypt a given length of input buffer (starting at "input" and
- * containing "input_len" bytes), placing the encrypted bytes in
- * "output" and storing the output length in "*output_len_p".
- * "obj" is the return value from sec_PKCS7CreateEncryptObject.
- * When "final" is true, this is the last of the data to be encrypted.
- */
-extern SECStatus sec_PKCS7Encrypt (sec_PKCS7CipherObject *obj,
- unsigned char *output,
- unsigned int *output_len_p,
- unsigned int max_output_len,
- const unsigned char *input,
- unsigned int input_len,
- PRBool final);
-
-/* return the correct kea template based on the template selector. skipjack
- * does not have the extra IV.
- */
-const SEC_ASN1Template *
-sec_pkcs7_get_kea_template(SECKEATemplateSelector whichTemplate);
-
-/************************************************************************/
-SEC_END_PROTOS
-
-#endif /* _P7LOCAL_H_ */
diff --git a/security/nss/lib/pkcs7/pkcs7t.h b/security/nss/lib/pkcs7/pkcs7t.h
deleted file mode 100644
index 73b23014d..000000000
--- a/security/nss/lib/pkcs7/pkcs7t.h
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * Header for pkcs7 types.
- *
- * $Id$
- */
-
-#ifndef _PKCS7T_H_
-#define _PKCS7T_H_
-
-#include "plarena.h"
-
-#include "seccomon.h"
-#include "secoidt.h"
-#include "certt.h"
-#include "secmodt.h"
-
-/* Opaque objects */
-typedef struct SEC_PKCS7DecoderContextStr SEC_PKCS7DecoderContext;
-typedef struct SEC_PKCS7EncoderContextStr SEC_PKCS7EncoderContext;
-
-/* Non-opaque objects. NOTE, though: I want them to be treated as
- * opaque as much as possible. If I could hide them completely,
- * I would. (I tried, but ran into trouble that was taking me too
- * much time to get out of.) I still intend to try to do so.
- * In fact, the only type that "outsiders" should even *name* is
- * SEC_PKCS7ContentInfo, and they should not reference its fields.
- */
-/* rjr: PKCS #11 cert handling (pk11cert.c) does use SEC_PKCS7RecipientInfo's.
- * This is because when we search the recipient list for the cert and key we
- * want, we need to invert the order of the loops we used to have. The old
- * loops were:
- *
- * For each recipient {
- * find_cert = PK11_Find_AllCert(recipient->issuerSN);
- * [which unrolls to... ]
- * For each slot {
- * Log into slot;
- * search slot for cert;
- * }
- * }
- *
- * the new loop searchs all the recipients at once on a slot. this allows
- * PKCS #11 to order slots in such a way that logout slots don't get checked
- * if we can find the cert on a logged in slot. This eliminates lots of
- * spurious password prompts when smart cards are installed... so why this
- * comment? If you make SEC_PKCS7RecipientInfo completely opaque, you need
- * to provide a non-opaque list of issuerSN's (the only field PKCS#11 needs
- * and fix up pk11cert.c first. NOTE: Only S/MIME calls this special PKCS #11
- * function.
- */
-typedef struct SEC_PKCS7ContentInfoStr SEC_PKCS7ContentInfo;
-typedef struct SEC_PKCS7SignedDataStr SEC_PKCS7SignedData;
-typedef struct SEC_PKCS7EncryptedContentInfoStr SEC_PKCS7EncryptedContentInfo;
-typedef struct SEC_PKCS7EnvelopedDataStr SEC_PKCS7EnvelopedData;
-typedef struct SEC_PKCS7SignedAndEnvelopedDataStr
- SEC_PKCS7SignedAndEnvelopedData;
-typedef struct SEC_PKCS7SignerInfoStr SEC_PKCS7SignerInfo;
-typedef struct SEC_PKCS7RecipientInfoStr SEC_PKCS7RecipientInfo;
-typedef struct SEC_PKCS7DigestedDataStr SEC_PKCS7DigestedData;
-typedef struct SEC_PKCS7EncryptedDataStr SEC_PKCS7EncryptedData;
-typedef struct SEC_PKCS7SMIMEKEAParametersStr SEC_PKCS7SMIMEKEAParameters;
-/*
- * The following is not actually a PKCS7 type, but for now it is only
- * used by PKCS7, so we have adopted it. If someone else *ever* needs
- * it, its name should be changed and it should be moved out of here.
- * Do not dare to use it without doing so!
- */
-typedef struct SEC_PKCS7AttributeStr SEC_PKCS7Attribute;
-
-
-struct SEC_PKCS7ContentInfoStr {
- PRArenaPool *poolp; /* local; not part of encoding */
- PRBool created; /* local; not part of encoding */
- int refCount; /* local; not part of encoding */
- SECOidData *contentTypeTag; /* local; not part of encoding */
- SECKEYGetPasswordKey pwfn; /* local; not part of encoding */
- void *pwfn_arg; /* local; not part of encoding */
- SECItem contentType;
- union {
- SECItem *data;
- SEC_PKCS7DigestedData *digestedData;
- SEC_PKCS7EncryptedData *encryptedData;
- SEC_PKCS7EnvelopedData *envelopedData;
- SEC_PKCS7SignedData *signedData;
- SEC_PKCS7SignedAndEnvelopedData *signedAndEnvelopedData;
- } content;
-};
-
-struct SEC_PKCS7SignedDataStr {
- SECItem version;
- SECAlgorithmID **digestAlgorithms;
- SEC_PKCS7ContentInfo contentInfo;
- SECItem **rawCerts;
- CERTSignedCrl **crls;
- SEC_PKCS7SignerInfo **signerInfos;
- SECItem **digests; /* local; not part of encoding */
- CERTCertificate **certs; /* local; not part of encoding */
- CERTCertificateList **certLists; /* local; not part of encoding */
-};
-#define SEC_PKCS7_SIGNED_DATA_VERSION 1 /* what we *create* */
-
-struct SEC_PKCS7EncryptedContentInfoStr {
- SECOidData *contentTypeTag; /* local; not part of encoding */
- SECItem contentType;
- SECAlgorithmID contentEncAlg;
- SECItem encContent;
- SECItem plainContent; /* local; not part of encoding */
- /* bytes not encrypted, but encoded */
- int keysize; /* local; not part of encoding */
- /* size of bulk encryption key
- * (only used by creation code) */
- SECOidTag encalg; /* local; not part of encoding */
- /* oid tag of encryption algorithm
- * (only used by creation code) */
-};
-
-struct SEC_PKCS7EnvelopedDataStr {
- SECItem version;
- SEC_PKCS7RecipientInfo **recipientInfos;
- SEC_PKCS7EncryptedContentInfo encContentInfo;
-};
-#define SEC_PKCS7_ENVELOPED_DATA_VERSION 0 /* what we *create* */
-
-struct SEC_PKCS7SignedAndEnvelopedDataStr {
- SECItem version;
- SEC_PKCS7RecipientInfo **recipientInfos;
- SECAlgorithmID **digestAlgorithms;
- SEC_PKCS7EncryptedContentInfo encContentInfo;
- SECItem **rawCerts;
- CERTSignedCrl **crls;
- SEC_PKCS7SignerInfo **signerInfos;
- SECItem **digests; /* local; not part of encoding */
- CERTCertificate **certs; /* local; not part of encoding */
- CERTCertificateList **certLists; /* local; not part of encoding */
- PK11SymKey *sigKey; /* local; not part of encoding */
-};
-#define SEC_PKCS7_SIGNED_AND_ENVELOPED_DATA_VERSION 1 /* what we *create* */
-
-struct SEC_PKCS7SignerInfoStr {
- SECItem version;
- CERTIssuerAndSN *issuerAndSN;
- SECAlgorithmID digestAlg;
- SEC_PKCS7Attribute **authAttr;
- SECAlgorithmID digestEncAlg;
- SECItem encDigest;
- SEC_PKCS7Attribute **unAuthAttr;
- CERTCertificate *cert; /* local; not part of encoding */
- CERTCertificateList *certList; /* local; not part of encoding */
-};
-#define SEC_PKCS7_SIGNER_INFO_VERSION 1 /* what we *create* */
-
-struct SEC_PKCS7RecipientInfoStr {
- SECItem version;
- CERTIssuerAndSN *issuerAndSN;
- SECAlgorithmID keyEncAlg;
- SECItem encKey;
- CERTCertificate *cert; /* local; not part of encoding */
-};
-#define SEC_PKCS7_RECIPIENT_INFO_VERSION 0 /* what we *create* */
-
-struct SEC_PKCS7DigestedDataStr {
- SECItem version;
- SECAlgorithmID digestAlg;
- SEC_PKCS7ContentInfo contentInfo;
- SECItem digest;
-};
-#define SEC_PKCS7_DIGESTED_DATA_VERSION 0 /* what we *create* */
-
-struct SEC_PKCS7EncryptedDataStr {
- SECItem version;
- SEC_PKCS7EncryptedContentInfo encContentInfo;
-};
-#define SEC_PKCS7_ENCRYPTED_DATA_VERSION 0 /* what we *create* */
-
-/*
- * See comment above about this type not really belonging to PKCS7.
- */
-struct SEC_PKCS7AttributeStr {
- /* The following fields make up an encoded Attribute: */
- SECItem type;
- SECItem **values; /* data may or may not be encoded */
- /* The following fields are not part of an encoded Attribute: */
- SECOidData *typeTag;
- PRBool encoded; /* when true, values are encoded */
-};
-
-/* An enumerated type used to select templates based on the encryption
- scenario and data specifics. */
-typedef enum
-{
- SECKEAUsesSkipjack,
- SECKEAUsesNonSkipjack,
- SECKEAUsesNonSkipjackWithPaddedEncKey
-} SECKEATemplateSelector;
-
-/* ### mwelch - S/MIME KEA parameters. These don't really fit here,
- but I cannot think of a more appropriate place at this time. */
-struct SEC_PKCS7SMIMEKEAParametersStr {
- SECItem originatorKEAKey; /* sender KEA key (encrypted?) */
- SECItem originatorRA; /* random number generated by sender */
- SECItem nonSkipjackIV; /* init'n vector for SkipjackCBC64
- decryption of KEA key if Skipjack
- is not the bulk algorithm used on
- the message */
- SECItem bulkKeySize; /* if Skipjack is not the bulk
- algorithm used on the message,
- and the size of the bulk encryption
- key is not the same as that of
- originatorKEAKey (due to padding
- perhaps), this field will contain
- the real size of the bulk encryption
- key. */
-};
-
-/*
- * Type of function passed to SEC_PKCS7Decode or SEC_PKCS7DecoderStart.
- * If specified, this is where the content bytes (only) will be "sent"
- * as they are recovered during the decoding.
- *
- * XXX Should just combine this with SEC_PKCS7EncoderContentCallback type
- * and use a simpler, common name.
- */
-typedef void (* SEC_PKCS7DecoderContentCallback)(void *arg,
- const char *buf,
- unsigned long len);
-
-/*
- * Type of function passed to SEC_PKCS7Encode or SEC_PKCS7EncoderStart.
- * This is where the encoded bytes will be "sent".
- *
- * XXX Should just combine this with SEC_PKCS7DecoderContentCallback type
- * and use a simpler, common name.
- */
-typedef void (* SEC_PKCS7EncoderOutputCallback)(void *arg,
- const char *buf,
- unsigned long len);
-
-
-/*
- * Type of function passed to SEC_PKCS7Decode or SEC_PKCS7DecoderStart
- * to retrieve the decryption key. This function is inteded to be
- * used for EncryptedData content info's which do not have a key available
- * in a certificate, etc.
- */
-typedef PK11SymKey * (* SEC_PKCS7GetDecryptKeyCallback)(void *arg,
- SECAlgorithmID *algid);
-
-/*
- * Type of function passed to SEC_PKCS7Decode or SEC_PKCS7DecoderStart.
- * This function in intended to be used to verify that decrypting a
- * particular crypto algorithm is allowed. Content types which do not
- * require decryption will not need the callback. If the callback
- * is not specified for content types which require decryption, the
- * decryption will be disallowed.
- */
-typedef PRBool (* SEC_PKCS7DecryptionAllowedCallback)(SECAlgorithmID *algid,
- PK11SymKey *bulkkey);
-
-#endif /* _PKCS7T_H_ */
diff --git a/security/nss/lib/pkcs7/secmime.c b/security/nss/lib/pkcs7/secmime.c
deleted file mode 100644
index 017896bd7..000000000
--- a/security/nss/lib/pkcs7/secmime.c
+++ /dev/null
@@ -1,901 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * Stuff specific to S/MIME policy and interoperability.
- * Depends on PKCS7, but there should be no dependency the other way around.
- *
- * $Id$
- */
-
-#include "secmime.h"
-#include "secoid.h"
-#include "pk11func.h"
-#include "ciferfam.h" /* for CIPHER_FAMILY symbols */
-#include "secasn1.h"
-#include "secitem.h"
-#include "cert.h"
-#include "key.h"
-#include "secerr.h"
-
-typedef struct smime_cipher_map_struct {
- unsigned long cipher;
- SECOidTag algtag;
- SECItem *parms;
-} smime_cipher_map;
-
-/*
- * These are macros because I think some subsequent parameters,
- * like those for RC5, will want to use them, too, separately.
- */
-#define SMIME_DER_INTVAL_16 SEC_ASN1_INTEGER, 0x01, 0x10
-#define SMIME_DER_INTVAL_40 SEC_ASN1_INTEGER, 0x01, 0x28
-#define SMIME_DER_INTVAL_64 SEC_ASN1_INTEGER, 0x01, 0x40
-#define SMIME_DER_INTVAL_128 SEC_ASN1_INTEGER, 0x02, 0x00, 0x80
-
-#ifdef SMIME_DOES_RC5 /* will be needed; quiet unused warning for now */
-static unsigned char smime_int16[] = { SMIME_DER_INTVAL_16 };
-#endif
-static unsigned char smime_int40[] = { SMIME_DER_INTVAL_40 };
-static unsigned char smime_int64[] = { SMIME_DER_INTVAL_64 };
-static unsigned char smime_int128[] = { SMIME_DER_INTVAL_128 };
-
-static SECItem smime_rc2p40 = { siBuffer, smime_int40, sizeof(smime_int40) };
-static SECItem smime_rc2p64 = { siBuffer, smime_int64, sizeof(smime_int64) };
-static SECItem smime_rc2p128 = { siBuffer, smime_int128, sizeof(smime_int128) };
-
-static smime_cipher_map smime_cipher_maps[] = {
- { SMIME_RC2_CBC_40, SEC_OID_RC2_CBC, &smime_rc2p40 },
- { SMIME_RC2_CBC_64, SEC_OID_RC2_CBC, &smime_rc2p64 },
- { SMIME_RC2_CBC_128, SEC_OID_RC2_CBC, &smime_rc2p128 },
-#ifdef SMIME_DOES_RC5
- { SMIME_RC5PAD_64_16_40, SEC_OID_RC5_CBC_PAD, &smime_rc5p40 },
- { SMIME_RC5PAD_64_16_64, SEC_OID_RC5_CBC_PAD, &smime_rc5p64 },
- { SMIME_RC5PAD_64_16_128, SEC_OID_RC5_CBC_PAD, &smime_rc5p128 },
-#endif
- { SMIME_DES_CBC_56, SEC_OID_DES_CBC, NULL },
- { SMIME_DES_EDE3_168, SEC_OID_DES_EDE3_CBC, NULL },
- { SMIME_FORTEZZA, SEC_OID_FORTEZZA_SKIPJACK, NULL}
-};
-
-/*
- * Note, the following value really just needs to be an upper bound
- * on the ciphers.
- */
-static const int smime_symmetric_count = sizeof(smime_cipher_maps)
- / sizeof(smime_cipher_map);
-
-static unsigned long *smime_prefs, *smime_newprefs;
-static int smime_current_pref_index = 0;
-static PRBool smime_prefs_complete = PR_FALSE;
-static PRBool smime_prefs_changed = PR_TRUE;
-
-static unsigned long smime_policy_bits = 0;
-
-
-static int
-smime_mapi_by_cipher (unsigned long cipher)
-{
- int i;
-
- for (i = 0; i < smime_symmetric_count; i++) {
- if (smime_cipher_maps[i].cipher == cipher)
- break;
- }
-
- if (i == smime_symmetric_count)
- return -1;
-
- return i;
-}
-
-
-/*
- * this function locally records the user's preference
- */
-SECStatus
-SECMIME_EnableCipher(long which, int on)
-{
- unsigned long mask;
-
- if (smime_newprefs == NULL || smime_prefs_complete) {
- /*
- * This is either the very first time, or we are starting over.
- */
- smime_newprefs = (unsigned long*)PORT_ZAlloc (smime_symmetric_count
- * sizeof(*smime_newprefs));
- if (smime_newprefs == NULL)
- return SECFailure;
- smime_current_pref_index = 0;
- smime_prefs_complete = PR_FALSE;
- }
-
- mask = which & CIPHER_FAMILYID_MASK;
- if (mask == CIPHER_FAMILYID_MASK) {
- /*
- * This call signifies that all preferences have been set.
- * Move "newprefs" over, after checking first whether or
- * not the new ones are different from the old ones.
- */
- if (smime_prefs != NULL) {
- if (PORT_Memcmp (smime_prefs, smime_newprefs,
- smime_symmetric_count * sizeof(*smime_prefs)) == 0)
- smime_prefs_changed = PR_FALSE;
- else
- smime_prefs_changed = PR_TRUE;
- PORT_Free (smime_prefs);
- }
-
- smime_prefs = smime_newprefs;
- smime_prefs_complete = PR_TRUE;
- return SECSuccess;
- }
-
- PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
- if (mask != CIPHER_FAMILYID_SMIME) {
- /* XXX set an error! */
- return SECFailure;
- }
-
- if (on) {
- PORT_Assert (smime_current_pref_index < smime_symmetric_count);
- if (smime_current_pref_index >= smime_symmetric_count) {
- /* XXX set an error! */
- return SECFailure;
- }
-
- smime_newprefs[smime_current_pref_index++] = which;
- }
-
- return SECSuccess;
-}
-
-
-/*
- * this function locally records the export policy
- */
-SECStatus
-SECMIME_SetPolicy(long which, int on)
-{
- unsigned long mask;
-
- PORT_Assert ((which & CIPHER_FAMILYID_MASK) == CIPHER_FAMILYID_SMIME);
- if ((which & CIPHER_FAMILYID_MASK) != CIPHER_FAMILYID_SMIME) {
- /* XXX set an error! */
- return SECFailure;
- }
-
- which &= ~CIPHER_FAMILYID_MASK;
-
- PORT_Assert (which < 32); /* bits in the long */
- if (which >= 32) {
- /* XXX set an error! */
- return SECFailure;
- }
-
- mask = 1UL << which;
-
- if (on) {
- smime_policy_bits |= mask;
- } else {
- smime_policy_bits &= ~mask;
- }
-
- return SECSuccess;
-}
-
-
-/*
- * Based on the given algorithm (including its parameters, in some cases!)
- * and the given key (may or may not be inspected, depending on the
- * algorithm), find the appropriate policy algorithm specification
- * and return it. If no match can be made, -1 is returned.
- */
-static long
-smime_policy_algorithm (SECAlgorithmID *algid, PK11SymKey *key)
-{
- SECOidTag algtag;
-
- algtag = SECOID_GetAlgorithmTag (algid);
- switch (algtag) {
- case SEC_OID_RC2_CBC:
- {
- unsigned int keylen_bits;
-
- keylen_bits = PK11_GetKeyStrength (key, algid);
- switch (keylen_bits) {
- case 40:
- return SMIME_RC2_CBC_40;
- case 64:
- return SMIME_RC2_CBC_64;
- case 128:
- return SMIME_RC2_CBC_128;
- default:
- break;
- }
- }
- break;
- case SEC_OID_DES_CBC:
- return SMIME_DES_CBC_56;
- case SEC_OID_DES_EDE3_CBC:
- return SMIME_DES_EDE3_168;
- case SEC_OID_FORTEZZA_SKIPJACK:
- return SMIME_FORTEZZA;
-#ifdef SMIME_DOES_RC5
- case SEC_OID_RC5_CBC_PAD:
- PORT_Assert (0); /* XXX need to pull out parameters and match */
- break;
-#endif
- default:
- break;
- }
-
- return -1;
-}
-
-
-static PRBool
-smime_cipher_allowed (unsigned long which)
-{
- unsigned long mask;
-
- which &= ~CIPHER_FAMILYID_MASK;
- PORT_Assert (which < 32); /* bits per long (min) */
- if (which >= 32)
- return PR_FALSE;
-
- mask = 1UL << which;
- if ((mask & smime_policy_bits) == 0)
- return PR_FALSE;
-
- return PR_TRUE;
-}
-
-
-PRBool
-SECMIME_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key)
-{
- long which;
-
- which = smime_policy_algorithm (algid, key);
- if (which < 0)
- return PR_FALSE;
-
- return smime_cipher_allowed ((unsigned long)which);
-}
-
-
-/*
- * Does the current policy allow *any* S/MIME encryption (or decryption)?
- *
- * This tells whether or not *any* S/MIME encryption can be done,
- * according to policy. Callers may use this to do nicer user interface
- * (say, greying out a checkbox so a user does not even try to encrypt
- * a message when they are not allowed to) or for any reason they want
- * to check whether S/MIME encryption (or decryption, for that matter)
- * may be done.
- *
- * It takes no arguments. The return value is a simple boolean:
- * PR_TRUE means encryption (or decryption) is *possible*
- * (but may still fail due to other reasons, like because we cannot
- * find all the necessary certs, etc.; PR_TRUE is *not* a guarantee)
- * PR_FALSE means encryption (or decryption) is not permitted
- *
- * There are no errors from this routine.
- */
-PRBool
-SECMIME_EncryptionPossible (void)
-{
- if (smime_policy_bits != 0)
- return PR_TRUE;
-
- return PR_FALSE;
-}
-
-
-/*
- * XXX Would like the "parameters" field to be a SECItem *, but the
- * encoder is having trouble with optional pointers to an ANY. Maybe
- * once that is fixed, can change this back...
- */
-typedef struct smime_capability_struct {
- unsigned long cipher; /* local; not part of encoding */
- SECOidTag capIDTag; /* local; not part of encoding */
- SECItem capabilityID;
- SECItem parameters;
-} smime_capability;
-
-static const SEC_ASN1Template smime_capability_template[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(smime_capability) },
- { SEC_ASN1_OBJECT_ID,
- offsetof(smime_capability,capabilityID), },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
- offsetof(smime_capability,parameters), },
- { 0, }
-};
-
-static const SEC_ASN1Template smime_capabilities_template[] = {
- { SEC_ASN1_SEQUENCE_OF, 0, smime_capability_template }
-};
-
-
-
-static void
-smime_fill_capability (smime_capability *cap)
-{
- unsigned long cipher;
- SECOidTag algtag;
- int i;
-
- algtag = SECOID_FindOIDTag (&(cap->capabilityID));
-
- for (i = 0; i < smime_symmetric_count; i++) {
- if (smime_cipher_maps[i].algtag != algtag)
- continue;
- /*
- * XXX If SECITEM_CompareItem allowed NULLs as arguments (comparing
- * 2 NULLs as equal and NULL and non-NULL as not equal), we could
- * use that here instead of all of the following comparison code.
- */
- if (cap->parameters.data != NULL) {
- if (smime_cipher_maps[i].parms == NULL)
- continue;
- if (cap->parameters.len != smime_cipher_maps[i].parms->len)
- continue;
- if (PORT_Memcmp (cap->parameters.data,
- smime_cipher_maps[i].parms->data,
- cap->parameters.len) == 0)
- break;
- } else if (smime_cipher_maps[i].parms == NULL) {
- break;
- }
- }
-
- if (i == smime_symmetric_count)
- cipher = 0;
- else
- cipher = smime_cipher_maps[i].cipher;
-
- cap->cipher = cipher;
- cap->capIDTag = algtag;
-}
-
-
-static long
-smime_choose_cipher (CERTCertificate *scert, CERTCertificate **rcerts)
-{
- PRArenaPool *poolp;
- long chosen_cipher;
- int *cipher_abilities;
- int *cipher_votes;
- int strong_mapi;
- int rcount, mapi, max, i;
- PRBool isFortezza = PK11_FortezzaHasKEA(scert);
-
- if (smime_policy_bits == 0) {
- PORT_SetError (SEC_ERROR_BAD_EXPORT_ALGORITHM);
- return -1;
- }
-
- chosen_cipher = SMIME_RC2_CBC_40; /* the default, LCD */
-
- poolp = PORT_NewArena (1024); /* XXX what is right value? */
- if (poolp == NULL)
- goto done;
-
- cipher_abilities = (int*)PORT_ArenaZAlloc (poolp,
- smime_symmetric_count * sizeof(int));
- if (cipher_abilities == NULL)
- goto done;
-
- cipher_votes = (int*)PORT_ArenaZAlloc (poolp,
- smime_symmetric_count * sizeof(int));
- if (cipher_votes == NULL)
- goto done;
-
- /*
- * XXX Should have a #define somewhere which specifies default
- * strong cipher. (Or better, a way to configure, which would
- * take Fortezza into account as well.)
- */
-
- /* If the user has the Fortezza preference turned on, make
- * that the strong cipher. Otherwise, use triple-DES. */
- strong_mapi = -1;
- if (isFortezza) {
- for(i=0;i < smime_current_pref_index && strong_mapi < 0;i++)
- {
- if (smime_prefs[i] == SMIME_FORTEZZA)
- strong_mapi = smime_mapi_by_cipher(SMIME_FORTEZZA);
- }
- }
-
- if (strong_mapi == -1)
- strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168);
-
- PORT_Assert (strong_mapi >= 0);
-
- for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
- SECItem *profile;
- smime_capability **caps;
- int capi, pref;
- SECStatus dstat;
-
- pref = smime_symmetric_count;
- profile = CERT_FindSMimeProfile (rcerts[rcount]);
- if (profile != NULL && profile->data != NULL && profile->len > 0) {
- caps = NULL;
- dstat = SEC_ASN1DecodeItem (poolp, &caps,
- smime_capabilities_template,
- profile);
- if (dstat == SECSuccess && caps != NULL) {
- for (capi = 0; caps[capi] != NULL; capi++) {
- smime_fill_capability (caps[capi]);
- mapi = smime_mapi_by_cipher (caps[capi]->cipher);
- if (mapi >= 0) {
- cipher_abilities[mapi]++;
- cipher_votes[mapi] += pref;
- --pref;
- }
- }
- }
- } else {
- SECKEYPublicKey *key;
- unsigned int pklen_bits;
-
- /*
- * XXX This is probably only good for RSA keys. What I would
- * really like is a function to just say; Is the public key in
- * this cert an export-length key? Then I would not have to
- * know things like the value 512, or the kind of key, or what
- * a subjectPublicKeyInfo is, etc.
- */
- key = CERT_ExtractPublicKey (rcerts[rcount]);
- if (key != NULL) {
- pklen_bits = SECKEY_PublicKeyStrength (key) * 8;
- SECKEY_DestroyPublicKey (key);
-
- if (pklen_bits > 512) {
- cipher_abilities[strong_mapi]++;
- cipher_votes[strong_mapi] += pref;
- }
- }
- }
- if (profile != NULL)
- SECITEM_FreeItem (profile, PR_TRUE);
- }
-
- max = 0;
- for (mapi = 0; mapi < smime_symmetric_count; mapi++) {
- if (cipher_abilities[mapi] != rcount)
- continue;
- if (! smime_cipher_allowed (smime_cipher_maps[mapi].cipher))
- continue;
- if (!isFortezza && (smime_cipher_maps[mapi].cipher == SMIME_FORTEZZA))
- continue;
- if (cipher_votes[mapi] > max) {
- chosen_cipher = smime_cipher_maps[mapi].cipher;
- max = cipher_votes[mapi];
- } /* XXX else if a tie, let scert break it? */
- }
-
-done:
- if (poolp != NULL)
- PORT_FreeArena (poolp, PR_FALSE);
-
- return chosen_cipher;
-}
-
-
-/*
- * XXX This is a hack for now to satisfy our current interface.
- * Eventually, with more parameters needing to be specified, just
- * looking up the keysize is not going to be sufficient.
- */
-static int
-smime_keysize_by_cipher (unsigned long which)
-{
- int keysize;
-
- switch (which) {
- case SMIME_RC2_CBC_40:
- keysize = 40;
- break;
- case SMIME_RC2_CBC_64:
- keysize = 64;
- break;
- case SMIME_RC2_CBC_128:
- keysize = 128;
- break;
-#ifdef SMIME_DOES_RC5
- case SMIME_RC5PAD_64_16_40:
- case SMIME_RC5PAD_64_16_64:
- case SMIME_RC5PAD_64_16_128:
- /* XXX See comment above; keysize is not enough... */
- PORT_Assert (0);
- PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
- keysize = -1;
- break;
-#endif
- case SMIME_DES_CBC_56:
- case SMIME_DES_EDE3_168:
- case SMIME_FORTEZZA:
- /*
- * These are special; since the key size is fixed, we actually
- * want to *avoid* specifying a key size.
- */
- keysize = 0;
- break;
- default:
- keysize = -1;
- break;
- }
-
- return keysize;
-}
-
-
-/*
- * Start an S/MIME encrypting context.
- *
- * "scert" is the cert for the sender. It will be checked for validity.
- * "rcerts" are the certs for the recipients. They will also be checked.
- *
- * "certdb" is the cert database to use for verifying the certs.
- * It can be NULL if a default database is available (like in the client).
- *
- * This function already does all of the stuff specific to S/MIME protocol
- * and local policy; the return value just needs to be passed to
- * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
- * and finally to SEC_PKCS7DestroyContentInfo().
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-SEC_PKCS7ContentInfo *
-SECMIME_CreateEncrypted(CERTCertificate *scert,
- CERTCertificate **rcerts,
- CERTCertDBHandle *certdb,
- SECKEYGetPasswordKey pwfn,
- void *pwfn_arg)
-{
- SEC_PKCS7ContentInfo *cinfo;
- long cipher;
- SECOidTag encalg;
- int keysize;
- int mapi, rci;
-
- cipher = smime_choose_cipher (scert, rcerts);
- if (cipher < 0)
- return NULL;
-
- mapi = smime_mapi_by_cipher (cipher);
- if (mapi < 0)
- return NULL;
-
- /*
- * XXX This is stretching it -- CreateEnvelopedData should probably
- * take a cipher itself of some sort, because we cannot know what the
- * future will bring in terms of parameters for each type of algorithm.
- * For example, just an algorithm and keysize is *not* sufficient to
- * fully specify the usage of RC5 (which also needs to know rounds and
- * block size). Work this out into a better API!
- */
- encalg = smime_cipher_maps[mapi].algtag;
- keysize = smime_keysize_by_cipher (cipher);
- if (keysize < 0)
- return NULL;
-
- cinfo = SEC_PKCS7CreateEnvelopedData (scert, certUsageEmailRecipient,
- certdb, encalg, keysize,
- pwfn, pwfn_arg);
- if (cinfo == NULL)
- return NULL;
-
- for (rci = 0; rcerts[rci] != NULL; rci++) {
- if (rcerts[rci] == scert)
- continue;
- if (SEC_PKCS7AddRecipient (cinfo, rcerts[rci], certUsageEmailRecipient,
- NULL) != SECSuccess) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- return NULL;
- }
- }
-
- return cinfo;
-}
-
-
-static smime_capability **smime_capabilities;
-static SECItem *smime_encoded_caps;
-static PRBool lastUsedFortezza;
-
-
-static SECStatus
-smime_init_caps (PRBool isFortezza)
-{
- smime_capability *cap;
- smime_cipher_map *map;
- SECOidData *oiddata;
- SECStatus rv;
- int i, capIndex;
-
- if (smime_encoded_caps != NULL
- && (! smime_prefs_changed)
- && lastUsedFortezza == isFortezza)
- return SECSuccess;
-
- if (smime_encoded_caps != NULL) {
- SECITEM_FreeItem (smime_encoded_caps, PR_TRUE);
- smime_encoded_caps = NULL;
- }
-
- if (smime_capabilities == NULL) {
- smime_capabilities = (smime_capability**)PORT_ZAlloc (
- (smime_symmetric_count + 1)
- * sizeof(smime_capability *));
- if (smime_capabilities == NULL)
- return SECFailure;
- }
-
- rv = SECFailure;
-
- /*
- The process of creating the encoded PKCS7 cipher capability list
- involves two basic steps:
-
- (a) Convert our internal representation of cipher preferences
- (smime_prefs) into an array containing cipher OIDs and
- parameter data (smime_capabilities). This step is
- performed here.
-
- (b) Encode, using ASN.1, the cipher information in
- smime_capabilities, leaving the encoded result in
- smime_encoded_caps.
-
- (In the process of performing (a), Lisa put in some optimizations
- which allow us to avoid needlessly re-populating elements in
- smime_capabilities as we walk through smime_prefs.)
-
- We want to use separate loop variables for smime_prefs and
- smime_capabilities because in the case where the Skipjack cipher
- is turned on in the prefs, but where we don't want to include
- Skipjack in the encoded capabilities (presumably due to using a
- non-fortezza cert when sending a message), we want to avoid creating
- an empty element in smime_capabilities. This would otherwise cause
- the encoding step to produce an empty set, since Skipjack happens
- to be the first cipher in smime_prefs, if it is turned on.
- */
- for (i = 0, capIndex = 0; i < smime_current_pref_index; i++, capIndex++) {
- int mapi;
-
- /* Get the next cipher preference in smime_prefs. */
- mapi = smime_mapi_by_cipher (smime_prefs[i]);
- if (mapi < 0)
- break;
-
- /* Find the corresponding entry in the cipher map. */
- PORT_Assert (mapi < smime_symmetric_count);
- map = &(smime_cipher_maps[mapi]);
-
- /* If we're using a non-Fortezza cert, only advertise non-Fortezza
- capabilities. (We advertise all capabilities if we have a
- Fortezza cert.) */
- if ((!isFortezza) && (map->cipher == SMIME_FORTEZZA))
- {
- capIndex--; /* we want to visit the same caps index entry next time */
- continue;
- }
-
- /*
- * Convert the next preference found in smime_prefs into an
- * smime_capability.
- */
-
- cap = smime_capabilities[capIndex];
- if (cap == NULL) {
- cap = (smime_capability*)PORT_ZAlloc (sizeof(smime_capability));
- if (cap == NULL)
- break;
- smime_capabilities[capIndex] = cap;
- } else if (cap->cipher == smime_prefs[i]) {
- continue; /* no change to this one */
- }
-
- cap->capIDTag = map->algtag;
- oiddata = SECOID_FindOIDByTag (map->algtag);
- if (oiddata == NULL)
- break;
-
- if (cap->capabilityID.data != NULL) {
- SECITEM_FreeItem (&(cap->capabilityID), PR_FALSE);
- cap->capabilityID.data = NULL;
- cap->capabilityID.len = 0;
- }
-
- rv = SECITEM_CopyItem (NULL, &(cap->capabilityID), &(oiddata->oid));
- if (rv != SECSuccess)
- break;
-
- if (map->parms == NULL) {
- cap->parameters.data = NULL;
- cap->parameters.len = 0;
- } else {
- cap->parameters.data = map->parms->data;
- cap->parameters.len = map->parms->len;
- }
-
- cap->cipher = smime_prefs[i];
- }
-
- if (i != smime_current_pref_index)
- return rv;
-
- while (capIndex < smime_symmetric_count) {
- cap = smime_capabilities[capIndex];
- if (cap != NULL) {
- SECITEM_FreeItem (&(cap->capabilityID), PR_FALSE);
- PORT_Free (cap);
- }
- smime_capabilities[capIndex] = NULL;
- capIndex++;
- }
- smime_capabilities[capIndex] = NULL;
-
- smime_encoded_caps = SEC_ASN1EncodeItem (NULL, NULL, &smime_capabilities,
- smime_capabilities_template);
- if (smime_encoded_caps == NULL)
- return SECFailure;
-
- lastUsedFortezza = isFortezza;
-
- return SECSuccess;
-}
-
-
-static SECStatus
-smime_add_profile (CERTCertificate *cert, SEC_PKCS7ContentInfo *cinfo)
-{
- PRBool isFortezza = PR_FALSE;
-
- PORT_Assert (smime_prefs_complete);
- if (! smime_prefs_complete)
- return SECFailure;
-
- /* See if the sender's cert specifies Fortezza key exchange. */
- if (cert != NULL)
- isFortezza = PK11_FortezzaHasKEA(cert);
-
- /* For that matter, if capabilities haven't been initialized yet,
- do so now. */
- if (isFortezza != lastUsedFortezza || smime_encoded_caps == NULL || smime_prefs_changed) {
- SECStatus rv;
-
- rv = smime_init_caps(isFortezza);
- if (rv != SECSuccess)
- return rv;
-
- PORT_Assert (smime_encoded_caps != NULL);
- }
-
- return SEC_PKCS7AddSignedAttribute (cinfo, SEC_OID_PKCS9_SMIME_CAPABILITIES,
- smime_encoded_caps);
-}
-
-
-/*
- * Start an S/MIME signing context.
- *
- * "scert" is the cert that will be used to sign the data. It will be
- * checked for validity.
- *
- * "ecert" is the signer's encryption cert. If it is different from
- * scert, then it will be included in the signed message so that the
- * recipient can save it for future encryptions.
- *
- * "certdb" is the cert database to use for verifying the cert.
- * It can be NULL if a default database is available (like in the client).
- *
- * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
- * XXX There should be SECMIME functions for hashing, or the hashing should
- * be built into this interface, which we would like because we would
- * support more smartcards that way, and then this argument should go away.)
- *
- * "digest" is the actual digest of the data. It must be provided in
- * the case of detached data or NULL if the content will be included.
- *
- * This function already does all of the stuff specific to S/MIME protocol
- * and local policy; the return value just needs to be passed to
- * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
- * and finally to SEC_PKCS7DestroyContentInfo().
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-
-SEC_PKCS7ContentInfo *
-SECMIME_CreateSigned (CERTCertificate *scert,
- CERTCertificate *ecert,
- CERTCertDBHandle *certdb,
- SECOidTag digestalg,
- SECItem *digest,
- SECKEYGetPasswordKey pwfn,
- void *pwfn_arg)
-{
- SEC_PKCS7ContentInfo *cinfo;
- SECStatus rv;
-
- /* See note in header comment above about digestalg. */
- PORT_Assert (digestalg == SEC_OID_SHA1);
-
- cinfo = SEC_PKCS7CreateSignedData (scert, certUsageEmailSigner,
- certdb, digestalg, digest,
- pwfn, pwfn_arg);
- if (cinfo == NULL)
- return NULL;
-
- if (SEC_PKCS7IncludeCertChain (cinfo, NULL) != SECSuccess) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- return NULL;
- }
-
- /* if the encryption cert and the signing cert differ, then include
- * the encryption cert too.
- */
- /* it is ok to compare the pointers since we ref count, and the same
- * cert will always have the same pointer
- */
- if ( ( ecert != NULL ) && ( ecert != scert ) ) {
- rv = SEC_PKCS7AddCertificate(cinfo, ecert);
- if ( rv != SECSuccess ) {
- SEC_PKCS7DestroyContentInfo (cinfo);
- return NULL;
- }
- }
- /*
- * Add the signing time. But if it fails for some reason,
- * may as well not give up altogether -- just assert.
- */
- rv = SEC_PKCS7AddSigningTime (cinfo);
- PORT_Assert (rv == SECSuccess);
-
- /*
- * Add the email profile. Again, if it fails for some reason,
- * may as well not give up altogether -- just assert.
- */
- rv = smime_add_profile (ecert, cinfo);
- PORT_Assert (rv == SECSuccess);
-
- return cinfo;
-}
diff --git a/security/nss/lib/pkcs7/secmime.h b/security/nss/lib/pkcs7/secmime.h
deleted file mode 100644
index 6950e416f..000000000
--- a/security/nss/lib/pkcs7/secmime.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * Header file for routines specific to S/MIME. Keep things that are pure
- * pkcs7 out of here; this is for S/MIME policy, S/MIME interoperability, etc.
- *
- * $Id$
- */
-
-#ifndef _SECMIME_H_
-#define _SECMIME_H_ 1
-
-#include "secpkcs7.h"
-
-
-/************************************************************************/
-SEC_BEGIN_PROTOS
-
-/*
- * Initialize the local recording of the user S/MIME cipher preferences.
- * This function is called once for each cipher, the order being
- * important (first call records greatest preference, and so on).
- * When finished, it is called with a "which" of CIPHER_FAMILID_MASK.
- * If the function is called again after that, it is assumed that
- * the preferences are being reset, and the old preferences are
- * discarded.
- *
- * XXX This is for a particular user, and right now the storage is
- * XXX local, static. The preference should be stored elsewhere to allow
- * XXX for multiple uses of one library? How does SSL handle this;
- * XXX it has something similar?
- *
- * - The "which" values are defined in ciferfam.h (the SMIME_* values,
- * for example SMIME_DES_CBC_56).
- * - If "on" is non-zero then the named cipher is enabled, otherwise
- * it is disabled. (It is not necessary to call the function for
- * ciphers that are disabled, however, as that is the default.)
- *
- * If the cipher preference is successfully recorded, SECSuccess
- * is returned. Otherwise SECFailure is returned. The only errors
- * are due to failure allocating memory or bad parameters/calls:
- * SEC_ERROR_XXX ("which" is not in the S/MIME cipher family)
- * SEC_ERROR_XXX (function is being called more times than there
- * are known/expected ciphers)
- */
-extern SECStatus SECMIME_EnableCipher(long which, int on);
-
-/*
- * Initialize the local recording of the S/MIME policy.
- * This function is called to enable/disable a particular cipher.
- * (S/MIME encryption or decryption using a particular cipher is only
- * allowed if that cipher is currently enabled.) At startup, all S/MIME
- * ciphers are disabled. From that point, this function can be called
- * to enable a cipher -- it is not necessary to call this to disable
- * a cipher unless that cipher was previously, explicitly enabled via
- * this function.
- *
- * XXX This is for a the current module, I think, so local, static storage
- * XXX is okay. Is that correct, or could multiple uses of the same
- * XXX library expect to operate under different policies?
- *
- * - The "which" values are defined in ciferfam.h (the SMIME_* values,
- * for example SMIME_DES_CBC_56).
- * - If "on" is non-zero then the named cipher is enabled, otherwise
- * it is disabled.
- *
- * If the cipher is successfully enabled/disabled, SECSuccess is
- * returned. Otherwise SECFailure is returned. The only errors
- * are due to bad parameters:
- * SEC_ERROR_XXX ("which" is not in the S/MIME cipher family)
- * SEC_ERROR_XXX ("which" exceeds expected maximum cipher; this is
- * really an internal error)
- */
-extern SECStatus SECMIME_SetPolicy(long which, int on);
-
-/*
- * Does the current policy allow S/MIME decryption of this particular
- * algorithm and keysize?
- */
-extern PRBool SECMIME_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key);
-
-/*
- * Does the current policy allow *any* S/MIME encryption (or decryption)?
- *
- * This tells whether or not *any* S/MIME encryption can be done,
- * according to policy. Callers may use this to do nicer user interface
- * (say, greying out a checkbox so a user does not even try to encrypt
- * a message when they are not allowed to) or for any reason they want
- * to check whether S/MIME encryption (or decryption, for that matter)
- * may be done.
- *
- * It takes no arguments. The return value is a simple boolean:
- * PR_TRUE means encryption (or decryption) is *possible*
- * (but may still fail due to other reasons, like because we cannot
- * find all the necessary certs, etc.; PR_TRUE is *not* a guarantee)
- * PR_FALSE means encryption (or decryption) is not permitted
- *
- * There are no errors from this routine.
- */
-extern PRBool SECMIME_EncryptionPossible(void);
-
-/*
- * Start an S/MIME encrypting context.
- *
- * "scert" is the cert for the sender. It will be checked for validity.
- * "rcerts" are the certs for the recipients. They will also be checked.
- *
- * "certdb" is the cert database to use for verifying the certs.
- * It can be NULL if a default database is available (like in the client).
- *
- * This function already does all of the stuff specific to S/MIME protocol
- * and local policy; the return value just needs to be passed to
- * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
- * and finally to SEC_PKCS7DestroyContentInfo().
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-extern SEC_PKCS7ContentInfo *SECMIME_CreateEncrypted(CERTCertificate *scert,
- CERTCertificate **rcerts,
- CERTCertDBHandle *certdb,
- SECKEYGetPasswordKey pwfn,
- void *pwfn_arg);
-
-/*
- * Start an S/MIME signing context.
- *
- * "scert" is the cert that will be used to sign the data. It will be
- * checked for validity.
- *
- * "certdb" is the cert database to use for verifying the cert.
- * It can be NULL if a default database is available (like in the client).
- *
- * "digestalg" names the digest algorithm. (It should be SEC_OID_SHA1;
- * XXX There should be SECMIME functions for hashing, or the hashing should
- * be built into this interface, which we would like because we would
- * support more smartcards that way, and then this argument should go away.)
- *
- * "digest" is the actual digest of the data. It must be provided in
- * the case of detached data or NULL if the content will be included.
- *
- * This function already does all of the stuff specific to S/MIME protocol
- * and local policy; the return value just needs to be passed to
- * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
- * and finally to SEC_PKCS7DestroyContentInfo().
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-extern SEC_PKCS7ContentInfo *SECMIME_CreateSigned(CERTCertificate *scert,
- CERTCertificate *ecert,
- CERTCertDBHandle *certdb,
- SECOidTag digestalg,
- SECItem *digest,
- SECKEYGetPasswordKey pwfn,
- void *pwfn_arg);
-
-/************************************************************************/
-SEC_END_PROTOS
-
-#endif /* _SECMIME_H_ */
diff --git a/security/nss/lib/pkcs7/secpkcs7.h b/security/nss/lib/pkcs7/secpkcs7.h
deleted file mode 100644
index 7a2b71b24..000000000
--- a/security/nss/lib/pkcs7/secpkcs7.h
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * Interface to the PKCS7 implementation.
- *
- * $Id$
- */
-
-#ifndef _SECPKCS7_H_
-#define _SECPKCS7_H_
-
-#include "seccomon.h"
-#include "mcom_db.h" /* needed by certt.h */
-
-#include "secoidt.h"
-#include "secder.h" /* needed by certt.h; XXX go away when possible */
-#include "certt.h"
-#include "keyt.h"
-#include "hasht.h"
-#include "pkcs7t.h"
-
-extern const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[];
-
-/************************************************************************/
-SEC_BEGIN_PROTOS
-
-/************************************************************************
- * Miscellaneous
- ************************************************************************/
-
-/*
- * Returns the content type of the given contentInfo.
- */
-extern SECOidTag SEC_PKCS7ContentType (SEC_PKCS7ContentInfo *cinfo);
-
-/*
- * Destroy a PKCS7 contentInfo and all of its sub-pieces.
- */
-extern void SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *contentInfo);
-
-/*
- * Copy a PKCS7 contentInfo. A Destroy is needed on *each* copy.
- */
-extern SEC_PKCS7ContentInfo *
-SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *contentInfo);
-
-/*
- * Return a pointer to the actual content. In the case of those types
- * which are encrypted, this returns the *plain* content.
- */
-extern SECItem *SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo);
-
-/************************************************************************
- * PKCS7 Decoding, Verification, etc..
- ************************************************************************/
-
-extern SEC_PKCS7DecoderContext *
-SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback callback,
- void *callback_arg,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg,
- SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
- void *decrypt_key_cb_arg,
- SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb);
-
-extern SECStatus
-SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
- const char *buf, unsigned long len);
-
-extern SEC_PKCS7ContentInfo *
-SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx);
-
-extern SEC_PKCS7ContentInfo *
-SEC_PKCS7DecodeItem(SECItem *p7item,
- SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg,
- SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
- void *decrypt_key_cb_arg,
- SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb);
-
-extern PRBool SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo);
-
-/* checks to see if the contents of the content info is
- * empty. it so, PR_TRUE is returned. PR_FALSE, otherwise.
- *
- * minLen is used to specify a minimum size. if content size <= minLen,
- * content is assumed empty.
- */
-extern PRBool
-SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen);
-
-extern PRBool SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo);
-
-/*
- * If the PKCS7 content has a signature (not just *could* have a signature)
- * return true; false otherwise. This can/should be called before calling
- * VerifySignature, which will always indicate failure if no signature is
- * present, but that does not mean there even was a signature!
- * Note that the content itself can be empty (detached content was sent
- * another way); it is the presence of the signature that matters.
- */
-extern PRBool SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo);
-
-/*
- * SEC_PKCS7VerifySignature
- * Look at a PKCS7 contentInfo and check if the signature is good.
- * The verification checks that the signing cert is valid and trusted
- * for the purpose specified by "certusage".
- *
- * In addition, if "keepcerts" is true, add any new certificates found
- * into our local database.
- */
-extern PRBool SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
- SECCertUsage certusage,
- PRBool keepcerts);
-
-/*
- * SEC_PKCS7VerifyDetachedSignature
- * Look at a PKCS7 contentInfo and check if the signature matches
- * a passed-in digest (calculated, supposedly, from detached contents).
- * The verification checks that the signing cert is valid and trusted
- * for the purpose specified by "certusage".
- *
- * In addition, if "keepcerts" is true, add any new certificates found
- * into our local database.
- */
-extern PRBool SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
- SECCertUsage certusage,
- SECItem *detached_digest,
- HASH_HashType digest_type,
- PRBool keepcerts);
-
-/*
- * SEC_PKCS7GetSignerCommonName, SEC_PKCS7GetSignerEmailAddress
- * The passed-in contentInfo is espected to be Signed, and these
- * functions return the specified portion of the full signer name.
- *
- * Returns a pointer to allocated memory, which must be freed.
- * A NULL return value is an error.
- */
-extern char *SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo);
-extern char *SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo);
-
-/*
- * Return the the signing time, in UTCTime format, of a PKCS7 contentInfo.
- */
-extern SECItem *SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo);
-
-
-/************************************************************************
- * PKCS7 Creation and Encoding.
- ************************************************************************/
-
-/*
- * Start a PKCS7 signing context.
- *
- * "cert" is the cert that will be used to sign the data. It will be
- * checked for validity.
- *
- * "certusage" describes the signing usage (e.g. certUsageEmailSigner)
- * XXX Maybe SECCertUsage should be split so that our caller just says
- * "email" and *we* add the "signing" part -- otherwise our caller
- * could be lying about the usage; we do not want to allow encryption
- * certs for signing or vice versa.
- *
- * "certdb" is the cert database to use for verifying the cert.
- * It can be NULL if a default database is available (like in the client).
- *
- * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
- *
- * "digest" is the actual digest of the data. It must be provided in
- * the case of detached data or NULL if the content will be included.
- *
- * The return value can be passed to functions which add things to
- * it like attributes, then eventually to SEC_PKCS7Encode() or to
- * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
- * SEC_PKCS7DestroyContentInfo().
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-extern SEC_PKCS7ContentInfo *
-SEC_PKCS7CreateSignedData (CERTCertificate *cert,
- SECCertUsage certusage,
- CERTCertDBHandle *certdb,
- SECOidTag digestalg,
- SECItem *digest,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg);
-
-/*
- * Create a PKCS7 certs-only container.
- *
- * "cert" is the (first) cert that will be included.
- *
- * "include_chain" specifies whether the entire chain for "cert" should
- * be included.
- *
- * "certdb" is the cert database to use for finding the chain.
- * It can be NULL in when "include_chain" is false, or when meaning
- * use the default database.
- *
- * More certs and chains can be added via AddCertficate and AddCertChain.
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-extern SEC_PKCS7ContentInfo *
-SEC_PKCS7CreateCertsOnly (CERTCertificate *cert,
- PRBool include_chain,
- CERTCertDBHandle *certdb);
-
-/*
- * Start a PKCS7 enveloping context.
- *
- * "cert" is the cert for the recipient. It will be checked for validity.
- *
- * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
- * XXX Maybe SECCertUsage should be split so that our caller just says
- * "email" and *we* add the "recipient" part -- otherwise our caller
- * could be lying about the usage; we do not want to allow encryption
- * certs for signing or vice versa.
- *
- * "certdb" is the cert database to use for verifying the cert.
- * It can be NULL if a default database is available (like in the client).
- *
- * "encalg" specifies the bulk encryption algorithm to use (e.g. SEC_OID_RC2).
- *
- * "keysize" specifies the bulk encryption key size, in bits.
- *
- * The return value can be passed to functions which add things to
- * it like more recipients, then eventually to SEC_PKCS7Encode() or to
- * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
- * SEC_PKCS7DestroyContentInfo().
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-extern SEC_PKCS7ContentInfo *
-SEC_PKCS7CreateEnvelopedData (CERTCertificate *cert,
- SECCertUsage certusage,
- CERTCertDBHandle *certdb,
- SECOidTag encalg,
- int keysize,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg);
-
-/*
- * XXX There will be a similar routine for creating signedAndEnvelopedData.
- * But its parameters will be different and I have no plans to implement
- * it any time soon because we have no current need for it.
- */
-
-/*
- * Create an empty PKCS7 data content info.
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-extern SEC_PKCS7ContentInfo *SEC_PKCS7CreateData (void);
-
-/*
- * Create an empty PKCS7 encrypted content info.
- *
- * "algorithm" specifies the bulk encryption algorithm to use.
- *
- * An error results in a return value of NULL and an error set.
- * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
- */
-extern SEC_PKCS7ContentInfo *
-SEC_PKCS7CreateEncryptedData (SECOidTag algorithm, int keysize,
- SECKEYGetPasswordKey pwfn, void *pwfn_arg);
-
-/*
- * All of the following things return SECStatus to signal success or failure.
- * Failure should have a more specific error status available via
- * PORT_GetError()/XP_GetError().
- */
-
-/*
- * Add the specified attribute to the authenticated (i.e. signed) attributes
- * of "cinfo" -- "oidtag" describes the attribute and "value" is the
- * value to be associated with it. NOTE! "value" must already be encoded;
- * no interpretation of "oidtag" is done. Also, it is assumed that this
- * signedData has only one signer -- if we ever need to add attributes
- * when there is more than one signature, we need a way to specify *which*
- * signature should get the attribute.
- *
- * XXX Technically, a signed attribute can have multiple values; if/when
- * we ever need to support an attribute which takes multiple values, we
- * either need to change this interface or create an AddSignedAttributeValue
- * which can be called subsequently, and would then append a value.
- *
- * "cinfo" should be of type signedData (the only kind of pkcs7 data
- * that is allowed authenticated attributes); SECFailure will be returned
- * if it is not.
- */
-extern SECStatus SEC_PKCS7AddSignedAttribute (SEC_PKCS7ContentInfo *cinfo,
- SECOidTag oidtag,
- SECItem *value);
-
-/*
- * Add "cert" and its entire chain to the set of certs included in "cinfo".
- *
- * "certdb" is the cert database to use for finding the chain.
- * It can be NULL, meaning use the default database.
- *
- * "cinfo" should be of type signedData or signedAndEnvelopedData;
- * SECFailure will be returned if it is not.
- */
-extern SECStatus SEC_PKCS7AddCertChain (SEC_PKCS7ContentInfo *cinfo,
- CERTCertificate *cert,
- CERTCertDBHandle *certdb);
-
-/*
- * Add "cert" to the set of certs included in "cinfo".
- *
- * "cinfo" should be of type signedData or signedAndEnvelopedData;
- * SECFailure will be returned if it is not.
- */
-extern SECStatus SEC_PKCS7AddCertificate (SEC_PKCS7ContentInfo *cinfo,
- CERTCertificate *cert);
-
-/*
- * Add another recipient to an encrypted message.
- *
- * "cinfo" should be of type envelopedData or signedAndEnvelopedData;
- * SECFailure will be returned if it is not.
- *
- * "cert" is the cert for the recipient. It will be checked for validity.
- *
- * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
- * XXX Maybe SECCertUsage should be split so that our caller just says
- * "email" and *we* add the "recipient" part -- otherwise our caller
- * could be lying about the usage; we do not want to allow encryption
- * certs for signing or vice versa.
- *
- * "certdb" is the cert database to use for verifying the cert.
- * It can be NULL if a default database is available (like in the client).
- */
-extern SECStatus SEC_PKCS7AddRecipient (SEC_PKCS7ContentInfo *cinfo,
- CERTCertificate *cert,
- SECCertUsage certusage,
- CERTCertDBHandle *certdb);
-
-/*
- * Add the signing time to the authenticated (i.e. signed) attributes
- * of "cinfo". This is expected to be included in outgoing signed
- * messages for email (S/MIME) but is likely useful in other situations.
- *
- * This should only be added once; a second call will either do
- * nothing or replace an old signing time with a newer one.
- *
- * XXX This will probably just shove the current time into "cinfo"
- * but it will not actually get signed until the entire item is
- * processed for encoding. Is this (expected to be small) delay okay?
- *
- * "cinfo" should be of type signedData (the only kind of pkcs7 data
- * that is allowed authenticated attributes); SECFailure will be returned
- * if it is not.
- */
-extern SECStatus SEC_PKCS7AddSigningTime (SEC_PKCS7ContentInfo *cinfo);
-
-/*
- * Add the signer's symmetric capabilities to the authenticated
- * (i.e. signed) attributes of "cinfo". This is expected to be
- * included in outgoing signed messages for email (S/MIME).
- *
- * This can only be added once; a second call will return SECFailure.
- *
- * "cinfo" should be of type signedData or signedAndEnvelopedData;
- * SECFailure will be returned if it is not.
- */
-extern SECStatus SEC_PKCS7AddSymmetricCapabilities(SEC_PKCS7ContentInfo *cinfo);
-
-/*
- * Mark that the signer's certificate and its issuing chain should
- * be included in the encoded data. This is expected to be used
- * in outgoing signed messages for email (S/MIME).
- *
- * "certdb" is the cert database to use for finding the chain.
- * It can be NULL, meaning use the default database.
- *
- * "cinfo" should be of type signedData or signedAndEnvelopedData;
- * SECFailure will be returned if it is not.
- */
-extern SECStatus SEC_PKCS7IncludeCertChain (SEC_PKCS7ContentInfo *cinfo,
- CERTCertDBHandle *certdb);
-
-
-/*
- * Set the content; it will be included and also hashed and/or encrypted
- * as appropriate. This is for in-memory content (expected to be "small")
- * that will be included in the PKCS7 object. All others should stream the
- * content through when encoding (see SEC_PKCS7Encoder{Start,Update,Finish}).
- *
- * "buf" points to data of length "len"; it will be copied.
- */
-extern SECStatus SEC_PKCS7SetContent (SEC_PKCS7ContentInfo *cinfo,
- const char *buf, unsigned long len);
-
-/*
- * Encode a PKCS7 object, in one shot. All necessary components
- * of the object must already be specified. Either the data has
- * already been included (via SetContent), or the data is detached,
- * or there is no data at all (certs-only).
- *
- * "cinfo" specifies the object to be encoded.
- *
- * "outputfn" is where the encoded bytes will be passed.
- *
- * "outputarg" is an opaque argument to the above callback.
- *
- * "bulkkey" specifies the bulk encryption key to use. This argument
- * can be NULL if no encryption is being done, or if the bulk key should
- * be generated internally (usually the case for EnvelopedData but never
- * for EncryptedData, which *must* provide a bulk encryption key).
- *
- * "pwfn" is a callback for getting the password which protects the
- * private key of the signer. This argument can be NULL if it is known
- * that no signing is going to be done.
- *
- * "pwfnarg" is an opaque argument to the above callback.
- */
-extern SECStatus SEC_PKCS7Encode (SEC_PKCS7ContentInfo *cinfo,
- SEC_PKCS7EncoderOutputCallback outputfn,
- void *outputarg,
- PK11SymKey *bulkkey,
- SECKEYGetPasswordKey pwfn,
- void *pwfnarg);
-
-/*
- * Encode a PKCS7 object, in one shot. All necessary components
- * of the object must already be specified. Either the data has
- * already been included (via SetContent), or the data is detached,
- * or there is no data at all (certs-only). The output, rather than
- * being passed to an output function as is done above, is all put
- * into a SECItem.
- *
- * "pool" specifies a pool from which to allocate the result.
- * It can be NULL, in which case memory is allocated generically.
- *
- * "dest" specifies a SECItem in which to put the result data.
- * It can be NULL, in which case the entire item is allocated, too.
- *
- * "cinfo" specifies the object to be encoded.
- *
- * "bulkkey" specifies the bulk encryption key to use. This argument
- * can be NULL if no encryption is being done, or if the bulk key should
- * be generated internally (usually the case for EnvelopedData but never
- * for EncryptedData, which *must* provide a bulk encryption key).
- *
- * "pwfn" is a callback for getting the password which protects the
- * private key of the signer. This argument can be NULL if it is known
- * that no signing is going to be done.
- *
- * "pwfnarg" is an opaque argument to the above callback.
- */
-extern SECItem *SEC_PKCS7EncodeItem (PRArenaPool *pool,
- SECItem *dest,
- SEC_PKCS7ContentInfo *cinfo,
- PK11SymKey *bulkkey,
- SECKEYGetPasswordKey pwfn,
- void *pwfnarg);
-
-/*
- * For those who want to simply point to the pkcs7 contentInfo ASN.1
- * template, and *not* call the encoding functions directly, the
- * following function can be used -- after it is called, the entire
- * PKCS7 contentInfo is ready to be encoded.
- */
-extern SECStatus SEC_PKCS7PrepareForEncode (SEC_PKCS7ContentInfo *cinfo,
- PK11SymKey *bulkkey,
- SECKEYGetPasswordKey pwfn,
- void *pwfnarg);
-
-/*
- * Start the process of encoding a PKCS7 object. The first part of
- * the encoded object will be passed to the output function right away;
- * after that it is expected that SEC_PKCS7EncoderUpdate will be called,
- * streaming in the actual content that is getting included as well as
- * signed or encrypted (or both).
- *
- * "cinfo" specifies the object to be encoded.
- *
- * "outputfn" is where the encoded bytes will be passed.
- *
- * "outputarg" is an opaque argument to the above callback.
- *
- * "bulkkey" specifies the bulk encryption key to use. This argument
- * can be NULL if no encryption is being done, or if the bulk key should
- * be generated internally (usually the case for EnvelopedData but never
- * for EncryptedData, which *must* provide a bulk encryption key).
- *
- * Returns an object to be passed to EncoderUpdate and EncoderFinish.
- */
-extern SEC_PKCS7EncoderContext *
-SEC_PKCS7EncoderStart (SEC_PKCS7ContentInfo *cinfo,
- SEC_PKCS7EncoderOutputCallback outputfn,
- void *outputarg,
- PK11SymKey *bulkkey);
-
-/*
- * Encode more contents, hashing and/or encrypting along the way.
- */
-extern SECStatus SEC_PKCS7EncoderUpdate (SEC_PKCS7EncoderContext *p7ecx,
- const char *buf,
- unsigned long len);
-
-/*
- * No more contents; finish the signature creation, if appropriate,
- * and then the encoding.
- *
- * "pwfn" is a callback for getting the password which protects the
- * signer's private key. This argument can be NULL if it is known
- * that no signing is going to be done.
- *
- * "pwfnarg" is an opaque argument to the above callback.
- */
-extern SECStatus SEC_PKCS7EncoderFinish (SEC_PKCS7EncoderContext *p7ecx,
- SECKEYGetPasswordKey pwfn,
- void *pwfnarg);
-
-/* retrieve the algorithm ID used to encrypt the content info
- * for encrypted and enveloped data. The SECAlgorithmID pointer
- * returned needs to be freed as it is a copy of the algorithm
- * id in the content info.
- */
-extern SECAlgorithmID *
-SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo);
-
-/* the content of an encrypted data content info is encrypted.
- * it is assumed that for encrypted data, that the data has already
- * been set and is in the "plainContent" field of the content info.
- *
- * cinfo is the content info to encrypt
- *
- * key is the key with which to perform the encryption. if the
- * algorithm is a password based encryption algorithm, the
- * key is actually a password which will be processed per
- * PKCS #5.
- *
- * in the event of an error, SECFailure is returned. SECSuccess
- * indicates a success.
- */
-extern SECStatus
-SEC_PKCS7EncryptContents(PRArenaPool *poolp,
- SEC_PKCS7ContentInfo *cinfo,
- SECItem *key,
- void *wincx);
-
-/* the content of an encrypted data content info is decrypted.
- * it is assumed that for encrypted data, that the data has already
- * been set and is in the "encContent" field of the content info.
- *
- * cinfo is the content info to decrypt
- *
- * key is the key with which to perform the decryption. if the
- * algorithm is a password based encryption algorithm, the
- * key is actually a password which will be processed per
- * PKCS #5.
- *
- * in the event of an error, SECFailure is returned. SECSuccess
- * indicates a success.
- */
-extern SECStatus
-SEC_PKCS7DecryptContents(PRArenaPool *poolp,
- SEC_PKCS7ContentInfo *cinfo,
- SECItem *key,
- void *wincx);
-
-/* retrieve the certificate list from the content info. the list
- * is a pointer to the list in the content info. this should not
- * be deleted or freed in any way short of calling
- * SEC_PKCS7DestroyContentInfo
- */
-extern SECItem **
-SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo);
-
-/* Returns the key length (in bits) of the algorithm used to encrypt
- this object. Returns 0 if it's not encrypted, or the key length is
- irrelevant. */
-extern int
-SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo);
-
-
-/************************************************************************/
-SEC_END_PROTOS
-
-#endif /* _SECPKCS7_H_ */