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; }
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; }
/* * Cook up a symmetric encryption context for the specified key, * inferring all needed attributes solely from the key algorithm. * This is obviously not a one-size-fits all function, but rather * the "most common case". If you need to encrypt/decrypt with other * padding, mode, etc., do it yourself. */ static CSSM_RETURN genCryptHandle( CSSM_CSP_HANDLE cspHandle, const CSSM_KEY *key, const CSSM_DATA *ivPtr, CSSM_CC_HANDLE *ccHandle) { CSSM_ALGORITHMS keyAlg = key->KeyHeader.AlgorithmId; CSSM_ALGORITHMS encrAlg; CSSM_ENCRYPT_MODE encrMode = CSSM_ALGMODE_NONE; CSSM_PADDING encrPad = CSSM_PADDING_NONE; CSSM_RETURN crtn; CSSM_CC_HANDLE ccHand = 0; CSSM_ACCESS_CREDENTIALS creds; CSSM_BOOL isSymmetric = CSSM_TRUE; /* * Infer algorithm - ususally it's the same as in the key itself */ switch(keyAlg) { case CSSM_ALGID_3DES_3KEY: encrAlg = CSSM_ALGID_3DES_3KEY_EDE; break; default: encrAlg = keyAlg; break; } /* infer mode and padding */ switch(encrAlg) { /* 8-byte block ciphers */ case CSSM_ALGID_DES: case CSSM_ALGID_3DES_3KEY_EDE: case CSSM_ALGID_RC5: case CSSM_ALGID_RC2: encrMode = CSSM_ALGMODE_CBCPadIV8; encrPad = CSSM_PADDING_PKCS5; break; /* 16-byte block ciphers */ case CSSM_ALGID_AES: encrMode = CSSM_ALGMODE_CBCPadIV8; encrPad = CSSM_PADDING_PKCS7; break; /* stream ciphers */ case CSSM_ALGID_ASC: case CSSM_ALGID_RC4: encrMode = CSSM_ALGMODE_NONE; encrPad = CSSM_PADDING_NONE; break; /* RSA asymmetric */ case CSSM_ALGID_RSA: /* encrMode not used */ encrPad = CSSM_PADDING_PKCS1; isSymmetric = CSSM_FALSE; break; default: /* don't wing it - abort */ return CSSMERR_CSP_INTERNAL_ERROR; } memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); if(isSymmetric) { crtn = CSSM_CSP_CreateSymmetricContext(cspHandle, encrAlg, encrMode, NULL, // access cred key, ivPtr, // InitVector encrPad, NULL, // Params &ccHand); } else { crtn = CSSM_CSP_CreateAsymmetricContext(cspHandle, encrAlg, &creds, // access key, encrPad, &ccHand); } if(crtn) { return crtn; } *ccHandle = ccHand; return CSSM_OK; }
/* wrap key function. */ static CSSM_RETURN wrapKey(CSSM_CSP_HANDLE cspHand, const CSSM_KEY_PTR unwrappedKey, // must be ref const CSSM_KEY_PTR wrappingKey, CSSM_ALGORITHMS wrapAlg, CSSM_ENCRYPT_MODE wrapMode, CSSM_KEYBLOB_FORMAT wrapFormat, // NONE, PKCS7, PKCS8 CSSM_PADDING wrapPad, CSSM_KEY_PTR wrappedKey) // RETURNED { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_RETURN crtn2; #if WRAP_KEY_REQUIRES_CREDS CSSM_ACCESS_CREDENTIALS creds; #endif #if 0 if(unwrappedKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) { printf("Hey! you can only wrap a reference key!\n"); return CSSM_ERRCODE_INTERNAL_ERROR; } #endif memset(wrappedKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); /* special case for NULL wrap - no wrapping key */ if((wrappingKey == NULL) || (wrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) { crtn = CSSM_CSP_CreateSymmetricContext(cspHand, wrapAlg, wrapMode, &creds, // accessCred wrappingKey, &initVector, wrapPad, // Padding NULL, // Reserved &ccHand); if(crtn) { printError("cspWrapKey/CreateContext", crtn); return CSSM_ERRCODE_INTERNAL_ERROR; } } else { crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, wrapAlg, &creds, // passPhrase wrappingKey, wrapPad, // Padding &ccHand); if(crtn) { printError("cspWrapKey/CreateContext", crtn); return CSSM_ERRCODE_INTERNAL_ERROR; } /* CMS requires 8-byte IV */ crtn = AddContextAttribute(ccHand, CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(CSSM_DATA), CAT_Ptr, &initVector, 0); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } if(wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) { /* only add this attribute if it's not the default */ CSSM_CONTEXT_ATTRIBUTE attr; attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT; attr.AttributeLength = sizeof(uint32); attr.Attribute.Uint32 = wrapFormat; crtn = CSSM_UpdateContextAttributes( ccHand, 1, &attr); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } crtn = CSSM_WrapKey(ccHand, #if WRAP_KEY_REQUIRES_CREDS &creds, #else NULL, // AccessCred #endif unwrappedKey, NULL, // DescriptiveData wrappedKey); if(crtn != CSSM_OK) { printError("CSSM_WrapKey", crtn); } if((crtn2 = CSSM_DeleteContext(ccHand))) { printError("CSSM_DeleteContext", crtn2); } return crtn; }
/* unwrap key function. */ static CSSM_RETURN unwrapKey(CSSM_CSP_HANDLE cspHand, const CSSM_KEY_PTR wrappedKey, const CSSM_KEY_PTR unwrappingKey, CSSM_ALGORITHMS unwrapAlg, CSSM_ENCRYPT_MODE unwrapMode, CSSM_PADDING unwrapPad, CSSM_KEY_PTR unwrappedKey, // RETURNED const unsigned char *keyLabel, unsigned keyLabelLen) { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_RETURN crtn2; CSSM_DATA labelData; uint32 keyAttr; CSSM_DATA descData = { 0, NULL }; CSSM_ACCESS_CREDENTIALS creds; memset(unwrappedKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); if((unwrappingKey == NULL) || (unwrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) { crtn = CSSM_CSP_CreateSymmetricContext(cspHand, unwrapAlg, unwrapMode, &creds, // accessCreds unwrappingKey, &initVector, unwrapPad, // Padding 0, // Reserved &ccHand); if(crtn) { printError("cspUnwrapKey/CreateContext", crtn); return CSSM_ERRCODE_INTERNAL_ERROR; } } else { crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, unwrapAlg, &creds, // passPhrase, unwrappingKey, unwrapPad, // Padding &ccHand); if(crtn) { printError("cspUnwrapKey/CreateContext", crtn); return CSSM_ERRCODE_INTERNAL_ERROR; } /* CMS requires 8-byte IV */ crtn = AddContextAttribute(ccHand, CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(CSSM_DATA), CAT_Ptr, &initVector, 0); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } labelData.Data = (uint8 *)keyLabel; labelData.Length = keyLabelLen; /* * New keyAttr - clear some old bits, make sure we ask for ref key */ keyAttr = wrappedKey->KeyHeader.KeyAttr; keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE); keyAttr |= CSSM_KEYATTR_RETURN_REF; crtn = CSSM_UnwrapKey(ccHand, NULL, // PublicKey wrappedKey, CSSM_KEYUSE_ANY, // FIXME keyAttr, &labelData, NULL, // CredAndAclEntry unwrappedKey, &descData); // required if(crtn != CSSM_OK) { printError("CSSM_UnwrapKey", crtn); } if((crtn2 = CSSM_DeleteContext(ccHand))) { printError("CSSM_DeleteContext", crtn2); } return crtn; }
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; }
static int doEncrypt( CSSM_CSP_HANDLE cspHand, const char *algStr, CSSM_KEY_PTR key, // session, public CSSM_ALGORITHMS encrAlg, CSSM_ENCRYPT_MODE encrMode, CSSM_PADDING encrPad, CSSM_RETURN expRtn, // expected result CSSM_BOOL quiet) { uint8 ptextData[PTEXT_SIZE]; CSSM_DATA ptext = {PTEXT_SIZE, ptextData}; uint8 someIvData[IV_SIZE]; CSSM_DATA someIv = {IV_SIZE, someIvData}; simpleGenData(&ptext, PTEXT_SIZE, PTEXT_SIZE); simpleGenData(&someIv, IV_SIZE, 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_PUBLIC_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 encrypt with session and public keys\n"); exit(1); } CSSM_DATA ctext = {0, NULL}; CSSM_DATA remData = {0, NULL}; CSSM_SIZE bEncr; int irtn = 0; crtn = CSSM_EncryptData(cryptHand, &ptext, 1, &ctext, 1, &bEncr, &remData); if(crtn != expRtn) { if(expRtn == CSSM_OK) { printError("CSSM_EncryptData", crtn); printf("Unexpected error encrypting with %s\n", algStr); } else { printf("***Encrypt with %s: expected %s, got %s.\n", algStr, cssmErrToStr(expRtn), cssmErrToStr(crtn)); } irtn = testError(quiet); } appFreeCssmData(&ctext, CSSM_FALSE); appFreeCssmData(&remData, CSSM_FALSE); CSSM_DeleteContext(cryptHand); return irtn; }