1/*
2 * Copyright (c) 2010-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25#include "EncryptTransform.h"
26#include "SecEncryptTransform.h"
27#include "EncryptTransformUtilities.h"
28#include "Utilities.h"
29#include "SecDigestTransform.h"
30#include "Digest.h"
31#include <Security/SecRandom.h>
32#include "SecMaskGenerationFunctionTransform.h"
33
34static CFStringRef kEncryptTransformType = CFSTR("Encrypt Transform");
35static CFStringRef kDecryptTransformType = CFSTR("Decrypt Transform");
36//static const char *kEncryptTransformType_cstr = "Encrypt Transform";
37//static const char *kDecryptTransformType_cstr = "Decrypt Transform";
38static uint8 iv[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
39static const CSSM_DATA gKeySalt = {16, iv}; // default Salt for key
40
41dispatch_once_t EncryptDecryptBase::serializerSetUp;
42dispatch_queue_t EncryptDecryptBase::serializerTransformStartingExecution;
43
44/* --------------------------------------------------------------------------
45 Implementation of the EncryptDecryptBase class
46 -------------------------------------------------------------------------- */
47
48/* --------------------------------------------------------------------------
49 method: 		EncryptDecryptBase (Constructor)
50 description: 	Initialize a new instance of a EncryptDecryptBase class
51 -------------------------------------------------------------------------- */
52EncryptDecryptBase::EncryptDecryptBase(CFStringRef type) :
53Transform(type),
54m_cssm_padding(CSSM_PADDING_NONE),
55m_mode(CSSM_ALGMODE_CBCPadIV8),
56m_cssm_key(NULL),
57m_handle((CSSM_CC_HANDLE)0),
58m_forEncryption(FALSE),
59m_processedData(NULL),
60m_accumulator(NULL)
61{
62	m_forEncryption = CFEqual(type, kEncryptTransformType);
63    inputAH = transforms_assume(this->getAH(kSecTransformInputAttributeName, false, false));
64}
65
66/* --------------------------------------------------------------------------
67 method: 		~EncryptDecryptBase (pre-Destructor)
68 description: 	Clean m_handle, let Transform::Finalize() do the rest
69 -------------------------------------------------------------------------- */
70void EncryptDecryptBase::Finalize()
71{
72	if (m_handle != (CSSM_CC_HANDLE)0)
73	{
74		CSSM_CC_HANDLE tmp_handle = m_handle;
75		// Leaving this to the destructor causes occasional crashes.
76		// This may be a CDSA thread afinity bug, or it might be more
77		// local.
78		dispatch_async(mDispatchQueue, ^{
79			CSSM_DeleteContext(tmp_handle);
80		});
81		m_handle = ((CSSM_CC_HANDLE)0);
82	}
83
84	Transform::Finalize();
85}
86
87
88/* --------------------------------------------------------------------------
89 method: 		~EncryptDecryptBase (Destructor)
90 description: 	Clean up the memory of an EncryptDecryptBase object
91 -------------------------------------------------------------------------- */
92EncryptDecryptBase::~EncryptDecryptBase()
93{
94	if (NULL != m_processedData)
95	{
96		CFRelease(m_processedData);
97		m_processedData = NULL;
98	}
99	if (NULL != m_accumulator)
100	{
101		CFRelease(m_accumulator);
102		m_accumulator = NULL;
103	}
104}
105
106/* --------------------------------------------------------------------------
107 method: 		InitializeObject(SecKeyRef key, CFErrorRef *error)
108 description: 	Initialize an instance of the base encrypt/decrypt transform
109 -------------------------------------------------------------------------- */
110bool EncryptDecryptBase::InitializeObject(SecKeyRef key, CFErrorRef *error)
111{
112	SetAttributeNoCallback(kSecEncryptKey, key);
113	if (error)
114	{
115		*error = NULL;
116	}
117
118	return true;
119}
120
121/* --------------------------------------------------------------------------
122 method: 		SerializedTransformStartingExecution()
123 description: 	Get this transform ready to run, should only be called on
124				the serializerTransformStartingExecution queue
125 -------------------------------------------------------------------------- */
126CFErrorRef EncryptDecryptBase::SerializedTransformStartingExecution()
127{
128	CFErrorRef result = NULL;	// Assume all is well
129	SecKeyRef key = (SecKeyRef) GetAttribute(kSecEncryptKey);
130	if (NULL == key)
131	{
132		return CreateSecTransformErrorRef(kSecTransformErrorAttributeNotFound, "The attribute %@ was not found.", kSecEncryptKey);
133	}
134
135	OSStatus err = errSecSuccess;
136	err = SecKeyGetCSSMKey(key, (const CSSM_KEY **)&m_cssm_key);
137	if (errSecSuccess != err)
138	{
139		CFStringRef result = SecCopyErrorMessageString(err, NULL);
140		CFErrorRef retValue = CreateSecTransformErrorRef(err, "CDSA error (%@).", result);
141		CFRelease(result);
142		return retValue;
143	}
144
145	CSSM_CSP_HANDLE csp;
146	err = SecKeyGetCSPHandle(key, &csp);
147	if (errSecSuccess != err)
148	{
149		CFStringRef result = SecCopyErrorMessageString(err, NULL);
150		CFErrorRef retValue = CreateSecTransformErrorRef(err, "CDSA error (%@).", result);
151		CFRelease(result);
152		return retValue;
153	}
154
155	CSSM_ALGORITHMS	keyAlg = m_cssm_key->KeyHeader.AlgorithmId;
156
157	m_cssm_padding = CSSM_PADDING_NONE;
158	CFStringRef paddingStr = (CFStringRef) GetAttribute(kSecPaddingKey);
159	CFStringRef modeStr = (CFStringRef) GetAttribute (kSecEncryptionMode);
160	CFDataRef ivData = (CFDataRef) GetAttribute(kSecIVKey);
161
162	Boolean hasPadding = (paddingStr != NULL);
163	Boolean hasMode = (modeStr != NULL);
164	Boolean hasIVData = (ivData != NULL);
165	Boolean isSymmetrical = (m_cssm_key->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY);
166
167
168    if (!hasPadding)
169	{
170		if (CSSM_ALGID_RSA == keyAlg || CSSM_ALGID_ECDSA == keyAlg)
171		{
172			m_cssm_padding = CSSM_PADDING_PKCS1;
173		}
174		else
175		{
176			m_cssm_padding = CSSM_PADDING_PKCS7;
177		}
178		m_oaep_padding = false;
179	}
180	else
181	{
182		if (CFStringCompare(kSecPaddingOAEPKey, paddingStr, kCFCompareAnchored)) {
183			m_oaep_padding = false;
184			m_cssm_padding = ConvertPaddingStringToEnum(paddingStr);
185		} else {
186			m_cssm_padding = CSSM_PADDING_NONE;
187			m_oaep_padding = true;
188			m_accumulator = CFDataCreateMutable(NULL, 0);
189			if (!m_accumulator) {
190				return GetNoMemoryErrorAndRetain();
191			}
192		}
193	}
194
195	if (!hasMode)
196	{
197		m_mode = (CSSM_PADDING_NONE == m_cssm_padding) ? CSSM_ALGMODE_CBC_IV8 : CSSM_ALGMODE_CBCPadIV8;
198	}
199	else
200	{
201		m_mode = ConvertEncryptModeStringToEnum(modeStr, (CSSM_PADDING_NONE != m_cssm_padding));
202	}
203
204
205	CSSM_RETURN crtn = CSSM_OK;
206	CSSM_ACCESS_CREDENTIALS	creds;
207	CSSM_ACCESS_CREDENTIALS* credPtr = NULL;
208	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
209
210	err = SecKeyGetCredentials(key,
211	                           (m_forEncryption) ? CSSM_ACL_AUTHORIZATION_ENCRYPT : CSSM_ACL_AUTHORIZATION_DECRYPT,
212	                           kSecCredentialTypeDefault,
213	                           (const CSSM_ACCESS_CREDENTIALS **)&credPtr);
214	if (errSecSuccess != err)
215	{
216		memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
217		credPtr = &creds;
218	}
219
220	if (isSymmetrical)
221	{
222		CSSM_DATA initVector;
223		if (hasIVData)
224		{
225			initVector.Length = CFDataGetLength(ivData);
226			initVector.Data = const_cast<uint8_t*>(CFDataGetBytePtr(ivData));
227		}
228		else
229		{
230			initVector.Length = gKeySalt.Length;
231			initVector.Data = (uint8 *)malloc(initVector.Length);
232			initVector.Data = gKeySalt.Data;
233		}
234
235		crtn = CSSM_CSP_CreateSymmetricContext(csp, keyAlg, m_mode, credPtr, m_cssm_key,
236		                                       &initVector, m_cssm_padding, NULL, &m_handle);
237
238		// Need better error here
239		if (crtn != CSSM_OK)
240		{
241			CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
242			CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result);
243			CFRelease(result);
244			return retValue;
245		}
246	}
247	else
248	{
249		crtn = CSSM_CSP_CreateAsymmetricContext(csp, keyAlg, credPtr, m_cssm_key, m_cssm_padding, &m_handle);
250
251		// Need better error here
252		if (crtn != CSSM_OK)
253		{
254			CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
255			CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result);
256			CFRelease(result);
257			return retValue;
258		}
259	}
260
261	// Encryption
262	crtn = (m_forEncryption) ? CSSM_EncryptDataInit(m_handle) : CSSM_DecryptDataInit(m_handle);
263	// Need better error here
264	if (crtn != CSSM_OK)
265	{
266			CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
267			CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA encrypt/decrypt init error (%@).", result);
268			CFRelease(result);
269			return retValue;
270	}
271
272
273	return result;
274}
275
276/* --------------------------------------------------------------------------
277 method: 		TransformStartingExecution()
278 description: 	Get this transform ready to run.
279 NOTE:			the encrypt/decrypt setup is not safe to call for a single
280				key from multiple threads at once, TransformStartingExecution is
281				responsable making sure this doesn't happen,
282				SerializedTransformStartingExecution() does the real set up work.
283 -------------------------------------------------------------------------- */
284CFErrorRef EncryptDecryptBase::TransformStartingExecution()
285{
286
287	dispatch_once(&serializerSetUp, ^{
288		serializerTransformStartingExecution = dispatch_queue_create("com.apple.security.EncryptDecrypt.key-setup", NULL);
289	});
290
291	__block CFErrorRef result = NULL;	// Assume all is well
292
293	dispatch_sync(serializerTransformStartingExecution, ^{
294		result = SerializedTransformStartingExecution();
295	});
296	return result;
297}
298
299/* --------------------------------------------------------------------------
300 method: 		TransformCanExecute
301 description: 	Do we have a key?
302 -------------------------------------------------------------------------- */
303Boolean EncryptDecryptBase::TransformCanExecute()
304{
305	// make sure we have a key -- there may be some circumstance when one isn't available
306	// and besides, it helps test this logic
307	SecKeyRef key = (SecKeyRef) GetAttribute(kSecEncryptKey);
308	return key != NULL;
309}
310
311void EncryptDecryptBase::SendCSSMError(CSSM_RETURN retCode)
312{
313	// make a CFErrorRef for the error message
314	CFStringRef errorString = SecCopyErrorMessageString(retCode, NULL);
315	CFErrorRef errorRef = CreateGenericErrorRef(kCFErrorDomainOSStatus, retCode, "%@", errorString);
316	CFRelease(errorString);
317
318	SendAttribute(kSecTransformOutputAttributeName, errorRef);
319	CFRelease(errorRef);
320}
321
322#warning "This declaration should be in some header"
323void xor_bytes(UInt8 *dst, const UInt8 *src1, const UInt8 *src2, CFIndex length);
324void xor_bytes(UInt8 *dst, const UInt8 *src1, const UInt8 *src2, CFIndex length)
325{
326	// NOTE: this can be made faster, but see if we already have a faster version somewhere first.
327
328	// _mm_xor_ps would be nice here
329	// failing that, getting to an aligned boundry and switching to uint64_t
330	// would be good.
331
332	while (length--) {
333		*dst++ = *src1++ ^ *src2++;
334	}
335}
336
337extern "C" {
338	extern CFDataRef oaep_unpadding_via_c(CFDataRef encodedMessage);
339}
340
341CFDataRef EncryptDecryptBase::remove_oaep_padding(CFDataRef encodedMessage)
342{
343#if 1
344	return oaep_unpadding_via_c(encodedMessage);
345#else
346    CFStringRef hashAlgo = NULL;
347    CFDataRef message = NULL, maskedSeed = NULL, maskedDB = NULL, seedMask = NULL, seed = NULL, dbMask = NULL;
348    CFDataRef pHash = NULL, pHashPrime = NULL;
349    CFDataRef EncodingParameters = NULL;
350    CFErrorRef error = NULL;
351    UInt8 *raw_seed = NULL, *raw_DB = NULL, *addr01 = NULL;
352    SecTransformRef mgf_maskedDB = NULL, mgf_dbMask = NULL, hash = NULL;
353    int hLen = -1;
354	// RSA's OAEP documentation assumes the crypto layer will remove the leading (partial) byte,
355	// but CDSA leaves that responsability to us (we did ask it for "no padding" after all).
356	// (use extraPaddingLength = 0 when using a layer that does strip that byte)
357    const int extraPaddingLength = 1;
358
359	// The numbered steps below correspond to RSA Laboratories' RSAES-OAEP Encryption Scheme
360	// document's numbered steps.
361
362    // NOTE: we omit step 1: "If the length of P is greater than the input limitation for the hash
363    // function (2^61 − 1 octets for SHA-1) then output ‘‘decoding error’’ and stop."; we don't have
364    // ready access to the input limits of the hash functions, and in the real world we won't be
365    // seeing messages that long anyway.
366
367    // (2) If emLen < 2hLen + 1, output ‘‘decoding error’’ and stop.
368    hashAlgo = (CFStringRef)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName);
369	if (hashAlgo == NULL) {
370		hashAlgo = kSecDigestSHA1;
371	}
372    hLen = Digest::LengthForType(hashAlgo);
373    if (CFDataGetLength(encodedMessage) < 2*hLen + 1) {
374        goto out;
375    }
376
377    // (3) Let maskedSeed be the first hLen octets of EM and let maskedDB be the remaining emLen−hLen
378    // octets.
379    maskedSeed = CFDataCreateWithBytesNoCopy(NULL, CFDataGetBytePtr(encodedMessage) +extraPaddingLength, hLen, kCFAllocatorNull);
380    maskedDB = CFDataCreateWithBytesNoCopy(NULL, CFDataGetBytePtr(encodedMessage) + hLen +extraPaddingLength, CFDataGetLength(encodedMessage) - hLen -extraPaddingLength, kCFAllocatorNull);
381
382    // (4) Let seedMask = MGF(maskedDB, hLen).
383    mgf_maskedDB = SecCreateMaskGenerationFunctionTransform(hashAlgo, hLen, &error);
384    if (!mgf_maskedDB) {
385        goto out;
386    }
387    if (!SecTransformSetAttribute(mgf_maskedDB, kSecTransformInputAttributeName, maskedDB, &error)) {
388        goto out;
389    }
390    seedMask = (CFDataRef)SecTransformExecute(mgf_maskedDB, &error);
391    if (!seedMask) {
392        goto out;
393    }
394	(void)transforms_assume(hLen == CFDataGetLength(seedMask));
395
396    // (5) Let seed = maskedSeed ⊕ seedMask.
397    raw_seed = (UInt8*)malloc(hLen);
398    xor_bytes(raw_seed, CFDataGetBytePtr(maskedSeed), CFDataGetBytePtr(seedMask), hLen);
399    seed = CFDataCreateWithBytesNoCopy(NULL, raw_seed, hLen, kCFAllocatorNull);
400    if (!seed) {
401		free(raw_seed);
402		error = GetNoMemoryErrorAndRetain();
403		goto out;
404	}
405    // (6) Let dbMask = MGF (seed, emLen − hLen).
406    mgf_dbMask = SecCreateMaskGenerationFunctionTransform(hashAlgo, CFDataGetLength(encodedMessage) - hLen, &error);
407    if (!mgf_dbMask) {
408        goto out;
409    }
410    if (!SecTransformSetAttribute(mgf_dbMask, kSecTransformInputAttributeName, seed, &error)) {
411        goto out;
412    }
413    dbMask = (CFDataRef)SecTransformExecute(mgf_dbMask, &error);
414    if (!dbMask) {
415        goto out;
416    }
417
418    // (7) Let DB = maskedDB ⊕ dbMask.
419    raw_DB = (UInt8*)malloc(CFDataGetLength(dbMask));
420    xor_bytes(raw_DB, CFDataGetBytePtr(maskedDB), CFDataGetBytePtr(dbMask), CFDataGetLength(dbMask));
421
422    // (8) Let pHash = Hash(P), an octet string of length hLen.
423    hash = SecDigestTransformCreate(hashAlgo, 0, &error);
424	if (!hash) {
425		goto out;
426	}
427    EncodingParameters = (CFDataRef)this->GetAttribute(kSecOAEPEncodingParametersAttributeName);
428	if (EncodingParameters) {
429		CFRetain(EncodingParameters);
430	} else {
431		EncodingParameters = CFDataCreate(NULL, (UInt8*)"", 0);
432		if (!EncodingParameters) {
433			goto out;
434		}
435	}
436	if (!SecTransformSetAttribute(hash, kSecTransformInputAttributeName, EncodingParameters, &error)) {
437		goto out;
438	}
439
440	pHash = (CFDataRef)transforms_assume(SecTransformExecute(hash, &error));
441	if (!pHash) {
442		goto out;
443	}
444	(void)transforms_assume(hLen == CFDataGetLength(pHash));
445
446
447    // (9) Separate DB into an octet string pHash’ consisting of the first hLen octets of DB, a
448    // (possibly empty) octet string PS consisting of consecutive zero octets following pHash’,
449    // and a message M as If there is no 01 octet to separate PS from M , output ‘‘decoding error’’ and stop.
450    pHashPrime = CFDataCreateWithBytesNoCopy(NULL, raw_DB, hLen, kCFAllocatorNull);
451    if (CFEqual(pHash, pHashPrime)) {
452        addr01 = (UInt8*)memchr(raw_DB + hLen, 0x01, CFDataGetLength(dbMask) - hLen);
453        if (!addr01) {
454            goto out;
455        }
456        message = CFDataCreate(NULL, addr01 + 1, (CFDataGetLength(dbMask) - ((addr01 - raw_DB) + 1)) -extraPaddingLength);
457    } else {
458        // (10) If pHash’ does not equal pHash, output ‘‘decoding error’’ and stop.
459        goto out;
460    }
461
462out:
463    if (!message) {
464        if (!error) {
465            error = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "decoding error");
466        }
467        SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
468    }
469
470	// Release eveything except:
471	//	hashAlgo (obtained via get)
472	//	message (return value)
473	CFSafeRelease(maskedSeed);
474	CFSafeRelease(maskedDB);
475	CFSafeRelease(seedMask);
476	CFSafeRelease(seed);
477	CFSafeRelease(dbMask);
478	CFSafeRelease(pHash);
479	CFSafeRelease(pHashPrime);
480	CFSafeRelease(mgf_dbMask);
481	CFSafeRelease(mgf_maskedDB);
482	CFSafeRelease(hash);
483	CFSafeRelease(EncodingParameters);
484	// raw_seed is free'd via CFData, addr01 was never allocated, so raw_DB is our lot
485	free(raw_DB);
486
487    // (11) Output M.
488    return message;
489#endif
490}
491
492extern "C" {
493	extern CFDataRef oaep_padding_via_c(int desired_message_length, CFDataRef dataValue);
494}
495
496CFDataRef EncryptDecryptBase::apply_oaep_padding(CFDataRef dataValue)
497{
498#if 1
499	// MGF1 w/ SHA1 assumed here
500
501	CFErrorRef error = NULL;
502	int hLen = Digest::LengthForType(kSecDigestSHA1);
503	CFNumberRef desired_message_length_cf = (CFNumberRef)this->GetAttribute(kSecOAEPMessageLengthAttributeName);
504	int desired_message_length = 0;
505	CSSM_QUERY_SIZE_DATA RSA_size;
506	CFDataRef EM = NULL;
507
508	if (desired_message_length_cf) {
509		CFNumberGetValue(desired_message_length_cf, kCFNumberIntType, &desired_message_length);
510	} else {
511		// take RSA (or whatever crypto) block size onto account too
512		RSA_size.SizeInputBlock = (uint32)(CFDataGetLength(dataValue) + 2*hLen +1);
513		RSA_size.SizeOutputBlock = 0;
514		OSStatus status = CSSM_QuerySize(m_handle, CSSM_TRUE, 1, &RSA_size);
515		if (status != errSecSuccess) {
516			CFStringRef errorString = SecCopyErrorMessageString(status, NULL);
517			error = CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "CDSA error (%@).", errorString);
518			CFRelease(errorString);
519			SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
520			(void)transforms_assume_zero(EM);
521			return EM;
522		}
523		(void)transforms_assume(RSA_size.SizeInputBlock <= RSA_size.SizeOutputBlock);
524		desired_message_length = RSA_size.SizeOutputBlock;
525	}
526	CFDataRef returnData = oaep_padding_via_c(desired_message_length, dataValue);
527	return returnData;
528
529#else
530	CFDataRef seed = NULL, dbMask = NULL, maskedDB = NULL, seedMask = NULL, padHash = NULL, padZeros = NULL;
531    CFDataRef EncodingParameters = NULL;
532	CFMutableDataRef EM = NULL, dataBlob = NULL;
533	CFNumberRef desired_message_length_cf = NULL;
534	CFErrorRef error = NULL;
535	CFStringRef hashAlgo = NULL;
536	UInt8 *raw_padZeros = NULL, *raw_seed = NULL, *raw_maskedSeed = NULL, *raw_maskedDB = NULL;
537	SecTransformRef mgf_dbMask = NULL, mgf_seedMask = NULL, hash = NULL;
538	CFIndex paddingNeeded = -1, padLen = -1;
539	int hLen = -1;
540	CSSM_QUERY_SIZE_DATA RSA_size;
541
542	// NOTE: we omit (1) If the length of P is greater than the input limitation for the hash function
543	// (2^61 − 1 octets for SHA-1) then output ‘‘parameter string too long’’ and stop.
544	// We don't have ready access to the input limit of the hash functions, and in the real world
545	// we won't be seeing a message that long anyway.
546
547	// (2) If mLen > emLen − 2hLen − 1, output ‘‘message too long’’ and stop.
548	hashAlgo = (CFStringRef)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName);
549	if (hashAlgo == NULL) {
550		hashAlgo = kSecDigestSHA1;
551	}
552	hLen = Digest::LengthForType(hashAlgo);
553	desired_message_length_cf = (CFNumberRef)this->GetAttribute(kSecOAEPMessageLengthAttributeName);
554	int desired_message_length = 0;
555	if (desired_message_length_cf) {
556		CFNumberGetValue(desired_message_length_cf, kCFNumberIntType, &desired_message_length);
557	} else {
558		// take RSA (or whatever crypto) block size onto account too
559		RSA_size.SizeInputBlock = CFDataGetLength(dataValue) + 2*hLen +1;
560		RSA_size.SizeOutputBlock = 0;
561		OSStatus status = CSSM_QuerySize(m_handle, CSSM_TRUE, 1, &RSA_size);
562		if (status != errSecSuccess) {
563			CFStringRef errorString = SecCopyErrorMessageString(status, NULL);
564			error = CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "CDSA error (%@).", errorString);
565			CFRelease(errorString);
566			goto out;
567		}
568		(void)transforms_assume(RSA_size.SizeInputBlock <= RSA_size.SizeOutputBlock);
569		desired_message_length = RSA_size.SizeOutputBlock -1;
570	}
571	padLen = (desired_message_length - (2*hLen) -1) - CFDataGetLength(dataValue);
572	if (padLen < 0) {
573		error = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "Your message is too long for your message length, it needs to be %d bytes shorter, or you need to adjust the kSecOAEPMessageLengthAttributeName attribute", -padLen);
574        goto out;
575	}
576
577	// (3) Generate an octet string PS consisting of emLen − mLen − 2hLen − 1 zero octets. The length of PS may be 0.
578	raw_padZeros = (UInt8*)calloc(padLen, 1);
579	if (!raw_padZeros) {
580		error = GetNoMemoryErrorAndRetain();
581		goto out;
582	}
583	padZeros = CFDataCreateWithBytesNoCopy(NULL, raw_padZeros, padLen, kCFAllocatorMalloc);
584	if (!padZeros) {
585		free(raw_padZeros);
586		error = GetNoMemoryErrorAndRetain();
587		goto out;
588	}
589
590	// (4) Let pHash = Hash(P), an octet string of length hLen.
591	hash = SecDigestTransformCreate(hashAlgo, 0, &error);
592	if (!hash) {
593		goto out;
594	}
595    EncodingParameters = (CFDataRef)this->GetAttribute(kSecOAEPEncodingParametersAttributeName);
596	if (EncodingParameters) {
597		CFRetain(EncodingParameters);
598	} else {
599		EncodingParameters = CFDataCreate(NULL, (UInt8*)"", 0);
600		if (!EncodingParameters) {
601			error = GetNoMemoryErrorAndRetain();
602			goto out;
603		}
604	}
605	if (!SecTransformSetAttribute(hash, kSecTransformInputAttributeName, EncodingParameters, &error)) {
606		goto out;
607	}
608
609	padHash = (CFDataRef)transforms_assume(SecTransformExecute(hash, &error));
610	if (!padHash) {
611		goto out;
612	}
613	(void)transforms_assume(hLen == CFDataGetLength(padHash));
614
615	// (5) Concatenate pHash,PS, the message M, and other padding to form a data block DB as DB = pHash∥PS∥01∥M.
616	dataBlob = CFDataCreateMutable(NULL, CFDataGetLength(padHash) + padLen + 1 + CFDataGetLength(dataValue));
617	if (!dataBlob) {
618		error = GetNoMemoryErrorAndRetain();
619		goto out;
620	}
621	CFDataAppendBytes(dataBlob, CFDataGetBytePtr(padHash), hLen);
622	CFDataAppendBytes(dataBlob, raw_padZeros, padLen);
623	CFDataAppendBytes(dataBlob, (UInt8*)"\01", 1);
624	CFDataAppendBytes(dataBlob, CFDataGetBytePtr(dataValue), CFDataGetLength(dataValue));
625
626	// (6) Generate a random octet string seed of length hLen.
627	seed = (CFDataRef)this->GetAttribute(CFSTR("FixedSeedForOAEPTesting"));
628	raw_seed = NULL;
629	if (seed) {
630		raw_seed = (UInt8*)CFDataGetBytePtr(seed);
631		(void)transforms_assume(hLen == CFDataGetLength(seed));
632		CFRetain(seed);
633	} else {
634		raw_seed = (UInt8*)malloc(hLen);
635		if (!raw_seed) {
636			error = GetNoMemoryErrorAndRetain();
637			goto out;
638		}
639		SecRandomCopyBytes(kSecRandomDefault, hLen, raw_seed);
640		seed = CFDataCreateWithBytesNoCopy(NULL, raw_seed, hLen, kCFAllocatorMalloc);
641		if (!seed) {
642			free(raw_seed);
643			error = GetNoMemoryErrorAndRetain();
644		}
645	}
646
647	// (7) Let dbMask = MGF (seed, emLen − hLen).
648	mgf_dbMask = transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo, desired_message_length - hLen, &error));
649	if (!mgf_dbMask) {
650		goto out;
651	}
652	if (!SecTransformSetAttribute(mgf_dbMask, kSecTransformInputAttributeName, seed, &error)) {
653		goto out;
654	}
655	dbMask = (CFDataRef)SecTransformExecute(mgf_dbMask, &error);
656
657	// (8) Let maskedDB = DB ⊕ dbMask.
658	// NOTE: we do some allocations above...you know, we should be able to malloc ONE buffer of the
659	// proper size.
660	raw_maskedDB = (UInt8 *)malloc(CFDataGetLength(dbMask));
661	if (!raw_maskedDB) {
662		error = GetNoMemoryErrorAndRetain();
663		goto out;
664	}
665	xor_bytes(raw_maskedDB, CFDataGetBytePtr(dbMask), CFDataGetBytePtr(dataBlob), CFDataGetLength(dbMask));
666	maskedDB = CFDataCreateWithBytesNoCopy(NULL, raw_maskedDB, CFDataGetLength(dataBlob), kCFAllocatorMalloc);
667	if (!maskedDB) {
668		free(raw_maskedDB);
669		error = GetNoMemoryErrorAndRetain();
670		goto out;
671	}
672
673	// (9) Let seedMask = MGF(maskedDB, hLen).
674	mgf_seedMask = transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo, hLen, &error));
675	if (!mgf_seedMask) {
676		goto out;
677	}
678	if (!SecTransformSetAttribute(mgf_seedMask, kSecTransformInputAttributeName, maskedDB, &error)) {
679		goto out;
680	}
681	seedMask = transforms_assume((CFDataRef)SecTransformExecute(mgf_seedMask, &error));
682	if (!seedMask) {
683		goto out;
684	}
685
686	// (10) Let maskedSeed = seed ⊕ seedMask
687	raw_maskedSeed = (UInt8 *)malloc(hLen);
688	if (!raw_maskedSeed) {
689		error = GetNoMemoryErrorAndRetain();
690		goto out;
691	}
692	xor_bytes(raw_maskedSeed, raw_seed, CFDataGetBytePtr(seedMask), hLen);
693
694	// (11) Let EM = maskedSeed∥maskedDB (if we didn't have to pushback the NULL we could do this without physically concatanating)
695	// (figure out amount of leading zero padding we need)
696	RSA_size.SizeInputBlock = hLen + CFDataGetLength(maskedDB);
697	CSSM_QuerySize(m_handle, CSSM_TRUE, 1, &RSA_size);
698	paddingNeeded = RSA_size.SizeOutputBlock - RSA_size.SizeInputBlock;
699	(void)transforms_assume(paddingNeeded >= 0);
700
701	EM = CFDataCreateMutable(NULL, CFDataGetLength(maskedDB) + hLen + paddingNeeded);
702	if (!EM) {
703		error = GetNoMemoryErrorAndRetain();
704		goto out;
705	}
706	while(paddingNeeded--) {
707		CFDataAppendBytes(EM, (UInt8*)"", 1);
708	}
709
710	CFDataAppendBytes(EM, raw_maskedSeed, hLen);
711	CFDataAppendBytes(EM, raw_maskedDB, CFDataGetLength(maskedDB));
712out:
713	if (error) {
714		SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
715		(void)transforms_assume_zero(EM);
716	}
717
718	CFSafeRelease(seed); // via get??
719	CFSafeRelease(dbMask);
720	CFSafeRelease(maskedDB);
721	CFSafeRelease(seedMask);
722	CFSafeRelease(padHash);
723	CFSafeRelease(padZeros);
724	CFSafeRelease(EncodingParameters);
725	CFSafeRelease(dataBlob);
726	// desired_message_length_cf -- via get
727	// hashAlgo -- via get
728	CFSafeRelease(mgf_dbMask);
729	CFSafeRelease(mgf_seedMask);
730	CFSafeRelease(hash);
731	// raw_* are all freed by their associated CFDatas, except raw_maskedSeed
732	free(raw_maskedSeed);
733
734	// (12) Output EM.
735	return EM;
736#endif
737}
738
739/* --------------------------------------------------------------------------
740 method: 		AttributeChanged
741 description: 	deal with input
742 -------------------------------------------------------------------------- */
743void EncryptDecryptBase::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value)
744{
745	// sanity check our arguments
746	if (ah != inputAH)
747	{
748		return; // we only deal with input
749	}
750
751	if (value != NULL)
752	{
753		CFTypeID valueType = CFGetTypeID(value);
754		if (valueType != CFDataGetTypeID())
755		{
756			CFStringRef realType = CFCopyTypeIDDescription(valueType);
757			CFErrorRef error = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "Value is not a CFDataRef -- this one is a %@", realType);
758			CFRelease(realType);
759			SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
760			return;
761		}
762
763		if (m_forEncryption && m_accumulator) {
764			CFDataRef d = (CFDataRef)value;
765			CFDataAppendBytes(m_accumulator, CFDataGetBytePtr(d), CFDataGetLength(d));
766			return;
767		}
768	}
769
770	if (m_forEncryption && m_accumulator) {
771		(void)transforms_assume_zero(value);
772		value = m_accumulator;
773		m_accumulator = NULL;
774		dispatch_async(this->mDispatchQueue, ^{
775			CFSafeRelease(value);
776		});
777		this->Pushback(inputAH, NULL);
778
779        if (m_oaep_padding) {
780			value = apply_oaep_padding((CFDataRef)value);
781			dispatch_async(this->mDispatchQueue, ^{
782				CFSafeRelease(value);
783			});
784        }
785	}
786
787	// add the input to our cryptor
788	CFDataRef valueRef = (CFDataRef) value;
789	CSSM_RETURN	crtn = CSSM_OK;
790	Boolean inFinal = FALSE;
791
792	if (valueRef != NULL)
793	{
794		// Convert to A CSSM_DATA
795		CSSM_DATA dataStruct;
796		dataStruct.Length = CFDataGetLength(valueRef);
797        dataStruct.Data = const_cast<uint8_t*>(CFDataGetBytePtr(valueRef));
798
799		CSSM_DATA intermediateDataStruct;
800		memset(&intermediateDataStruct, 0, sizeof(intermediateDataStruct));
801
802		CSSM_SIZE bytesProcessed = 0;
803
804		if (m_forEncryption)
805		{
806			crtn = CSSM_EncryptDataUpdate(m_handle,
807										  &dataStruct,
808										  1,
809										  &intermediateDataStruct,
810										  1,
811										  &bytesProcessed);
812		}
813		else
814		{
815			crtn = CSSM_DecryptDataUpdate(m_handle,
816										  &dataStruct,
817										  1,
818										  &intermediateDataStruct,
819										  1,
820										  &bytesProcessed);
821		}
822
823		if (CSSM_OK != crtn)
824		{
825			SendCSSMError(crtn);
826			return;
827		}
828
829
830		if (intermediateDataStruct.Length > 0)
831		{
832			if (NULL == m_processedData)
833			{
834				m_processedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
835			}
836
837			CFDataAppendBytes(m_processedData, intermediateDataStruct.Data, bytesProcessed);
838			free(intermediateDataStruct.Data);
839		}
840	}
841	else
842	{
843		// Finalize
844
845		inFinal = TRUE;
846		CSSM_DATA remData;
847		memset(&remData, 0, sizeof(remData));
848
849		crtn = (m_forEncryption) ? CSSM_EncryptDataFinal(m_handle, &remData) : CSSM_DecryptDataFinal(m_handle, &remData);
850
851		if (CSSM_OK == crtn)
852		{
853            if (m_forEncryption == false && m_accumulator) {
854                (void)transforms_assume_zero(m_processedData);
855                if (remData.Length > 0) {
856                    CFDataAppendBytes(m_accumulator, remData.Data, remData.Length);
857                }
858            } else {
859                if (NULL == m_processedData)
860                {
861                    m_processedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
862                }
863
864                if (remData.Length > 0)
865                {
866                    CFDataAppendBytes(m_processedData, remData.Data, remData.Length);
867                }
868            }
869		}
870
871		free(remData.Data);
872
873		if (CSSM_OK != crtn)
874		{
875			SendCSSMError(crtn);
876			return;
877		}
878	}
879
880	if (NULL != m_processedData)
881	{
882        SendAttribute(kSecTransformOutputAttributeName, m_processedData);
883		CFRelease(m_processedData);
884		m_processedData = NULL;
885	}
886
887	if (inFinal)
888	{
889        if (m_oaep_padding && m_forEncryption == false) {
890            CFTypeRef unpadded = remove_oaep_padding(m_accumulator);
891            SendAttribute(kSecTransformOutputAttributeName, unpadded);
892            CFRelease(unpadded);
893        }
894		SendAttribute(kSecTransformOutputAttributeName, NULL);
895	}
896
897
898}
899
900/* --------------------------------------------------------------------------
901 method: 		CopyState
902 description: 	Copy the current state of this transform
903 -------------------------------------------------------------------------- */
904CFDictionaryRef EncryptDecryptBase::CopyState()
905{
906	// make a dictionary for our state
907	CFMutableDictionaryRef state = (CFMutableDictionaryRef) CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
908	CFStringRef paddingStr = (CFStringRef) GetAttribute(kSecPaddingKey);
909	CFStringRef modeStr = (CFStringRef) GetAttribute (kSecEncryptionMode);
910	CFDataRef ivData = (CFDataRef) GetAttribute(kSecIVKey);
911	if (NULL != paddingStr)
912	{
913		CFDictionaryAddValue(state, kSecPaddingKey, paddingStr);
914	}
915
916	if (NULL != modeStr)
917	{
918		CFDictionaryAddValue(state, kSecEncryptionMode, modeStr);
919	}
920
921	if (NULL != ivData)
922	{
923		CFDictionaryAddValue(state, kSecIVKey, ivData);
924	}
925
926	return state;
927}
928
929/* --------------------------------------------------------------------------
930 method: 		RestoreState
931 description: 	Restore the state of this transform from a dictionary
932 -------------------------------------------------------------------------- */
933void EncryptDecryptBase::RestoreState(CFDictionaryRef state)
934{
935	if (NULL == state)
936	{
937		return;
938	}
939
940	CFStringRef paddingStr = (CFStringRef)CFDictionaryGetValue(state, kSecPaddingKey);
941	CFStringRef modeStr = (CFStringRef)CFDictionaryGetValue(state, kSecEncryptionMode);
942	CFDataRef ivData = (CFDataRef)CFDictionaryGetValue(state, kSecIVKey);
943
944	if (NULL != paddingStr)
945	{
946		SetAttribute(kSecPaddingKey, paddingStr);
947	}
948
949	if (NULL != modeStr)
950	{
951		SetAttribute(kSecEncryptionMode, modeStr);
952	}
953
954	if (NULL != ivData)
955	{
956		SetAttribute(kSecIVKey, ivData);
957	}
958
959}
960
961/* --------------------------------------------------------------------------
962 Implementation of the EncryptTransform
963 -------------------------------------------------------------------------- */
964
965/* --------------------------------------------------------------------------
966 method: 		EncryptTransform (Constructor)
967 description: 	Make a new EncryptTransform
968 -------------------------------------------------------------------------- */
969EncryptTransform::EncryptTransform() : EncryptDecryptBase(kEncryptTransformType)
970{
971}
972
973/* --------------------------------------------------------------------------
974 method: 		~EncryptTransform (Destructor)
975 description: 	Clean up the memory of anEncryptTransform
976 -------------------------------------------------------------------------- */
977EncryptTransform::~EncryptTransform()
978{
979}
980
981/* --------------------------------------------------------------------------
982 method: 		[static] Make
983 description: 	Make a new instance of this class
984 -------------------------------------------------------------------------- */
985SecTransformRef EncryptTransform::Make()
986{
987	EncryptTransform* tr = new EncryptTransform();
988	SecTransformRef str = (SecTransformRef) CoreFoundationHolder::MakeHolder(kEncryptTransformType, tr);
989	return str;
990}
991
992/* --------------------------------------------------------------------------
993 Interface and implementation of the EncryptTransformFactory
994 -------------------------------------------------------------------------- */
995
996class EncryptTransformFactory : public TransformFactory
997{
998public:
999	EncryptTransformFactory();
1000	CFTypeRef Make();
1001};
1002
1003
1004/* --------------------------------------------------------------------------
1005 method: 		EncryptTransformFactory (Constructor)
1006 description:
1007 -------------------------------------------------------------------------- */
1008EncryptTransformFactory::EncryptTransformFactory() :
1009TransformFactory(kEncryptTransformType)
1010{}
1011
1012
1013/* --------------------------------------------------------------------------
1014 method: 		MakeTransformFactory
1015 description: 	Make an instance of this factory class
1016 -------------------------------------------------------------------------- */
1017TransformFactory* EncryptTransform::MakeTransformFactory()
1018{
1019	return new EncryptTransformFactory;
1020}
1021
1022/* --------------------------------------------------------------------------
1023 method: 		Make
1024 description: 	Create an instance of this class
1025 -------------------------------------------------------------------------- */
1026CFTypeRef EncryptTransformFactory::Make()
1027{
1028	return EncryptTransform::Make();
1029}
1030
1031
1032/* --------------------------------------------------------------------------
1033 method: 		DecryptTransform (Constructor)
1034 description: 	Make a new DecryptTransform
1035 -------------------------------------------------------------------------- */
1036DecryptTransform::DecryptTransform() : EncryptDecryptBase(kDecryptTransformType)
1037{
1038}
1039
1040/* --------------------------------------------------------------------------
1041 method: 		~DecryptTransform (Destructor)
1042 description: 	Clean up the memory of anDecryptTransform
1043 -------------------------------------------------------------------------- */
1044DecryptTransform::~DecryptTransform()
1045{
1046}
1047
1048
1049/* --------------------------------------------------------------------------
1050 method: 		[static] Make
1051 description: 	Make a new instance of this class
1052 -------------------------------------------------------------------------- */
1053SecTransformRef DecryptTransform::Make()
1054{
1055	DecryptTransform* tr = new DecryptTransform();
1056	SecTransformRef str = (SecTransformRef) CoreFoundationHolder::MakeHolder(kDecryptTransformType, tr);
1057	return str;
1058}
1059
1060/* --------------------------------------------------------------------------
1061 Interface and implementation of the DecryptTransformFactory
1062 -------------------------------------------------------------------------- */
1063
1064class DecryptTransformFactory : public TransformFactory
1065{
1066public:
1067	DecryptTransformFactory();
1068	CFTypeRef Make();
1069};
1070
1071
1072/* --------------------------------------------------------------------------
1073 method: 		DecryptTransformFactory (Constructor)
1074 description:
1075 -------------------------------------------------------------------------- */
1076DecryptTransformFactory::DecryptTransformFactory() :
1077TransformFactory(kDecryptTransformType)
1078{}
1079
1080
1081/* --------------------------------------------------------------------------
1082 method: 		MakeTransformFactory
1083 description: 	Make an instance of this factory class
1084 -------------------------------------------------------------------------- */
1085TransformFactory* DecryptTransform::MakeTransformFactory()
1086{
1087	return new DecryptTransformFactory;
1088}
1089
1090/* --------------------------------------------------------------------------
1091 method: 		Make
1092 description: 	Create an instance of this class
1093 -------------------------------------------------------------------------- */
1094CFTypeRef DecryptTransformFactory::Make()
1095{
1096	return DecryptTransform::Make();
1097}
1098
1099