X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_smime/lib/cryptohi.c?ds=inline diff --git a/Security/libsecurity_smime/lib/cryptohi.c b/Security/libsecurity_smime/lib/cryptohi.c new file mode 100644 index 00000000..d80963c0 --- /dev/null +++ b/Security/libsecurity_smime/lib/cryptohi.c @@ -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 +#include +#include +#include +#include + +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; +}