]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_smime/lib/cmsutil.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_smime / lib / cmsutil.c
diff --git a/OSX/libsecurity_smime/lib/cmsutil.c b/OSX/libsecurity_smime/lib/cmsutil.c
new file mode 100644 (file)
index 0000000..73587d8
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * 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.
+ */
+
+#include <Security/SecCmsEncoder.h> /* @@@ Remove this when we move the Encoder method. */
+#include <Security/SecCmsSignerInfo.h>
+#include "cmslocal.h"
+
+#include "secitem.h"
+#include "secoid.h"
+#include "cryptohi.h"
+
+#include <security_asn1/secasn1.h>
+#include <security_asn1/secerr.h>
+#include <Security/cssmapi.h>
+#include <Security/cssmapple.h>
+#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
+
+
+/*
+ * SecCmsArraySortByDER - 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).
+ */
+OSStatus
+SecCmsArraySortByDER(void **objs, const SecAsn1Template *objtemplate, void **objs2)
+{
+    PRArenaPool *poolp;
+    int num_objs;
+    CSSM_DATA_PTR *enc_objs;
+    OSStatus rv = SECFailure;
+    int i;
+
+    if (objs == NULL)                                  /* already sorted */
+       return SECSuccess;
+
+    num_objs = SecCmsArrayCount((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.
+     */
+    // Security check to prevent under-allocation
+    if (num_objs<0 || num_objs>=(int)((INT_MAX/sizeof(CSSM_DATA_PTR))-1)) {
+        goto loser;
+    }
+    enc_objs = (CSSM_DATA_PTR *)PORT_ArenaZAlloc(poolp, (num_objs + 1) * sizeof(CSSM_DATA_PTR));
+    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 */
+    SecCmsArraySort((void **)enc_objs, SecCmsUtilDERCompare, objs, objs2);
+
+    rv = SECSuccess;
+
+loser:
+    PORT_FreeArena (poolp, PR_FALSE);
+    return rv;
+}
+
+/*
+ * SecCmsUtilDERCompare - for use with SecCmsArraySort to
+ *  sort arrays of CSSM_DATAs containing DER
+ */
+int
+SecCmsUtilDERCompare(void *a, void *b)
+{
+    CSSM_DATA_PTR der1 = (CSSM_DATA_PTR)a;
+    CSSM_DATA_PTR der2 = (CSSM_DATA_PTR)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->Length != der2->Length)
+       return (der1->Length < der2->Length) ? -1 : 1;
+
+    for (j = 0; j < der1->Length; j++) {
+       if (der1->Data[j] == der2->Data[j])
+           continue;
+       return (der1->Data[j] < der2->Data[j]) ? -1 : 1;
+    }
+    return 0;
+}
+
+/*
+ * SecCmsAlgArrayGetIndexByAlgID - 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
+SecCmsAlgArrayGetIndexByAlgID(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;
+}
+
+/*
+ * SecCmsAlgArrayGetIndexByAlgTag - 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
+SecCmsAlgArrayGetIndexByAlgTag(SECAlgorithmID **algorithmArray, 
+                                 SECOidTag algtag)
+{
+    SECOidData *algid;
+    int i = -1;
+
+    if (algorithmArray == NULL || algorithmArray[0] == NULL)
+       return i;
+
+#ifdef ORDER_N_SQUARED
+    for (i = 0; algorithmArray[i] != NULL; i++) {
+       algid = SECOID_FindOID(&(algorithmArray[i]->algorithm));
+       if (algid->offset == algtag)
+           break;      /* bingo */
+    }
+#else
+    algid = SECOID_FindOIDByTag(algtag);
+    if (!algid) 
+       return i;
+    for (i = 0; algorithmArray[i] != NULL; i++) {
+       if (SECITEM_ItemsAreEqual(&algorithmArray[i]->algorithm, &algid->oid))
+           break;      /* bingo */
+    }
+#endif
+
+    if (algorithmArray[i] == NULL)
+       return -1;      /* not found */
+
+    return i;
+}
+
+CSSM_CC_HANDLE
+SecCmsUtilGetHashObjByAlgID(SECAlgorithmID *algid)
+{
+    SECOidData *oidData = SECOID_FindOID(&(algid->algorithm));
+    if (oidData)
+    {
+       CSSM_ALGORITHMS alg = oidData->cssmAlgorithm;
+       if (alg)
+       {
+           CSSM_CC_HANDLE digobj;
+           CSSM_CSP_HANDLE cspHandle = SecCspHandleForAlgorithm(alg);
+
+           if (!CSSM_CSP_CreateDigestContext(cspHandle, alg, &digobj))
+               return digobj;
+       }
+    }
+
+    return 0;
+}
+
+/*
+ * XXX I would *really* like to not have to do this, but the current
+ * signing interface gives me little choice.
+ */
+SECOidTag
+SecCmsUtilMakeSignatureAlgorithm(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;
+         case SEC_OID_SHA256:
+           return SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
+         case SEC_OID_SHA384:
+           return SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
+         case SEC_OID_SHA512:
+           return SEC_OID_PKCS1_SHA512_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;
+       }
+      case SEC_OID_EC_PUBLIC_KEY:
+       switch(hashalg) {
+         /* 
+          * Note this is only used when signing and verifying signed attributes,
+          * In which case we really do want the combined ECDSA_WithSHA1 alg...
+          */
+         case SEC_OID_SHA1:
+           return SEC_OID_ECDSA_WithSHA1;
+         default:
+           return SEC_OID_UNKNOWN;
+       }
+      default:
+       break;
+    }
+
+    return encalg;             /* maybe it is already the right algid */
+}
+
+const SecAsn1Template *
+SecCmsUtilGetTemplateByTypeTag(SECOidTag type)
+{
+    const SecAsn1Template *template;
+    extern const SecAsn1Template SecCmsSignedDataTemplate[];
+    extern const SecAsn1Template SecCmsEnvelopedDataTemplate[];
+    extern const SecAsn1Template SecCmsEncryptedDataTemplate[];
+    extern const SecAsn1Template SecCmsDigestedDataTemplate[];
+
+    switch (type) {
+    case SEC_OID_PKCS7_SIGNED_DATA:
+       template = SecCmsSignedDataTemplate;
+       break;
+    case SEC_OID_PKCS7_ENVELOPED_DATA:
+       template = SecCmsEnvelopedDataTemplate;
+       break;
+    case SEC_OID_PKCS7_ENCRYPTED_DATA:
+       template = SecCmsEncryptedDataTemplate;
+       break;
+    case SEC_OID_PKCS7_DIGESTED_DATA:
+       template = SecCmsDigestedDataTemplate;
+       break;
+    default:
+    case SEC_OID_PKCS7_DATA:
+    case SEC_OID_OTHER:
+       template = NULL;
+       break;
+    }
+    return template;
+}
+
+size_t
+SecCmsUtilGetSizeByTypeTag(SECOidTag type)
+{
+    size_t size;
+
+    switch (type) {
+    case SEC_OID_PKCS7_SIGNED_DATA:
+       size = sizeof(SecCmsSignedData);
+       break;
+    case SEC_OID_PKCS7_ENVELOPED_DATA:
+       size = sizeof(SecCmsEnvelopedData);
+       break;
+    case SEC_OID_PKCS7_ENCRYPTED_DATA:
+       size = sizeof(SecCmsEncryptedData);
+       break;
+    case SEC_OID_PKCS7_DIGESTED_DATA:
+       size = sizeof(SecCmsDigestedData);
+       break;
+    default:
+    case SEC_OID_PKCS7_DATA:
+       size = 0;
+       break;
+    }
+    return size;
+}
+
+SecCmsContentInfoRef
+SecCmsContentGetContentInfo(void *msg, SECOidTag type)
+{
+    SecCmsContent c;
+    SecCmsContentInfoRef cinfo;
+
+    if (!msg)
+       return 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;
+}
+
+// @@@ Return CFStringRef and do localization.
+const char *
+SecCmsUtilVerificationStatusToString(SecCmsVerificationStatus vs)
+{
+    switch (vs) {
+    case SecCmsVSUnverified:                   return "Unverified";
+    case SecCmsVSGoodSignature:                        return "GoodSignature";
+    case SecCmsVSBadSignature:                 return "BadSignature";
+    case SecCmsVSDigestMismatch:               return "DigestMismatch";
+    case SecCmsVSSigningCertNotFound:          return "SigningCertNotFound";
+    case SecCmsVSSigningCertNotTrusted:                return "SigningCertNotTrusted";
+    case SecCmsVSSignatureAlgorithmUnknown:    return "SignatureAlgorithmUnknown";
+    case SecCmsVSSignatureAlgorithmUnsupported: return "SignatureAlgorithmUnsupported";
+    case SecCmsVSMalformedSignature:           return "MalformedSignature";
+    case SecCmsVSProcessingError:              return "ProcessingError";
+    default:                                   return "Unknown";
+    }
+}
+
+OSStatus
+SecArenaPoolCreate(size_t chunksize, SecArenaPoolRef *outArena)
+{
+    OSStatus status;
+
+    if (!outArena) {
+        status = paramErr;
+        goto loser;
+    }
+
+    *outArena = (SecArenaPoolRef)PORT_NewArena(chunksize);
+    if (*outArena)
+        status = 0;
+    else
+        status = PORT_GetError();
+
+loser:
+    return status;
+}
+
+void
+SecArenaPoolFree(SecArenaPoolRef arena, Boolean zero)
+{
+    PORT_FreeArena((PLArenaPool *)arena, zero);
+}