]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_smime/lib/cmsencdata.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_smime / lib / cmsencdata.c
diff --git a/OSX/libsecurity_smime/lib/cmsencdata.c b/OSX/libsecurity_smime/lib/cmsencdata.c
new file mode 100644 (file)
index 0000000..895b508
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * 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 encryptedData methods.
+ */
+
+#include <Security/SecCmsEncryptedData.h>
+
+#include <Security/SecCmsContentInfo.h>
+
+#include "cmslocal.h"
+
+#include "secitem.h"
+#include "secoid.h"
+#include <security_asn1/secasn1.h>
+#include <security_asn1/secerr.h>
+
+/*
+ * SecCmsEncryptedDataCreate - create an empty encryptedData object.
+ *
+ * "algorithm" specifies the bulk encryption algorithm to use.
+ * "keysize" is the key size.
+ * 
+ * An error results in a return value of NULL and an error set.
+ * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
+ */
+SecCmsEncryptedDataRef
+SecCmsEncryptedDataCreate(SecCmsMessageRef cmsg, SECOidTag algorithm, int keysize)
+{
+    void *mark;
+    SecCmsEncryptedDataRef encd;
+    PLArenaPool *poolp;
+    SECAlgorithmID *pbe_algid;
+    OSStatus rv;
+
+    poolp = cmsg->poolp;
+
+    mark = PORT_ArenaMark(poolp);
+
+    encd = (SecCmsEncryptedDataRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsEncryptedData));
+    if (encd == NULL)
+       goto loser;
+
+    encd->cmsg = cmsg;
+
+    /* version is set in SecCmsEncryptedDataEncodeBeforeStart() */
+
+    switch (algorithm) {
+    /* XXX hmmm... hardcoded algorithms? */
+    case SEC_OID_RC2_CBC:
+    case SEC_OID_DES_EDE3_CBC:
+    case SEC_OID_DES_CBC:
+       rv = SecCmsContentInfoSetContentEncAlg((SecArenaPoolRef)poolp, &(encd->contentInfo), algorithm, NULL, keysize);
+       break;
+    default:
+       /* Assume password-based-encryption.  At least, try that. */
+#if 1
+       // @@@ Fix me
+       pbe_algid = NULL;
+#else
+       pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL);
+#endif
+       if (pbe_algid == NULL) {
+           rv = SECFailure;
+           break;
+       }
+       rv = SecCmsContentInfoSetContentEncAlgID((SecArenaPoolRef)poolp, &(encd->contentInfo), pbe_algid, keysize);
+       SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
+       break;
+    }
+    if (rv != SECSuccess)
+       goto loser;
+
+    PORT_ArenaUnmark(poolp, mark);
+    return encd;
+
+loser:
+    PORT_ArenaRelease(poolp, mark);
+    return NULL;
+}
+
+/*
+ * SecCmsEncryptedDataDestroy - destroy an encryptedData object
+ */
+void
+SecCmsEncryptedDataDestroy(SecCmsEncryptedDataRef encd)
+{
+    /* everything's in a pool, so don't worry about the storage */
+    SecCmsContentInfoDestroy(&(encd->contentInfo));
+    return;
+}
+
+/*
+ * SecCmsEncryptedDataGetContentInfo - return pointer to encryptedData object's contentInfo
+ */
+SecCmsContentInfoRef
+SecCmsEncryptedDataGetContentInfo(SecCmsEncryptedDataRef encd)
+{
+    return &(encd->contentInfo);
+}
+
+/*
+ * SecCmsEncryptedDataEncodeBeforeStart - do all the necessary things to a EncryptedData
+ *     before encoding begins.
+ *
+ * In particular:
+ *  - set the correct version value.
+ *  - get the encryption key
+ */
+OSStatus
+SecCmsEncryptedDataEncodeBeforeStart(SecCmsEncryptedDataRef encd)
+{
+    int version;
+    SecSymmetricKeyRef bulkkey = NULL;
+    CSSM_DATA_PTR dummy;
+    SecCmsContentInfoRef cinfo = &(encd->contentInfo);
+
+    if (SecCmsArrayIsEmpty((void **)encd->unprotectedAttr))
+       version = SEC_CMS_ENCRYPTED_DATA_VERSION;
+    else
+       version = SEC_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
+    
+    dummy = SEC_ASN1EncodeInteger (encd->cmsg->poolp, &(encd->version), version);
+    if (dummy == NULL)
+       return SECFailure;
+
+    /* now get content encryption key (bulk key) by using our cmsg callback */
+    if (encd->cmsg->decrypt_key_cb)
+       bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, 
+                   SecCmsContentInfoGetContentEncAlg(cinfo));
+    if (bulkkey == NULL)
+       return SECFailure;
+
+    /* store the bulk key in the contentInfo so that the encoder can find it */
+    SecCmsContentInfoSetBulkKey(cinfo, bulkkey);
+    CFRelease(bulkkey); /* This assumes the decrypt_key_cb hands us a copy of the key --mb */
+
+    return SECSuccess;
+}
+
+/*
+ * SecCmsEncryptedDataEncodeBeforeData - set up encryption
+ */
+OSStatus
+SecCmsEncryptedDataEncodeBeforeData(SecCmsEncryptedDataRef encd)
+{
+    SecCmsContentInfoRef cinfo;
+    SecSymmetricKeyRef bulkkey;
+    SECAlgorithmID *algid;
+
+    cinfo = &(encd->contentInfo);
+
+    /* find bulkkey and algorithm - must have been set by SecCmsEncryptedDataEncodeBeforeStart */
+    bulkkey = SecCmsContentInfoGetBulkKey(cinfo);
+    if (bulkkey == NULL)
+       return SECFailure;
+    algid = SecCmsContentInfoGetContentEncAlg(cinfo);
+    if (algid == NULL)
+       return SECFailure;
+
+    /* this may modify algid (with IVs generated in a token).
+     * it is therefore essential that algid is a pointer to the "real" contentEncAlg,
+     * not just to a copy */
+    cinfo->ciphcx = SecCmsCipherContextStartEncrypt(encd->cmsg->poolp, bulkkey, algid);
+    CFRelease(bulkkey);
+    if (cinfo->ciphcx == NULL)
+       return SECFailure;
+
+    return SECSuccess;
+}
+
+/*
+ * SecCmsEncryptedDataEncodeAfterData - finalize this encryptedData for encoding
+ */
+OSStatus
+SecCmsEncryptedDataEncodeAfterData(SecCmsEncryptedDataRef encd)
+{
+    if (encd->contentInfo.ciphcx) {
+       SecCmsCipherContextDestroy(encd->contentInfo.ciphcx);
+       encd->contentInfo.ciphcx = NULL;
+    }
+
+    /* nothing to do after data */
+    return SECSuccess;
+}
+
+
+/*
+ * SecCmsEncryptedDataDecodeBeforeData - find bulk key & set up decryption
+ */
+OSStatus
+SecCmsEncryptedDataDecodeBeforeData(SecCmsEncryptedDataRef encd)
+{
+    SecSymmetricKeyRef bulkkey = NULL;
+    SecCmsContentInfoRef cinfo;
+    SECAlgorithmID *bulkalg;
+    OSStatus rv = SECFailure;
+
+    cinfo = &(encd->contentInfo);
+
+    bulkalg = SecCmsContentInfoGetContentEncAlg(cinfo);
+
+    if (encd->cmsg->decrypt_key_cb == NULL)    /* no callback? no key../ */
+       goto loser;
+
+    bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg);
+    if (bulkkey == NULL)
+       /* no success finding a bulk key */
+       goto loser;
+
+    SecCmsContentInfoSetBulkKey(cinfo, bulkkey);
+
+    cinfo->ciphcx = SecCmsCipherContextStartDecrypt(bulkkey, bulkalg);
+    if (cinfo->ciphcx == NULL)
+       goto loser;             /* error has been set by SecCmsCipherContextStartDecrypt */
+
+#if 1
+    // @@@ Not done yet
+#else
+    /* 
+     * HACK ALERT!!
+     * 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(bulkalg)) {
+       SEC_PKCS5KeyAndPassword *keyPwd = (SEC_PKCS5KeyAndPassword *)bulkkey;
+       bulkkey = keyPwd->key;
+    }
+#endif
+
+    /* we are done with (this) bulkkey now. */
+    CFRelease(bulkkey);
+
+    rv = SECSuccess;
+
+loser:
+    return rv;
+}
+
+/*
+ * SecCmsEncryptedDataDecodeAfterData - finish decrypting this encryptedData's content
+ */
+OSStatus
+SecCmsEncryptedDataDecodeAfterData(SecCmsEncryptedDataRef encd)
+{
+    if (encd->contentInfo.ciphcx) {
+       SecCmsCipherContextDestroy(encd->contentInfo.ciphcx);
+       encd->contentInfo.ciphcx = NULL;
+    }
+
+    return SECSuccess;
+}
+
+/*
+ * SecCmsEncryptedDataDecodeAfterEnd - finish decoding this encryptedData
+ */
+OSStatus
+SecCmsEncryptedDataDecodeAfterEnd(SecCmsEncryptedDataRef encd)
+{
+    /* apply final touches */
+    return SECSuccess;
+}