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;
}
示例#3
0
/*
 * 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;
}