michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "ckmk.h" michael@0: michael@0: /* Sigh, For all the talk about 'ease of use', apple has hidden the interfaces michael@0: * needed to be able to truly use CSSM. These came from their modification michael@0: * to NSS's S/MIME code. The following two functions currently are not michael@0: * part of the SecKey.h interface. michael@0: */ michael@0: OSStatus michael@0: SecKeyGetCredentials michael@0: ( michael@0: SecKeyRef keyRef, michael@0: CSSM_ACL_AUTHORIZATION_TAG authTag, michael@0: int type, michael@0: const CSSM_ACCESS_CREDENTIALS **creds michael@0: ); michael@0: michael@0: /* this function could be implemented using 'SecKeychainItemCopyKeychain' and michael@0: * 'SecKeychainGetCSPHandle' */ michael@0: OSStatus michael@0: SecKeyGetCSPHandle michael@0: ( michael@0: SecKeyRef keyRef, michael@0: CSSM_CSP_HANDLE *cspHandle michael@0: ); michael@0: michael@0: michael@0: typedef struct ckmkInternalCryptoOperationRSAPrivStr michael@0: ckmkInternalCryptoOperationRSAPriv; michael@0: struct ckmkInternalCryptoOperationRSAPrivStr michael@0: { michael@0: NSSCKMDCryptoOperation mdOperation; michael@0: NSSCKMDMechanism *mdMechanism; michael@0: ckmkInternalObject *iKey; michael@0: NSSItem *buffer; michael@0: CSSM_CC_HANDLE cssmContext; michael@0: }; michael@0: michael@0: typedef enum { michael@0: CKMK_DECRYPT, michael@0: CKMK_SIGN michael@0: } ckmkRSAOpType; michael@0: michael@0: /* michael@0: * ckmk_mdCryptoOperationRSAPriv_Create michael@0: */ michael@0: static NSSCKMDCryptoOperation * michael@0: ckmk_mdCryptoOperationRSAPriv_Create michael@0: ( michael@0: const NSSCKMDCryptoOperation *proto, michael@0: NSSCKMDMechanism *mdMechanism, michael@0: NSSCKMDObject *mdKey, michael@0: ckmkRSAOpType type, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: ckmkInternalObject *iKey = (ckmkInternalObject *)mdKey->etc; michael@0: const NSSItem *classItem = nss_ckmk_FetchAttribute(iKey, CKA_CLASS, pError); michael@0: const NSSItem *keyType = nss_ckmk_FetchAttribute(iKey, CKA_KEY_TYPE, pError); michael@0: ckmkInternalCryptoOperationRSAPriv *iOperation; michael@0: SecKeyRef privateKey; michael@0: OSStatus macErr; michael@0: CSSM_RETURN cssmErr; michael@0: const CSSM_KEY *cssmKey; michael@0: CSSM_CSP_HANDLE cspHandle; michael@0: const CSSM_ACCESS_CREDENTIALS *creds = NULL; michael@0: CSSM_CC_HANDLE cssmContext; michael@0: CSSM_ACL_AUTHORIZATION_TAG authType; michael@0: michael@0: /* make sure we have the right objects */ michael@0: if (((const NSSItem *)NULL == classItem) || michael@0: (sizeof(CK_OBJECT_CLASS) != classItem->size) || michael@0: (CKO_PRIVATE_KEY != *(CK_OBJECT_CLASS *)classItem->data) || michael@0: ((const NSSItem *)NULL == keyType) || michael@0: (sizeof(CK_KEY_TYPE) != keyType->size) || michael@0: (CKK_RSA != *(CK_KEY_TYPE *)keyType->data)) { michael@0: *pError = CKR_KEY_TYPE_INCONSISTENT; michael@0: return (NSSCKMDCryptoOperation *)NULL; michael@0: } michael@0: michael@0: privateKey = (SecKeyRef) iKey->u.item.itemRef; michael@0: macErr = SecKeyGetCSSMKey(privateKey, &cssmKey); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR("Getting CSSM Key", macErr); michael@0: *pError = CKR_KEY_HANDLE_INVALID; michael@0: return (NSSCKMDCryptoOperation *)NULL; michael@0: } michael@0: macErr = SecKeyGetCSPHandle(privateKey, &cspHandle); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR("Getting CSP for Key", macErr); michael@0: *pError = CKR_KEY_HANDLE_INVALID; michael@0: return (NSSCKMDCryptoOperation *)NULL; michael@0: } michael@0: switch (type) { michael@0: case CKMK_DECRYPT: michael@0: authType = CSSM_ACL_AUTHORIZATION_DECRYPT; michael@0: break; michael@0: case CKMK_SIGN: michael@0: authType = CSSM_ACL_AUTHORIZATION_SIGN; michael@0: break; michael@0: default: michael@0: *pError = CKR_GENERAL_ERROR; michael@0: #ifdef DEBUG michael@0: fprintf(stderr,"RSAPriv_Create: bad type = %d\n", type); michael@0: #endif michael@0: return (NSSCKMDCryptoOperation *)NULL; michael@0: } michael@0: michael@0: macErr = SecKeyGetCredentials(privateKey, authType, 0, &creds); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR("Getting Credentials for Key", macErr); michael@0: *pError = CKR_KEY_HANDLE_INVALID; michael@0: return (NSSCKMDCryptoOperation *)NULL; michael@0: } michael@0: michael@0: switch (type) { michael@0: case CKMK_DECRYPT: michael@0: cssmErr = CSSM_CSP_CreateAsymmetricContext(cspHandle, CSSM_ALGID_RSA, michael@0: creds, cssmKey, CSSM_PADDING_PKCS1, &cssmContext); michael@0: break; michael@0: case CKMK_SIGN: michael@0: cssmErr = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, michael@0: creds, cssmKey, &cssmContext); michael@0: break; michael@0: default: michael@0: *pError = CKR_GENERAL_ERROR; michael@0: #ifdef DEBUG michael@0: fprintf(stderr,"RSAPriv_Create: bad type = %d\n", type); michael@0: #endif michael@0: return (NSSCKMDCryptoOperation *)NULL; michael@0: } michael@0: if (noErr != cssmErr) { michael@0: CKMK_MACERR("Getting Context for Key", cssmErr); michael@0: *pError = CKR_GENERAL_ERROR; michael@0: return (NSSCKMDCryptoOperation *)NULL; michael@0: } michael@0: michael@0: iOperation = nss_ZNEW(NULL, ckmkInternalCryptoOperationRSAPriv); michael@0: if ((ckmkInternalCryptoOperationRSAPriv *)NULL == iOperation) { michael@0: *pError = CKR_HOST_MEMORY; michael@0: return (NSSCKMDCryptoOperation *)NULL; michael@0: } michael@0: iOperation->mdMechanism = mdMechanism; michael@0: iOperation->iKey = iKey; michael@0: iOperation->cssmContext = cssmContext; michael@0: michael@0: nsslibc_memcpy(&iOperation->mdOperation, michael@0: proto, sizeof(NSSCKMDCryptoOperation)); michael@0: iOperation->mdOperation.etc = iOperation; michael@0: michael@0: return &iOperation->mdOperation; michael@0: } michael@0: michael@0: static void michael@0: ckmk_mdCryptoOperationRSAPriv_Destroy michael@0: ( michael@0: NSSCKMDCryptoOperation *mdOperation, michael@0: NSSCKFWCryptoOperation *fwOperation, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance michael@0: ) michael@0: { michael@0: ckmkInternalCryptoOperationRSAPriv *iOperation = michael@0: (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; michael@0: michael@0: if (iOperation->buffer) { michael@0: nssItem_Destroy(iOperation->buffer); michael@0: } michael@0: if (iOperation->cssmContext) { michael@0: CSSM_DeleteContext(iOperation->cssmContext); michael@0: } michael@0: nss_ZFreeIf(iOperation); michael@0: return; michael@0: } michael@0: michael@0: static CK_ULONG michael@0: ckmk_mdCryptoOperationRSA_GetFinalLength michael@0: ( michael@0: NSSCKMDCryptoOperation *mdOperation, michael@0: NSSCKFWCryptoOperation *fwOperation, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: ckmkInternalCryptoOperationRSAPriv *iOperation = michael@0: (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; michael@0: const NSSItem *modulus = michael@0: nss_ckmk_FetchAttribute(iOperation->iKey, CKA_MODULUS, pError); michael@0: michael@0: return modulus->size; michael@0: } michael@0: michael@0: michael@0: /* michael@0: * ckmk_mdCryptoOperationRSADecrypt_GetOperationLength michael@0: * we won't know the length until we actually decrypt the michael@0: * input block. Since we go to all the work to decrypt the michael@0: * the block, we'll save if for when the block is asked for michael@0: */ michael@0: static CK_ULONG michael@0: ckmk_mdCryptoOperationRSADecrypt_GetOperationLength michael@0: ( michael@0: NSSCKMDCryptoOperation *mdOperation, michael@0: NSSCKFWCryptoOperation *fwOperation, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: const NSSItem *input, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: ckmkInternalCryptoOperationRSAPriv *iOperation = michael@0: (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; michael@0: CSSM_DATA cssmInput; michael@0: CSSM_DATA cssmOutput = { 0, NULL }; michael@0: PRUint32 bytesDecrypted; michael@0: CSSM_DATA remainder = { 0, NULL }; michael@0: NSSItem output; michael@0: CSSM_RETURN cssmErr; michael@0: michael@0: if (iOperation->buffer) { michael@0: return iOperation->buffer->size; michael@0: } michael@0: michael@0: cssmInput.Data = input->data; michael@0: cssmInput.Length = input->size; michael@0: michael@0: cssmErr = CSSM_DecryptData(iOperation->cssmContext, michael@0: &cssmInput, 1, &cssmOutput, 1, michael@0: &bytesDecrypted, &remainder); michael@0: if (CSSM_OK != cssmErr) { michael@0: CKMK_MACERR("Decrypt Failed", cssmErr); michael@0: *pError = CKR_DATA_INVALID; michael@0: return 0; michael@0: } michael@0: /* we didn't suppy any buffers, so it should all be in remainder */ michael@0: output.data = nss_ZNEWARRAY(NULL, char, bytesDecrypted + remainder.Length); michael@0: if (NULL == output.data) { michael@0: free(cssmOutput.Data); michael@0: free(remainder.Data); michael@0: *pError = CKR_HOST_MEMORY; michael@0: return 0; michael@0: } michael@0: output.size = bytesDecrypted + remainder.Length; michael@0: michael@0: if (0 != bytesDecrypted) { michael@0: nsslibc_memcpy(output.data, cssmOutput.Data, bytesDecrypted); michael@0: free(cssmOutput.Data); michael@0: } michael@0: if (0 != remainder.Length) { michael@0: nsslibc_memcpy(((char *)output.data)+bytesDecrypted, michael@0: remainder.Data, remainder.Length); michael@0: free(remainder.Data); michael@0: } michael@0: michael@0: iOperation->buffer = nssItem_Duplicate(&output, NULL, NULL); michael@0: nss_ZFreeIf(output.data); michael@0: if ((NSSItem *) NULL == iOperation->buffer) { michael@0: *pError = CKR_HOST_MEMORY; michael@0: return 0; michael@0: } michael@0: michael@0: return iOperation->buffer->size; michael@0: } michael@0: michael@0: /* michael@0: * ckmk_mdCryptoOperationRSADecrypt_UpdateFinal michael@0: * michael@0: * NOTE: ckmk_mdCryptoOperationRSADecrypt_GetOperationLength is presumed to michael@0: * have been called previously. michael@0: */ michael@0: static CK_RV michael@0: ckmk_mdCryptoOperationRSADecrypt_UpdateFinal michael@0: ( michael@0: NSSCKMDCryptoOperation *mdOperation, michael@0: NSSCKFWCryptoOperation *fwOperation, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: const NSSItem *input, michael@0: NSSItem *output michael@0: ) michael@0: { michael@0: ckmkInternalCryptoOperationRSAPriv *iOperation = michael@0: (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; michael@0: NSSItem *buffer = iOperation->buffer; michael@0: michael@0: if ((NSSItem *)NULL == buffer) { michael@0: return CKR_GENERAL_ERROR; michael@0: } michael@0: nsslibc_memcpy(output->data, buffer->data, buffer->size); michael@0: output->size = buffer->size; michael@0: return CKR_OK; michael@0: } michael@0: michael@0: /* michael@0: * ckmk_mdCryptoOperationRSASign_UpdateFinal michael@0: * michael@0: */ michael@0: static CK_RV michael@0: ckmk_mdCryptoOperationRSASign_UpdateFinal michael@0: ( michael@0: NSSCKMDCryptoOperation *mdOperation, michael@0: NSSCKFWCryptoOperation *fwOperation, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: const NSSItem *input, michael@0: NSSItem *output michael@0: ) michael@0: { michael@0: ckmkInternalCryptoOperationRSAPriv *iOperation = michael@0: (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; michael@0: CSSM_DATA cssmInput; michael@0: CSSM_DATA cssmOutput = { 0, NULL }; michael@0: CSSM_RETURN cssmErr; michael@0: michael@0: cssmInput.Data = input->data; michael@0: cssmInput.Length = input->size; michael@0: michael@0: cssmErr = CSSM_SignData(iOperation->cssmContext, &cssmInput, 1, michael@0: CSSM_ALGID_NONE, &cssmOutput); michael@0: if (CSSM_OK != cssmErr) { michael@0: CKMK_MACERR("Signed Failed", cssmErr); michael@0: return CKR_FUNCTION_FAILED; michael@0: } michael@0: if (cssmOutput.Length > output->size) { michael@0: free(cssmOutput.Data); michael@0: return CKR_BUFFER_TOO_SMALL; michael@0: } michael@0: nsslibc_memcpy(output->data, cssmOutput.Data, cssmOutput.Length); michael@0: free(cssmOutput.Data); michael@0: output->size = cssmOutput.Length; michael@0: michael@0: return CKR_OK; michael@0: } michael@0: michael@0: michael@0: NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation michael@0: ckmk_mdCryptoOperationRSADecrypt_proto = { michael@0: NULL, /* etc */ michael@0: ckmk_mdCryptoOperationRSAPriv_Destroy, michael@0: NULL, /* GetFinalLengh - not needed for one shot Decrypt/Encrypt */ michael@0: ckmk_mdCryptoOperationRSADecrypt_GetOperationLength, michael@0: NULL, /* Final - not needed for one shot operation */ michael@0: NULL, /* Update - not needed for one shot operation */ michael@0: NULL, /* DigetUpdate - not needed for one shot operation */ michael@0: ckmk_mdCryptoOperationRSADecrypt_UpdateFinal, michael@0: NULL, /* UpdateCombo - not needed for one shot operation */ michael@0: NULL, /* DigetKey - not needed for one shot operation */ michael@0: (void *)NULL /* null terminator */ michael@0: }; michael@0: michael@0: NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation michael@0: ckmk_mdCryptoOperationRSASign_proto = { michael@0: NULL, /* etc */ michael@0: ckmk_mdCryptoOperationRSAPriv_Destroy, michael@0: ckmk_mdCryptoOperationRSA_GetFinalLength, michael@0: NULL, /* GetOperationLengh - not needed for one shot Sign/Verify */ michael@0: NULL, /* Final - not needed for one shot operation */ michael@0: NULL, /* Update - not needed for one shot operation */ michael@0: NULL, /* DigetUpdate - not needed for one shot operation */ michael@0: ckmk_mdCryptoOperationRSASign_UpdateFinal, michael@0: NULL, /* UpdateCombo - not needed for one shot operation */ michael@0: NULL, /* DigetKey - not needed for one shot operation */ michael@0: (void *)NULL /* null terminator */ michael@0: }; michael@0: michael@0: /********** NSSCKMDMechansim functions ***********************/ michael@0: /* michael@0: * ckmk_mdMechanismRSA_Destroy michael@0: */ michael@0: static void michael@0: ckmk_mdMechanismRSA_Destroy michael@0: ( michael@0: NSSCKMDMechanism *mdMechanism, michael@0: NSSCKFWMechanism *fwMechanism, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance michael@0: ) michael@0: { michael@0: nss_ZFreeIf(fwMechanism); michael@0: } michael@0: michael@0: /* michael@0: * ckmk_mdMechanismRSA_GetMinKeySize michael@0: */ michael@0: static CK_ULONG michael@0: ckmk_mdMechanismRSA_GetMinKeySize michael@0: ( michael@0: NSSCKMDMechanism *mdMechanism, michael@0: NSSCKFWMechanism *fwMechanism, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: return 384; michael@0: } michael@0: michael@0: /* michael@0: * ckmk_mdMechanismRSA_GetMaxKeySize michael@0: */ michael@0: static CK_ULONG michael@0: ckmk_mdMechanismRSA_GetMaxKeySize michael@0: ( michael@0: NSSCKMDMechanism *mdMechanism, michael@0: NSSCKFWMechanism *fwMechanism, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: return 16384; michael@0: } michael@0: michael@0: /* michael@0: * ckmk_mdMechanismRSA_DecryptInit michael@0: */ michael@0: static NSSCKMDCryptoOperation * michael@0: ckmk_mdMechanismRSA_DecryptInit michael@0: ( michael@0: NSSCKMDMechanism *mdMechanism, michael@0: NSSCKFWMechanism *fwMechanism, michael@0: CK_MECHANISM *pMechanism, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: NSSCKMDObject *mdKey, michael@0: NSSCKFWObject *fwKey, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: return ckmk_mdCryptoOperationRSAPriv_Create( michael@0: &ckmk_mdCryptoOperationRSADecrypt_proto, michael@0: mdMechanism, mdKey, CKMK_DECRYPT, pError); michael@0: } michael@0: michael@0: /* michael@0: * ckmk_mdMechanismRSA_SignInit michael@0: */ michael@0: static NSSCKMDCryptoOperation * michael@0: ckmk_mdMechanismRSA_SignInit michael@0: ( michael@0: NSSCKMDMechanism *mdMechanism, michael@0: NSSCKFWMechanism *fwMechanism, michael@0: CK_MECHANISM *pMechanism, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: NSSCKMDObject *mdKey, michael@0: NSSCKFWObject *fwKey, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: return ckmk_mdCryptoOperationRSAPriv_Create( michael@0: &ckmk_mdCryptoOperationRSASign_proto, michael@0: mdMechanism, mdKey, CKMK_SIGN, pError); michael@0: } michael@0: michael@0: michael@0: NSS_IMPLEMENT_DATA const NSSCKMDMechanism michael@0: nss_ckmk_mdMechanismRSA = { michael@0: (void *)NULL, /* etc */ michael@0: ckmk_mdMechanismRSA_Destroy, michael@0: ckmk_mdMechanismRSA_GetMinKeySize, michael@0: ckmk_mdMechanismRSA_GetMaxKeySize, michael@0: NULL, /* GetInHardware - default false */ michael@0: NULL, /* EncryptInit - default errs */ michael@0: ckmk_mdMechanismRSA_DecryptInit, michael@0: NULL, /* DigestInit - default errs*/ michael@0: ckmk_mdMechanismRSA_SignInit, michael@0: NULL, /* VerifyInit - default errs */ michael@0: ckmk_mdMechanismRSA_SignInit, /* SignRecoverInit */ michael@0: NULL, /* VerifyRecoverInit - default errs */ michael@0: NULL, /* GenerateKey - default errs */ michael@0: NULL, /* GenerateKeyPair - default errs */ michael@0: NULL, /* GetWrapKeyLength - default errs */ michael@0: NULL, /* WrapKey - default errs */ michael@0: NULL, /* UnwrapKey - default errs */ michael@0: NULL, /* DeriveKey - default errs */ michael@0: (void *)NULL /* null terminator */ michael@0: };