diff options
Diffstat (limited to 'security/nss/lib/pkcs7')
-rw-r--r-- | security/nss/lib/pkcs7/Makefile | 76 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/config.mk | 44 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/manifest.mn | 59 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/p7common.c | 738 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/p7create.c | 1320 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/p7decode.c | 2087 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/p7encode.c | 1329 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/p7local.c | 1431 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/p7local.h | 176 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/pkcs7t.h | 292 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/secmime.c | 901 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/secmime.h | 192 | ||||
-rw-r--r-- | security/nss/lib/pkcs7/secpkcs7.h | 618 |
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_ */ |