#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;
static CSSM_API_MEMORY_FUNCS memFuncs =
{
(CSSM_MALLOC)malloc,
(CSSM_FREE)free,
(CSSM_REALLOC)realloc,
(CSSM_CALLOC)calloc,
NULL
};
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;
}
SECStatus
SEC_SignData(SecAsn1Item *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;
SecAsn1Item dataBuf = { (uint32)len, (uint8_t *)buf };
SecAsn1Item 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;
if (CSSM_ERRCODE(rv) == CSSM_ERRCODE_USER_CANCELED
|| CSSM_ERRCODE(rv) == CSSM_ERRCODE_OPERATION_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
code = SEC_ERROR_LIBRARY_FAILURE;
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, SecAsn1Item *result, SecAsn1Item *digest)
{
const CSSM_ACCESS_CREDENTIALS *accessCred;
CSSM_ALGORITHMS digalg, sigalg;
CSSM_CC_HANDLE cc = 0;
CSSM_CSP_HANDLE csp;
const CSSM_KEY *key;
SecAsn1Item 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;
if (CSSM_ERRCODE(rv) == CSSM_ERRCODE_USER_CANCELED
|| CSSM_ERRCODE(rv) == CSSM_ERRCODE_OPERATION_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
code = SEC_ERROR_LIBRARY_FAILURE;
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, SecAsn1Item *sig,
SECOidTag digAlgTag, SECOidTag sigAlgTag, void *wincx)
{
SECOidTag algTag;
CSSM_ALGORITHMS algorithm;
CSSM_CC_HANDLE cc = 0;
CSSM_CSP_HANDLE csp;
OSStatus rv = SECFailure;
SecAsn1Item dataBuf = { (uint32)len, (uint8_t *)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(SecAsn1Item *digest, SecPublicKeyRef pk,
SecAsn1Item *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,
SecAsn1Item * encKey)
{
CSSM_WRAP_KEY wrappedKey = {};
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
rv = CSSM_CSP_CreateSymmetricContext(pkCsp,
CSSM_ALGID_NONE,
CSSM_MODE_NONE,
NULL,
NULL,
NULL,
CSSM_PADDING_NONE,
NULL,
&cc);
if (rv)
goto loser;
rv = CSSM_WrapKey(cc,
NULL ,
pk,
NULL ,
&wrappedPk);
CSSM_DeleteContext(cc);
cc = 0;
rv = CSSM_CSP_CreateSymmetricContext(bkCsp,
CSSM_ALGID_NONE,
CSSM_MODE_NONE,
NULL,
NULL,
NULL,
CSSM_PADDING_NONE,
NULL,
&cc);
if (rv)
goto loser;
rv = CSSM_UnwrapKey(cc, NULL, &wrappedPk, usage, attr, NULL , NULL , &upk, NULL );
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;
{
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;
}
{
CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_MODE, sizeof(uint32) };
contextAttribute.Attribute.Uint32 = CSSM_ALGMODE_NONE;
rv = CSSM_UpdateContextAttributes(cc, 1, &contextAttribute);
if (rv)
goto loser;
}
{
SecAsn1Item initVector = {};
CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(SecAsn1Item *) };
contextAttribute.Attribute.Data = &initVector;
rv = CSSM_UpdateContextAttributes(cc, 1, &contextAttribute);
if (rv)
goto loser;
}
rv = CSSM_WrapKey(cc,
&accessCred,
bk,
NULL,
&wrappedKey);
if (rv)
goto loser;
if (encKey->Length < wrappedKey.KeyData.Length)
abort();
encKey->Length = wrappedKey.KeyData.Length;
memcpy(encKey->Data, wrappedKey.KeyData.Data, encKey->Length);
CSSM_FreeKey(bkCsp, NULL , &wrappedKey, FALSE);
loser:
if (cc)
CSSM_DeleteContext(cc);
return rv;
}
SecSymmetricKeyRef
WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, const SecAsn1Item *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;
SecAsn1Item 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,
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;
{
SecAsn1Item initVector = {};
CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(SecAsn1Item *) };
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;
wrappedKey.KeyData = *encKey;
rv = CSSM_UnwrapKey(cc,
NULL,
&wrappedKey,
CSSM_KEYUSE_DECRYPT,
CSSM_KEYATTR_EXTRACTABLE ,
NULL,
NULL,
&unwrappedKey,
&descriptiveData);
if (rv) {
SECErrorCodes code;
if (CSSM_ERRCODE(rv) == CSSM_ERRCODE_USER_CANCELED
|| CSSM_ERRCODE(rv) == CSSM_ERRCODE_OPERATION_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
code = SEC_ERROR_LIBRARY_FAILURE;
PORT_SetError(code);
goto loser;
}
rv = SecKeyCreate(&unwrappedKey, &bulkkey);
if (rv)
goto loser;
loser:
if (rv)
PORT_SetError(rv);
if (cc)
CSSM_DeleteContext(cc);
return bulkkey;
}