summaryrefslogtreecommitdiff
path: root/security/nss/lib/smime/cmsutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/smime/cmsutil.c')
-rw-r--r--security/nss/lib/smime/cmsutil.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/security/nss/lib/smime/cmsutil.c b/security/nss/lib/smime/cmsutil.c
new file mode 100644
index 000000000..f7899d881
--- /dev/null
+++ b/security/nss/lib/smime/cmsutil.c
@@ -0,0 +1,393 @@
+/*
+ * 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.
+ */
+
+/*
+ * CMS miscellaneous utility functions.
+ *
+ * $Id$
+ */
+
+#include "nssrenam.h"
+
+#include "cmslocal.h"
+
+#include "cert.h"
+#include "key.h"
+#include "secasn1.h"
+#include "secitem.h"
+#include "secoid.h"
+#include "pk11func.h"
+#include "secerr.h"
+#include "sechash.h"
+
+/*
+ * NSS_CMSArray_SortByDER - sort array of objects by objects' DER encoding
+ *
+ * make sure that the order of the objects 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 objs).
+ */
+SECStatus
+NSS_CMSArray_SortByDER(void **objs, const SEC_ASN1Template *objtemplate, void **objs2)
+{
+ PRArenaPool *poolp;
+ int num_objs;
+ SECItem **enc_objs;
+ SECStatus rv = SECFailure;
+ int i;
+
+ if (objs == NULL) /* already sorted */
+ return SECSuccess;
+
+ num_objs = NSS_CMSArray_Count((void **)objs);
+ if (num_objs == 0 || num_objs == 1) /* already sorted. */
+ return SECSuccess;
+
+ poolp = PORT_NewArena (1024); /* arena for temporaries */
+ 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_objs = (SECItem **)PORT_ArenaZAlloc(poolp, (num_objs + 1) * sizeof(SECItem *));
+ if (enc_objs == NULL)
+ goto loser;
+
+ /* DER encode each individual object. */
+ for (i = 0; i < num_objs; i++) {
+ enc_objs[i] = SEC_ASN1EncodeItem(poolp, NULL, objs[i], objtemplate);
+ if (enc_objs[i] == NULL)
+ goto loser;
+ }
+ enc_objs[num_objs] = NULL;
+
+ /* now compare and sort objs by the order of enc_objs */
+ NSS_CMSArray_Sort((void **)enc_objs, NSS_CMSUtil_DERCompare, objs, objs2);
+
+ rv = SECSuccess;
+
+loser:
+ PORT_FreeArena (poolp, PR_FALSE);
+ return rv;
+}
+
+/*
+ * NSS_CMSUtil_DERCompare - for use with NSS_CMSArray_Sort to
+ * sort arrays of SECItems containing DER
+ */
+int
+NSS_CMSUtil_DERCompare(void *a, void *b)
+{
+ SECItem *der1 = (SECItem *)a;
+ SECItem *der2 = (SECItem *)b;
+ int j;
+
+ /*
+ * 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.
+ */
+ if (der1->len != der2->len)
+ return (der1->len < der2->len) ? -1 : 1;
+
+ for (j = 0; j < der1->len; j++) {
+ if (der1->data[j] == der2->data[j])
+ continue;
+ return (der1->data[j] < der2->data[j]) ? -1 : 1;
+ }
+ return 0;
+}
+
+/*
+ * NSS_CMSAlgArray_GetIndexByAlgID - find a specific algorithm in an array of
+ * algorithms.
+ *
+ * algorithmArray - array of algorithm IDs
+ * algid - algorithmid of algorithm to pick
+ *
+ * Returns:
+ * An integer containing the index of the algorithm in the array or -1 if
+ * algorithm was not found.
+ */
+int
+NSS_CMSAlgArray_GetIndexByAlgID(SECAlgorithmID **algorithmArray, SECAlgorithmID *algid)
+{
+ int i;
+
+ if (algorithmArray == NULL || algorithmArray[0] == NULL)
+ return -1;
+
+ for (i = 0; algorithmArray[i] != NULL; i++) {
+ if (SECOID_CompareAlgorithmID(algorithmArray[i], algid) == SECEqual)
+ break; /* bingo */
+ }
+
+ if (algorithmArray[i] == NULL)
+ return -1; /* not found */
+
+ return i;
+}
+
+/*
+ * NSS_CMSAlgArray_GetIndexByAlgTag - find a specific algorithm in an array of
+ * algorithms.
+ *
+ * algorithmArray - array of algorithm IDs
+ * algtag - algorithm tag of algorithm to pick
+ *
+ * Returns:
+ * An integer containing the index of the algorithm in the array or -1 if
+ * algorithm was not found.
+ */
+int
+NSS_CMSAlgArray_GetIndexByAlgTag(SECAlgorithmID **algorithmArray, SECOidTag algtag)
+{
+ SECOidData *algid;
+ int i;
+
+ if (algorithmArray == NULL || algorithmArray[0] == NULL)
+ return -1;
+
+ for (i = 0; algorithmArray[i] != NULL; i++) {
+ algid = SECOID_FindOID(&(algorithmArray[i]->algorithm));
+ if (algid->offset == algtag)
+ break; /* bingo */
+ }
+
+ if (algorithmArray[i] == NULL)
+ return -1; /* not found */
+
+ return i;
+}
+
+const SECHashObject *
+NSS_CMSUtil_GetHashObjByAlgID(SECAlgorithmID *algid)
+{
+ SECOidData *oiddata;
+ const SECHashObject *digobj;
+
+ /* here are the algorithms we know */
+ oiddata = SECOID_FindOID(&(algid->algorithm));
+ if (oiddata == NULL) {
+ digobj = NULL;
+ } else {
+ switch (oiddata->offset) {
+ case SEC_OID_MD2:
+ digobj = HASH_GetHashObject(HASH_AlgMD2);
+ break;
+ case SEC_OID_MD5:
+ digobj = HASH_GetHashObject(HASH_AlgMD5);
+ break;
+ case SEC_OID_SHA1:
+ digobj = HASH_GetHashObject(HASH_AlgSHA1);
+ break;
+ default:
+ digobj = NULL;
+ break;
+ }
+ }
+ return digobj;
+}
+
+/*
+ * XXX I would *really* like to not have to do this, but the current
+ * signing interface gives me little choice.
+ */
+SECOidTag
+NSS_CMSUtil_MakeSignatureAlgorithm(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 */
+}
+
+const SEC_ASN1Template *
+NSS_CMSUtil_GetTemplateByTypeTag(SECOidTag type)
+{
+ const SEC_ASN1Template *template;
+ extern const SEC_ASN1Template NSSCMSSignedDataTemplate[];
+ extern const SEC_ASN1Template NSSCMSEnvelopedDataTemplate[];
+ extern const SEC_ASN1Template NSSCMSEncryptedDataTemplate[];
+ extern const SEC_ASN1Template NSSCMSDigestedDataTemplate[];
+
+ switch (type) {
+ case SEC_OID_PKCS7_SIGNED_DATA:
+ template = NSSCMSSignedDataTemplate;
+ break;
+ case SEC_OID_PKCS7_ENVELOPED_DATA:
+ template = NSSCMSEnvelopedDataTemplate;
+ break;
+ case SEC_OID_PKCS7_ENCRYPTED_DATA:
+ template = NSSCMSEncryptedDataTemplate;
+ break;
+ case SEC_OID_PKCS7_DIGESTED_DATA:
+ template = NSSCMSDigestedDataTemplate;
+ break;
+ default:
+ case SEC_OID_PKCS7_DATA:
+ template = NULL;
+ break;
+ }
+ return template;
+}
+
+size_t
+NSS_CMSUtil_GetSizeByTypeTag(SECOidTag type)
+{
+ size_t size;
+
+ switch (type) {
+ case SEC_OID_PKCS7_SIGNED_DATA:
+ size = sizeof(NSSCMSSignedData);
+ break;
+ case SEC_OID_PKCS7_ENVELOPED_DATA:
+ size = sizeof(NSSCMSEnvelopedData);
+ break;
+ case SEC_OID_PKCS7_ENCRYPTED_DATA:
+ size = sizeof(NSSCMSEncryptedData);
+ break;
+ case SEC_OID_PKCS7_DIGESTED_DATA:
+ size = sizeof(NSSCMSDigestedData);
+ break;
+ default:
+ case SEC_OID_PKCS7_DATA:
+ size = 0;
+ break;
+ }
+ return size;
+}
+
+NSSCMSContentInfo *
+NSS_CMSContent_GetContentInfo(void *msg, SECOidTag type)
+{
+ NSSCMSContent c;
+ NSSCMSContentInfo *cinfo;
+
+ PORT_Assert(msg != NULL);
+
+ c.pointer = msg;
+ switch (type) {
+ case SEC_OID_PKCS7_SIGNED_DATA:
+ cinfo = &(c.signedData->contentInfo);
+ break;
+ case SEC_OID_PKCS7_ENVELOPED_DATA:
+ cinfo = &(c.envelopedData->contentInfo);
+ break;
+ case SEC_OID_PKCS7_ENCRYPTED_DATA:
+ cinfo = &(c.encryptedData->contentInfo);
+ break;
+ case SEC_OID_PKCS7_DIGESTED_DATA:
+ cinfo = &(c.digestedData->contentInfo);
+ break;
+ default:
+ cinfo = NULL;
+ }
+ return cinfo;
+}
+
+const char *
+NSS_CMSUtil_VerificationStatusToString(NSSCMSVerificationStatus vs)
+{
+ switch (vs) {
+ case NSSCMSVS_Unverified: return "Unverified";
+ case NSSCMSVS_GoodSignature: return "GoodSignature";
+ case NSSCMSVS_BadSignature: return "BadSignature";
+ case NSSCMSVS_DigestMismatch: return "DigestMismatch";
+ case NSSCMSVS_SigningCertNotFound: return "SigningCertNotFound";
+ case NSSCMSVS_SigningCertNotTrusted: return "SigningCertNotTrusted";
+ case NSSCMSVS_SignatureAlgorithmUnknown: return "SignatureAlgorithmUnknown";
+ case NSSCMSVS_SignatureAlgorithmUnsupported: return "SignatureAlgorithmUnsupported";
+ case NSSCMSVS_MalformedSignature: return "MalformedSignature";
+ case NSSCMSVS_ProcessingError: return "ProcessingError";
+ default: return "Unknown";
+ }
+}
+
+SECStatus
+NSS_CMSDEREncode(NSSCMSMessage *cmsg, SECItem *input, SECItem *derOut,
+ PLArenaPool *arena)
+{
+ NSSCMSEncoderContext *ecx;
+ SECStatus rv = SECSuccess;
+ if (!cmsg || !derOut || !arena) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ ecx = NSS_CMSEncoder_Start(cmsg, 0, 0, derOut, arena, 0, 0, 0, 0, 0, 0);
+ if (!ecx) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ if (input) {
+ rv = NSS_CMSEncoder_Update(ecx, (const char*)input->data, input->len);
+ if (rv) {
+ PORT_SetError(SEC_ERROR_BAD_DATA);
+ }
+ }
+ rv |= NSS_CMSEncoder_Finish(ecx);
+ if (rv) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ }
+ return rv;
+}