static int kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA * rsa, int padding) { struct kc_rsa *kc = RSA_get_app_data(rsa); CSSM_RETURN cret; OSStatus ret; const CSSM_ACCESS_CREDENTIALS *creds; SecKeyRef privKeyRef = kc->pkey; CSSM_CSP_HANDLE cspHandle; const CSSM_KEY *cssmKey; CSSM_CC_HANDLE handle = 0; CSSM_DATA out, in, rem; int fret = 0; CSSM_SIZE outlen = 0; char remdata[1024]; if (padding != RSA_PKCS1_PADDING) return -1; cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); if(cret) heim_abort("SecKeyGetCSSMKey failed: %d", (int)cret); cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); if(cret) heim_abort("SecKeyGetCSPHandle failed: %d", (int)cret); ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeNoUI, &creds); if(ret) heim_abort("SecKeyGetCredentials failed: %d", (int)ret); ret = CSSM_CSP_CreateAsymmetricContext (cspHandle, CSSM_ALGID_RSA, creds, cssmKey, CSSM_PADDING_PKCS1, &handle); if(ret) heim_abort("CSSM_CSP_CreateAsymmetricContext failed: %d", (int)ret); in.Data = (uint8 *)from; in.Length = flen; out.Data = (uint8 *)to; out.Length = kc->keysize; rem.Data = (uint8 *)remdata; rem.Length = sizeof(remdata); cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem); if(cret) { /* cssmErrorString(cret); */ fret = -1; } else fret = (int)out.Length; if(handle) CSSM_DeleteContext(handle); return fret; }
/* * Decrypt. * plainText->Data is allocated by the CSP and must be freed (via * free()) by caller. */ CSSM_RETURN cdsaDecrypt( CSSM_CSP_HANDLE cspHandle, const CSSM_KEY *key, const CSSM_DATA *cipherText, CSSM_DATA_PTR plainText) { CSSM_RETURN crtn; CSSM_CC_HANDLE ccHandle; CSSM_DATA remData = {0, NULL}; uint32 bytesDecrypted; crtn = genCryptHandle(cspHandle, key, &ivCommon, &ccHandle); if(crtn) { return crtn; } plainText->Length = 0; plainText->Data = NULL; crtn = CSSM_DecryptData(ccHandle, cipherText, 1, plainText, 1, &bytesDecrypted, &remData); CSSM_DeleteContext(ccHandle); if(crtn) { return crtn; } plainText->Length = bytesDecrypted; if(remData.Length != 0) { /* append remaining data to plainText */ uint32 newLen = plainText->Length + remData.Length; plainText->Data = (uint8 *)appRealloc(plainText->Data, newLen, NULL); memmove(plainText->Data + plainText->Length, remData.Data, remData.Length); plainText->Length = newLen; appFree(remData.Data, NULL); } return CSSM_OK; }
static int badDecrypt( CSSM_CSP_HANDLE cspHand, CSSM_KEY_PTR key, const char *keyAlgStr, CSSM_ALGORITHMS opAlg, CSSM_RETURN expectRtn, CSSM_BOOL quiet, const char *goodUseStr, const char *badUseStr) { CSSM_CC_HANDLE cryptHand; CSSM_DATA ctext = {4, (uint8 *)"foo"}; CSSM_DATA ptext = {0, NULL}; CSSM_DATA remData = {0, NULL}; CSSM_RETURN crtn; CSSM_SIZE bytesDecrypted; int irtn; cryptHand = genCryptHandle(cspHand, opAlg, CSSM_ALGMODE_NONE, CSSM_PADDING_NONE, key, NULL /* key2 */, NULL /* iv */, 0, 0); if(cryptHand == 0) { return testError(quiet); } crtn = CSSM_DecryptData(cryptHand, &ctext, 1, &ptext, 1, &bytesDecrypted, &remData); if(crtn != expectRtn) { printf("***Testing %s key w/%s during %s:\n", keyAlgStr, goodUseStr, badUseStr); printf(" CSSM_DecryptData: expect %s\n", cssmErrToStr(expectRtn)); printf(" CSSM_DecryptData: got %s\n", cssmErrToStr(crtn)); irtn = testError(quiet); } else { irtn = 0; } /* assume no ptext or remdata - OK? */ CSSM_DeleteContext(cryptHand); return irtn; }
CFDataRef decodePrivateKeyHeader(SecKeychainRef keychain, const FVPrivateKeyHeader &inHeader) { // kSecKeyLabel is defined in libsecurity_keychain/lib/SecKey.h SecKeychainAttribute attrs[] = { { 6 /* kSecKeyLabel */, inHeader.publicKeyHashSize, const_cast<uint8 *>(inHeader.publicKeyHash) } }; SecKeychainAttributeList attrList = { sizeof(attrs) / sizeof(SecKeychainAttribute), attrs }; CSSM_CSP_HANDLE cspHandle = 0; const CSSM_KEY *cssmKey = NULL; const CSSM_ACCESS_CREDENTIALS *accessCred = NULL; CSSM_CC_HANDLE cc = 0; SecKeychainSearchRef _searchRef; throwIfError(SecKeychainSearchCreateFromAttributes(keychain, (SecItemClass) CSSM_DL_DB_RECORD_PRIVATE_KEY, &attrList, &_searchRef)); CFRef<SecKeychainSearchRef> searchRef(_searchRef); SecKeychainItemRef _item; if (SecKeychainSearchCopyNext(searchRef, &_item) != 0) { return NULL; // XXX possibly should throw here? } CFRef<SecKeyRef> keyItem(reinterpret_cast<SecKeyRef>(_item)); throwIfError(SecKeyGetCSPHandle(keyItem, &cspHandle)); throwIfError(SecKeyGetCSSMKey(keyItem, &cssmKey)); throwIfError(SecKeyGetCredentials(keyItem, CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault, &accessCred)); throwIfError(CSSM_CSP_CreateAsymmetricContext(cspHandle, cssmKey->KeyHeader.AlgorithmId, accessCred, cssmKey, CSSM_PADDING_PKCS1, &cc)); CFDataRef result; try { CssmMemoryFunctions memFuncs; throwIfError(CSSM_GetAPIMemoryFunctions(cspHandle, &memFuncs)); CssmMemoryFunctionsAllocator allocator(memFuncs); const CssmData cipherBuf(const_cast<uint8 *>(inHeader.encryptedBlob), inHeader.encryptedBlobSize); CssmAutoData clearBuf(allocator); CssmAutoData remData(allocator); size_t bytesDecrypted; CSSM_RETURN crx = CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get()); secinfo("FDERecovery", "decodePrivateKeyHeader: CSSM_DecryptData result: %d", crx); throwIfError(crx); // throwIfError(CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get())); clearBuf.length(bytesDecrypted); // rawKey.copy(clearBuf.get()); result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)clearBuf.get().data(), clearBuf.get().length()); // result = parseKeyBlob(clearBuf.get()); } catch(...) { CSSM_DeleteContext(cc); throw; } throwIfError(CSSM_DeleteContext(cc)); return result; }
/* * Decrypt (typically, an encrypted P7 ContentInfo contents) */ CSSM_RETURN p12Decrypt( CSSM_CSP_HANDLE cspHand, const CSSM_DATA &cipherText, CSSM_ALGORITHMS keyAlg, CSSM_ALGORITHMS encrAlg, CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only uint32 keySizeInBits, uint32 blockSizeInBytes, // for IV CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. uint32 iterCount, const CSSM_DATA &salt, /* exactly one of the following two must be valid */ const CSSM_DATA *pwd, // unicode external representation const CSSM_KEY *passKey, SecNssCoder &coder, // for mallocing plainText CSSM_DATA &plainText) { CSSM_RETURN crtn; CSSM_KEY ckey; CSSM_CC_HANDLE ccHand = 0; CSSM_DATA ourPtext = {0, NULL}; CSSM_DATA remData = {0, NULL}; /* P12 style IV derivation, optional */ CSSM_DATA iv = {0, NULL}; CSSM_DATA_PTR ivPtr = NULL; if(blockSizeInBytes) { coder.allocItem(iv, blockSizeInBytes); ivPtr = &iv; } /* P12 style key derivation */ crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, keySizeInBits, iterCount, salt, pwd, passKey, iv); if(crtn) { return crtn; } /* subsequent errors to errOut: */ /* CSSM context */ crtn = CSSM_CSP_CreateSymmetricContext(cspHand, encrAlg, mode, NULL, // access cred &ckey, ivPtr, // InitVector, optional padding, NULL, // Params &ccHand); if(crtn) { cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn); goto errOut; } /* go - CSP mallocs ptext and rem data */ CSSM_SIZE bytesDecrypted; crtn = CSSM_DecryptData(ccHand, &cipherText, 1, &ourPtext, 1, &bytesDecrypted, &remData); if(crtn) { cuPrintError("CSSM_DecryptData", crtn); } else { coder.allocCopyItem(ourPtext, plainText); plainText.Length = bytesDecrypted; /* plaintext copied into coder space; free the memory allocated * by the CSP */ freeCssmMemory(cspHand, ourPtext.Data); } /* an artifact of CSPFullPLuginSession - this never contains * valid data but sometimes gets mallocds */ if(remData.Data) { freeCssmMemory(cspHand, remData.Data); } errOut: if(ccHand) { CSSM_DeleteContext(ccHand); } CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); return crtn; }
/* * CDSA private key decrypt with blinding option. */ static CSSM_RETURN _cspDecrypt(CSSM_CSP_HANDLE cspHand, uint32 algorithm, // CSSM_ALGID_FEED, etc. uint32 mode, // CSSM_ALGMODE_CBC, etc. - only for symmetric algs CSSM_PADDING padding, // CSSM_PADDING_PKCS1, etc. CSSM_BOOL blinding, const CSSM_KEY *key, // public or session key const CSSM_DATA *ctext, CSSM_DATA_PTR ptext) // RETURNED { CSSM_CC_HANDLE cryptHand; CSSM_RETURN crtn; CSSM_RETURN ocrtn = CSSM_OK; CSSM_SIZE bytesDecrypted; CSSM_DATA remData = {0, NULL}; cryptHand = genCryptHandle(cspHand, algorithm, mode, padding, key, NULL, // pubKey, NULL, // iv, 0, // effectiveKeySizeInBits, 0); // rounds if(cryptHand == 0) { return CSSMERR_CSP_INTERNAL_ERROR; } if(blinding) { CSSM_CONTEXT_ATTRIBUTE newAttr; newAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; newAttr.AttributeLength = sizeof(uint32); newAttr.Attribute.Uint32 = 1; crtn = CSSM_UpdateContextAttributes(cryptHand, 1, &newAttr); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } crtn = CSSM_DecryptData(cryptHand, ctext, 1, ptext, 1, &bytesDecrypted, &remData); if(crtn == CSSM_OK) { // NOTE: We return the proper length in ptext.... ptext->Length = bytesDecrypted; // FIXME - sometimes get mallocd RemData here, but never any valid data // there...side effect of CSPFullPluginSession's buffer handling logic; // but will we ever actually see valid data in RemData? So far we never // have.... if(remData.Data != NULL) { appFree(remData.Data, NULL); } } else { printError("CSSM_DecryptData", crtn); ocrtn = crtn; } crtn = CSSM_DeleteContext(cryptHand); if(crtn) { printError("CSSM_DeleteContext", crtn); ocrtn = crtn; } return ocrtn; }
static int doDecrypt( CSSM_CSP_HANDLE cspHand, const char *algStr, CSSM_KEY_PTR key, // session, private CSSM_ALGORITHMS encrAlg, CSSM_ENCRYPT_MODE encrMode, CSSM_PADDING encrPad, DecrResult expResult, CSSM_BOOL quiet) { uint8 ctextData[CTEXT_SIZE]; CSSM_DATA ctext = {CTEXT_SIZE, ctextData}; uint8 someIvData[IV_SIZE]; CSSM_DATA someIv = {IV_SIZE, someIvData}; /* * I have not found a way to guarantee decrypt failure here, no matter * what ctext and IV I specify. We can't just do an encrypt and * munge because we might be testing a bad (expired) key. * We might have to redesign, first generating a good key, then an * expired key from it...? Until then this test is loose about * handling "key is good" detection. */ memset(ctextData, 0, CTEXT_SIZE); // guaranteed bad padding memset(someIvData, 0, IV_SIZE); CSSM_CC_HANDLE cryptHand = 0; CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); if(key->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY) { crtn = CSSM_CSP_CreateSymmetricContext(cspHand, encrAlg, encrMode, NULL, // access cred key, &someIv, encrPad, NULL, // Params &cryptHand); if(crtn) { printError("CSSM_CSP_CreateSymmetricContext", crtn); return testError(quiet); } } else if(key->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) { crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, encrAlg, &creds, // access key, encrPad, &cryptHand); if(crtn) { printError("CSSM_CSP_CreateAsymmetricContext", crtn); return testError(quiet); } } else { printf("***BRRZAP! Only decrypt with session and private" " keys\n"); exit(1); } CSSM_DATA ptext = {0, NULL}; CSSM_DATA remData = {0, NULL}; CSSM_SIZE bDecr; int irtn = 0; crtn = CSSM_DecryptData(cryptHand, &ctext, 1, &ptext, 1, &bDecr, &remData); switch(expResult) { case DR_BadStartDate: if(crtn != CSSMERR_CSP_APPLE_INVALID_KEY_START_DATE) { printf("***Decrypt with %s: expected INVALID_KEY_START_DATE, " "got %s.\n", algStr, cssmErrToStr(crtn)); irtn = testError(quiet); } break; case DR_BadEndDate: if(crtn != CSSMERR_CSP_APPLE_INVALID_KEY_END_DATE) { printf("***Decrypt with %s: expected INVALID_KEY_END_DATE, " "got %s.\n", algStr, cssmErrToStr(crtn)); irtn = testError(quiet); } break; case DR_BadData: switch(crtn) { case CSSM_OK: // good data, seen sometimes case CSSMERR_CSP_INVALID_DATA: // common case case CSSMERR_CSP_INTERNAL_ERROR: // default case in CSP's // throwRsaDsa() :-( break; default: printf("***Decrypt with %s: expected INVALID_DATA or OK, " "got %s.\n", algStr, cssmErrToStr(crtn)); irtn = testError(quiet); break; } break; } appFreeCssmData(&ptext, CSSM_FALSE); appFreeCssmData(&remData, CSSM_FALSE); CSSM_DeleteContext(cryptHand); return irtn; }