]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_smime/lib/cryptohi.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_smime / lib / cryptohi.c
diff --git a/OSX/libsecurity_smime/lib/cryptohi.c b/OSX/libsecurity_smime/lib/cryptohi.c
new file mode 100644 (file)
index 0000000..d80963c
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * crypto.h - public data structures and prototypes for the crypto library
+ *
+ * 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.
+ */
+
+#include "cryptohi.h"
+
+#include "secoid.h"
+#include "cmspriv.h"
+#include <security_asn1/secerr.h>
+#include <Security/cssmapi.h>
+#include <Security/cssmapi.h>
+#include <Security/SecKeyPriv.h>
+#include <Security/cssmapple.h>
+
+static CSSM_CSP_HANDLE gCsp = 0;
+static char gCssmInitialized = 0;
+
+/* @@@ Ugly hack casting, but the extra argument at the end will be ignored. */
+static CSSM_API_MEMORY_FUNCS memFuncs =
+{
+    (CSSM_MALLOC)malloc,
+    (CSSM_FREE)free,
+    (CSSM_REALLOC)realloc,
+    (CSSM_CALLOC)calloc,
+    NULL
+};
+
+/*
+ *
+ * SecCspHandleForAlgorithm
+ * @@@ This function should get more parameters like keysize and operation required and use mds.
+ *
+ */
+CSSM_CSP_HANDLE
+SecCspHandleForAlgorithm(CSSM_ALGORITHMS algorithm)
+{
+
+    if (!gCsp)
+    {
+       CSSM_VERSION version = { 2, 0 };
+       CSSM_RETURN rv;
+
+       if (!gCssmInitialized)
+       {
+           CSSM_GUID myGuid = { 0xFADE, 0, 0, { 1, 2, 3, 4, 5, 6, 7, 0 } };
+           CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
+    
+           rv = CSSM_Init (&version, CSSM_PRIVILEGE_SCOPE_NONE, &myGuid, CSSM_KEY_HIERARCHY_NONE, &pvcPolicy, NULL);
+           if (rv)
+               goto loser;
+           gCssmInitialized = 1;
+       }
+
+       rv = CSSM_ModuleLoad(&gGuidAppleCSP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
+       if (rv)
+           goto loser;
+       rv = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &memFuncs, 0, CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &gCsp);
+    }
+
+loser:
+    return gCsp;
+}
+
+CSSM_ALGORITHMS
+SECOID_FindyCssmAlgorithmByTag(SECOidTag algTag)
+{
+    const SECOidData *oidData = SECOID_FindOIDByTag(algTag);
+    return oidData ? oidData->cssmAlgorithm : CSSM_ALGID_NONE;
+}
+
+static SECStatus SEC_CssmRtnToSECStatus(CSSM_RETURN rv)
+{
+    CSSM_RETURN crtn = CSSM_ERRCODE(rv);
+    switch(crtn) {
+       case CSSM_ERRCODE_USER_CANCELED:
+       case CSSM_ERRCODE_OPERATION_AUTH_DENIED:
+       case CSSM_ERRCODE_OBJECT_USE_AUTH_DENIED:
+           return SEC_ERROR_USER_CANCELLED;
+       case CSSM_ERRCODE_NO_USER_INTERACTION:
+           return SEC_ERROR_NO_USER_INTERACTION;
+       case CSSMERR_CSP_KEY_USAGE_INCORRECT:
+           return SEC_ERROR_INADEQUATE_KEY_USAGE;
+       default:
+           fprintf(stderr, "CSSM_SignData returned: %08X\n", (uint32_t)rv);
+           return SEC_ERROR_LIBRARY_FAILURE;
+    }
+}
+
+SECStatus
+SEC_SignData(SECItem *result, unsigned char *buf, int len,
+           SecPrivateKeyRef pk, SECOidTag digAlgTag, SECOidTag sigAlgTag)
+{
+    const CSSM_ACCESS_CREDENTIALS *accessCred;
+    CSSM_ALGORITHMS algorithm;
+    CSSM_CC_HANDLE cc = 0;
+    CSSM_CSP_HANDLE csp;
+    OSStatus rv;
+    CSSM_DATA dataBuf = { (uint32)len, (uint8 *)buf };
+    CSSM_DATA sig = {};
+    const CSSM_KEY *key;
+
+    algorithm = SECOID_FindyCssmAlgorithmByTag(SecCmsUtilMakeSignatureAlgorithm(digAlgTag, sigAlgTag));
+    if (!algorithm)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+       rv = SECFailure;
+       goto loser;
+    }
+
+    rv = SecKeyGetCSPHandle(pk, &csp);
+    if (rv) {
+        PORT_SetError(SEC_ERROR_BAD_KEY);
+       goto loser;
+    }
+    rv = SecKeyGetCSSMKey(pk, &key);
+    if (rv) {
+        PORT_SetError(SEC_ERROR_BAD_KEY);
+       goto loser;
+    }
+    rv = SecKeyGetCredentials(pk, CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault, &accessCred);
+    if (rv) {
+        PORT_SetError(SEC_ERROR_BAD_KEY);
+       goto loser;
+    }
+
+    rv = CSSM_CSP_CreateSignatureContext(csp, algorithm, accessCred, key, &cc);
+    if (rv) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+       goto loser;
+    }
+
+    rv = CSSM_SignData(cc, &dataBuf, 1, CSSM_ALGID_NONE, &sig);
+    if (rv) {
+        SECErrorCodes code = SEC_CssmRtnToSECStatus(rv);
+        PORT_SetError(code);
+       goto loser;
+    }
+
+    result->Length = sig.Length;
+    result->Data = sig.Data;
+
+loser:
+    if (cc)
+       CSSM_DeleteContext(cc);
+
+    return rv;
+}
+
+SECStatus
+SGN_Digest(SecPrivateKeyRef pk, SECOidTag digAlgTag, SECOidTag sigAlgTag, SECItem *result, SECItem *digest)
+{
+    const CSSM_ACCESS_CREDENTIALS *accessCred;
+    CSSM_ALGORITHMS digalg, sigalg;
+    CSSM_CC_HANDLE cc = 0;
+    CSSM_CSP_HANDLE csp;
+    const CSSM_KEY *key;
+    CSSM_DATA sig = {};
+    OSStatus rv;
+
+    digalg = SECOID_FindyCssmAlgorithmByTag(digAlgTag);
+    sigalg = SECOID_FindyCssmAlgorithmByTag(sigAlgTag);
+    if (!digalg || !sigalg)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+       rv = SECFailure;
+       goto loser;
+    }
+
+    rv = SecKeyGetCSPHandle(pk, &csp);
+    if (rv) {
+        PORT_SetError(SEC_ERROR_BAD_KEY);
+       goto loser;
+    }
+    rv = SecKeyGetCSSMKey(pk, &key);
+    if (rv) {
+        PORT_SetError(SEC_ERROR_BAD_KEY);
+       goto loser;
+    }
+    rv = SecKeyGetCredentials(pk, CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault, &accessCred);
+    if (rv) {
+        PORT_SetError(SEC_ERROR_BAD_KEY);
+       goto loser;
+    }
+
+    rv = CSSM_CSP_CreateSignatureContext(csp, sigalg, accessCred, key, &cc);
+    if (rv) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+       goto loser;
+    }
+
+    rv = CSSM_SignData(cc, digest, 1, digalg, &sig);
+    if (rv) {
+        SECErrorCodes code = SEC_CssmRtnToSECStatus(rv);
+        PORT_SetError(code);
+       goto loser;
+    }
+
+    result->Length = sig.Length;
+    result->Data = sig.Data;
+
+loser:
+    if (cc)
+       CSSM_DeleteContext(cc);
+
+    return rv;
+}
+
+SECStatus
+VFY_VerifyData(unsigned char *buf, int len,
+               SecPublicKeyRef pk, SECItem *sig,
+               SECOidTag digAlgTag, SECOidTag sigAlgTag, void *wincx)
+{
+    SECOidTag algTag;
+    CSSM_ALGORITHMS algorithm;
+    CSSM_CC_HANDLE cc = 0;
+    CSSM_CSP_HANDLE csp;
+    OSStatus rv = SECFailure;
+    CSSM_DATA dataBuf = { (uint32)len, (uint8 *)buf };
+    const CSSM_KEY *key;
+
+    algTag = SecCmsUtilMakeSignatureAlgorithm(digAlgTag, sigAlgTag);
+    algorithm = SECOID_FindyCssmAlgorithmByTag(algTag);
+    if (!algorithm)
+    {
+       rv = algTag == SEC_OID_UNKNOWN ? SecCmsVSSignatureAlgorithmUnknown : SecCmsVSSignatureAlgorithmUnsupported;
+       goto loser;
+    }
+
+    rv = SecKeyGetCSPHandle(pk, &csp);
+    if (rv)
+       goto loser;
+    rv = SecKeyGetCSSMKey(pk, &key);
+    if (rv)
+       goto loser;
+
+    rv = CSSM_CSP_CreateSignatureContext(csp, algorithm, NULL, key, &cc);
+    if (rv)
+       goto loser;
+
+    rv = CSSM_VerifyData(cc, &dataBuf, 1, CSSM_ALGID_NONE, sig);
+
+loser:
+    if (cc)
+       CSSM_DeleteContext(cc);
+
+    return rv;
+}
+
+SECStatus
+VFY_VerifyDigest(SECItem *digest, SecPublicKeyRef pk,
+               SECItem *sig, SECOidTag digAlgTag, SECOidTag sigAlgTag, void *wincx)
+{
+    CSSM_ALGORITHMS sigalg, digalg;
+    CSSM_CC_HANDLE cc = 0;
+    CSSM_CSP_HANDLE csp;
+    const CSSM_KEY *key;
+    OSStatus rv;
+
+    digalg = SECOID_FindyCssmAlgorithmByTag(digAlgTag);
+    sigalg = SECOID_FindyCssmAlgorithmByTag(sigAlgTag);
+    if (!digalg || !sigalg)
+    {
+       rv = digAlgTag == SEC_OID_UNKNOWN  || sigAlgTag == SEC_OID_UNKNOWN ? SecCmsVSSignatureAlgorithmUnknown : SecCmsVSSignatureAlgorithmUnsupported;
+       goto loser;
+    }
+
+    rv = SecKeyGetCSPHandle(pk, &csp);
+    if (rv)
+       goto loser;
+    rv = SecKeyGetCSSMKey(pk, &key);
+    if (rv)
+       goto loser;
+
+    rv = CSSM_CSP_CreateSignatureContext(csp, sigalg, NULL, key, &cc);
+    if (rv)
+       goto loser;
+
+    rv = CSSM_VerifyData(cc, digest, 1, digalg, sig);
+
+loser:
+    if (cc)
+       CSSM_DeleteContext(cc);
+
+    return rv;
+}
+
+SECStatus
+WRAP_PubWrapSymKey(SecPublicKeyRef publickey,
+                  SecSymmetricKeyRef bulkkey,
+                  CSSM_DATA_PTR encKey)
+{
+    CSSM_WRAP_KEY wrappedKey = {};
+    //CSSM_WRAP_KEY wrappedPk = {}
+    //CSSM_KEY upk = {};
+    CSSM_CC_HANDLE cc = 0;
+    CSSM_CSP_HANDLE pkCsp, bkCsp;
+    const CSSM_KEY *pk, *bk, *pubkey;
+    OSStatus rv;
+    CSSM_ACCESS_CREDENTIALS accessCred = {};
+
+    rv = SecKeyGetCSPHandle(publickey, &pkCsp);
+    if (rv)
+       goto loser;
+    rv = SecKeyGetCSSMKey(publickey, &pk);
+    if (rv)
+       goto loser;
+
+    rv = SecKeyGetCSPHandle(bulkkey, &bkCsp);
+    if (rv)
+       goto loser;
+    rv = SecKeyGetCSSMKey(bulkkey, &bk);
+    if (rv)
+       goto loser;
+
+#if 1
+    pubkey = pk;
+#else
+    /* We need to get the publickey out of it's pkCsp and into the bkCsp so we can operate with it. */
+
+    /* Make a NULL wrap symmetric context to extract the public key from pkCsp. */
+    rv = CSSM_CSP_CreateSymmetricContext(pkCsp,
+           CSSM_ALGID_NONE,
+           CSSM_MODE_NONE,
+           NULL, /* accessCred */
+           NULL, /* key */
+           NULL, /* iv */
+           CSSM_PADDING_NONE,
+           NULL, /* reserved */
+           &cc);
+    if (rv)
+       goto loser;
+    rv = CSSM_WrapKey(cc,
+           NULL /* accessCred */,
+           pk,
+           NULL /* descriptiveData */,
+           &wrappedPk);
+    CSSM_DeleteContext(cc);
+    cc = 0;
+
+    /* Make a NULL unwrap symmetric context to import the public key into bkCsp. */
+    rv = CSSM_CSP_CreateSymmetricContext(bkCsp,
+           CSSM_ALGID_NONE,
+           CSSM_MODE_NONE,
+           NULL, /* accessCred */
+           NULL, /* key */
+           NULL, /* iv */
+           CSSM_PADDING_NONE,
+           NULL, /* reserved */
+           &cc);
+    if (rv)
+       goto loser;
+    rv = CSSM_UnwrapKey(cc, NULL, &wrappedPk, usage, attr, NULL /* label */, NULL /* rcc */, &upk, NULL /* descriptiveData */);
+    CSSM_DeleteContext(cc);
+    cc = 0;
+
+    pubkey  = &upk;
+#endif
+
+    rv = CSSM_CSP_CreateAsymmetricContext(bkCsp,
+           pubkey->KeyHeader.AlgorithmId,
+           &accessCred,
+           pubkey,
+           CSSM_PADDING_PKCS1,
+           &cc);
+    if (rv)
+       goto loser;
+
+    {
+       /* Set the wrapped key format to indicate we want just the raw bits encrypted. */
+       CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, sizeof(uint32) };
+       contextAttribute.Attribute.Uint32 = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
+       rv = CSSM_UpdateContextAttributes(cc, 1, &contextAttribute);
+       if (rv)
+           goto loser;
+    }
+
+    {
+       /* Set the mode to CSSM_ALGMODE_PKCS1_EME_V15. */
+       CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_MODE, sizeof(uint32) };
+       contextAttribute.Attribute.Uint32 = CSSM_ALGMODE_NONE; /* CSSM_ALGMODE_PKCS1_EME_V15 */
+       rv = CSSM_UpdateContextAttributes(cc, 1, &contextAttribute);
+       if (rv)
+           goto loser;
+    }
+
+    {
+       // @@@ Stick in an empty initVector to work around a csp bug.
+       CSSM_DATA initVector = {};
+       CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(CSSM_DATA_PTR) };
+       contextAttribute.Attribute.Data = &initVector;
+       rv = CSSM_UpdateContextAttributes(cc, 1, &contextAttribute);
+       if (rv)
+           goto loser;
+    }
+
+    rv = CSSM_WrapKey(cc,
+           &accessCred,
+           bk,
+           NULL, /* descriptiveData */
+           &wrappedKey);
+    if (rv)
+       goto loser;
+
+    // @@@ Fix leaks!
+    if (encKey->Length < wrappedKey.KeyData.Length)
+       abort();
+    encKey->Length = wrappedKey.KeyData.Length;
+    memcpy(encKey->Data, wrappedKey.KeyData.Data, encKey->Length);
+    CSSM_FreeKey(bkCsp, NULL /* credentials */, &wrappedKey, FALSE);
+
+loser:
+    if (cc)
+       CSSM_DeleteContext(cc);
+
+    return rv;
+}
+
+SecSymmetricKeyRef
+WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, CSSM_DATA_PTR encKey, SECOidTag bulkalgtag)
+{
+    SecSymmetricKeyRef bulkkey = NULL;
+    CSSM_WRAP_KEY wrappedKey = {};
+    CSSM_CC_HANDLE cc = 0;
+    CSSM_CSP_HANDLE pkCsp;
+    const CSSM_KEY *pk;
+    CSSM_KEY unwrappedKey = {};
+    const CSSM_ACCESS_CREDENTIALS *accessCred;
+    CSSM_DATA descriptiveData = {};
+    CSSM_ALGORITHMS bulkalg;
+    OSStatus rv;
+
+    rv = SecKeyGetCSPHandle(privkey, &pkCsp);
+    if (rv)
+       goto loser;
+    rv = SecKeyGetCSSMKey(privkey, &pk);
+    if (rv)
+       goto loser;
+    rv = SecKeyGetCredentials(privkey,
+           CSSM_ACL_AUTHORIZATION_DECRYPT, /* @@@ Should be UNWRAP */
+           kSecCredentialTypeDefault,
+           &accessCred);
+    if (rv)
+       goto loser;
+
+    bulkalg = SECOID_FindyCssmAlgorithmByTag(bulkalgtag);
+    if (!bulkalg)
+    {
+       rv = SEC_ERROR_INVALID_ALGORITHM;
+       goto loser;
+    }
+
+    rv = CSSM_CSP_CreateAsymmetricContext(pkCsp,
+           pk->KeyHeader.AlgorithmId,
+           accessCred,
+           pk,
+           CSSM_PADDING_PKCS1,
+           &cc);
+    if (rv)
+       goto loser;
+
+    {
+       // @@@ Stick in an empty initvector to work around a csp bug.
+       CSSM_DATA initVector = {};
+       CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(CSSM_DATA_PTR) };
+       contextAttribute.Attribute.Data = &initVector;
+       rv = CSSM_UpdateContextAttributes(cc, 1, &contextAttribute);
+       if (rv)
+           goto loser;
+    }
+
+    wrappedKey.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
+    wrappedKey.KeyHeader.BlobType = CSSM_KEYBLOB_WRAPPED;
+    wrappedKey.KeyHeader.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
+    wrappedKey.KeyHeader.AlgorithmId = bulkalg;
+    wrappedKey.KeyHeader.KeyClass = CSSM_KEYCLASS_SESSION_KEY;
+    wrappedKey.KeyHeader.WrapAlgorithmId = pk->KeyHeader.AlgorithmId;
+    wrappedKey.KeyHeader.WrapMode = CSSM_ALGMODE_NONE; /* CSSM_ALGMODE_PKCS1_EME_V15 */
+    wrappedKey.KeyData = *encKey;
+
+    rv = CSSM_UnwrapKey(cc,
+           NULL, /* publicKey */
+           &wrappedKey,
+           CSSM_KEYUSE_DECRYPT,
+           CSSM_KEYATTR_EXTRACTABLE /* | CSSM_KEYATTR_RETURN_DATA */,
+           NULL, /* keyLabel */
+           NULL, /* rcc */
+           &unwrappedKey,
+           &descriptiveData);
+    if (rv) {
+        SECErrorCodes code;
+        if (CSSM_ERRCODE(rv) == CSSM_ERRCODE_USER_CANCELED
+            || CSSM_ERRCODE(rv) == CSSM_ERRCODE_OPERATION_AUTH_DENIED
+           || CSSM_ERRCODE(rv) == CSSM_ERRCODE_OBJECT_USE_AUTH_DENIED)
+            code = SEC_ERROR_USER_CANCELLED;
+        else if (CSSM_ERRCODE(rv) == CSSM_ERRCODE_NO_USER_INTERACTION
+                 || rv == CSSMERR_CSP_KEY_USAGE_INCORRECT)
+            code = SEC_ERROR_INADEQUATE_KEY_USAGE;
+        else
+       {
+           fprintf(stderr, "CSSM_UnwrapKey returned: %08X\n", (uint32_t)rv);
+            code = SEC_ERROR_LIBRARY_FAILURE;
+       }
+
+        PORT_SetError(code);
+       goto loser;
+    }
+
+    // @@@ Export this key from the csp/dl and import it to the standard csp
+    rv = SecKeyCreateWithCSSMKey(&unwrappedKey, &bulkkey);
+    if (rv)
+       goto loser;
+
+loser:
+    if (rv)
+       PORT_SetError(rv);
+
+    if (cc)
+       CSSM_DeleteContext(cc);
+
+    return bulkkey;
+}