1#include <Security/Security.h>
2#include <Security/SecKeyPriv.h>
3#include <Security/SecItem.h>
4#include <CoreFoundation/CoreFoundation.h>
5#include <stdlib.h>
6#include <unistd.h>
7
8#include "testmore.h"
9#include "testenv.h"
10#include "testcssm.h"
11#include "testleaks.h"
12
13
14void AddKeyCFTypePairToDictionary(CFMutableDictionaryRef mdr, CFTypeRef key, CFTypeRef value)
15{
16	CFDictionaryAddValue(mdr, key, value);
17}
18
19
20
21void AddKeyNumberPairToDictionary(CFMutableDictionaryRef mdr, CFTypeRef key, uint32 value)
22{
23	// make a CFNumber out of the value
24	CFNumberRef number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);
25	CFDictionaryAddValue(mdr, key, number);
26	CFRelease(number);
27}
28
29
30
31void AddKeyStringPairToDictionary(CFMutableDictionaryRef mdr, CFTypeRef key, const char* string)
32{
33	// We add the string as a CFData
34	CFDataRef data = CFDataCreate(NULL, (const UInt8*) string, strlen(string));
35	CFDictionaryAddValue(mdr, key, data);
36	CFRelease(data);
37}
38
39
40
41int SignVerifyTest()
42{
43	CFMutableDictionaryRef parameters;
44	SecKeyRef publicKey, privateKey;
45
46	// start out with an empty dictionary and see if it returns an error
47	parameters = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
48	OSStatus result = SecKeyGeneratePair(parameters, &publicKey, &privateKey);
49
50	ok(result != noErr, "result is noErr");
51
52	// add the algorithm type
53	AddKeyCFTypePairToDictionary(parameters, kSecAttrKeyType, kSecAttrKeyTypeRSA);
54
55	// see if we can get a 2048 bit keypair
56	AddKeyNumberPairToDictionary(parameters, kSecAttrKeySizeInBits, 2048);
57
58	// put an application tag on the key
59	AddKeyStringPairToDictionary(parameters, kSecAttrApplicationTag, "This is a test.");
60
61	// try again
62	result = SecKeyGeneratePair(parameters, &publicKey, &privateKey);
63	ok_status(result, "SecKeyGeneratePair");
64	if (result != noErr)
65	{
66		return 1;
67	}
68
69	// Make a chunk of data
70	char data[] = "This is a test of some data.  Ain't it grand?";
71
72	SecPadding paddings[] = {kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingPKCS1MD2, kSecPaddingPKCS1MD5, kSecPaddingPKCS1SHA1};
73	const int numberOfPaddings = sizeof(paddings) / sizeof (SecPadding);
74
75	// test each padding mode
76	int n;
77	for (n = 0; n < numberOfPaddings; ++n)
78	{
79		// sign that data with the private key
80		uint8 signature[512];
81		size_t signatureLength = sizeof(signature);
82
83		result = SecKeyRawSign(privateKey, paddings[n], (uint8_t*) data, strlen(data), signature, &signatureLength);
84		ok_status(result, "SecKeyRawSign");
85
86		// verify with the signature
87		result = SecKeyRawVerify(publicKey, paddings[n], (uint8_t*) data, strlen(data), signature, signatureLength);
88		ok_status(result, "SecKeyRawVerify");
89	}
90
91	// clean up
92	SecKeychainItemDelete((SecKeychainItemRef) publicKey);
93	SecKeychainItemDelete((SecKeychainItemRef) privateKey);
94
95	CFRelease(publicKey);
96	CFRelease(privateKey);
97	CFRelease(parameters);
98
99	return 0;
100}
101
102int SignVerifyWithAsyncTest()
103{
104	CFMutableDictionaryRef parameters;
105	__block SecKeyRef publicKey, privateKey;
106
107	// start out with an empty dictionary and see if it returns an error
108	parameters = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
109	OSStatus result = SecKeyGeneratePair(parameters, &publicKey, &privateKey);
110	dispatch_group_t everyone_called = dispatch_group_create();
111
112	dispatch_group_enter(everyone_called);
113	SecKeyGeneratePairAsync(parameters, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(SecKeyRef publicKey, SecKeyRef privateKey,  CFErrorRef error){
114		ok(publicKey == NULL && privateKey == NULL, "keys are NULL");
115		ok(error != NULL, "error set");
116		dispatch_group_leave(everyone_called);
117	});
118
119	// add the algorithm type
120	AddKeyCFTypePairToDictionary(parameters, kSecAttrKeyType, kSecAttrKeyTypeRSA);
121
122	// see if we can get a 2048 bit keypair
123	AddKeyNumberPairToDictionary(parameters, kSecAttrKeySizeInBits, 2048);
124
125	// put an application tag on the key
126	AddKeyStringPairToDictionary(parameters, kSecAttrApplicationTag, "This is a test.");
127
128	// throw some sort of access thingie on it too
129	SecAccessRef access = NULL;
130	SecTrustedApplicationRef myself = NULL;
131	ok_status(SecTrustedApplicationCreateFromPath(NULL, &myself), "create trusted app for self");
132	CFArrayRef trustedApplications = CFArrayCreate(NULL, (const void **)&myself, 1, &kCFTypeArrayCallBacks);
133	ok_status(SecAccessCreate(CFSTR("Trust self (test)"), trustedApplications, &access), "SecAccessCreate");
134	CFRelease(trustedApplications);
135	CFRelease(myself);
136	AddKeyCFTypePairToDictionary(parameters, kSecAttrAccess, access);
137
138	// try again
139	dispatch_group_enter(everyone_called);
140	SecKeyGeneratePairAsync(parameters, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(SecKeyRef pubKey, SecKeyRef privKey,  CFErrorRef error){
141		ok(pubKey != NULL && privKey != NULL, "keys set");
142		ok(error == NULL, "no error");
143		publicKey = (SecKeyRef)CFRetain(pubKey);
144		privateKey = (SecKeyRef)CFRetain(privKey);
145		dispatch_group_leave(everyone_called);
146	});
147
148	dispatch_group_wait(everyone_called, DISPATCH_TIME_FOREVER);
149	if (NULL == publicKey || NULL == privateKey)
150	{
151		return 1;
152	}
153
154	// Make a chunk of data
155	char data[] = "This is a test of some data.  Ain't it grand?";
156
157	SecPadding paddings[] = {kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingPKCS1MD2, kSecPaddingPKCS1MD5, kSecPaddingPKCS1SHA1};
158	const int numberOfPaddings = sizeof(paddings) / sizeof (SecPadding);
159
160	// test each padding mode
161	int n;
162	for (n = 0; n < numberOfPaddings; ++n)
163	{
164		// sign that data with the private key
165		uint8 signature[512];
166		size_t signatureLength = sizeof(signature);
167
168		result = SecKeyRawSign(privateKey, paddings[n], (uint8_t*) data, strlen(data), signature, &signatureLength);
169		ok_status(result, "SecKeyRawSign");
170
171		// verify with the signature
172		result = SecKeyRawVerify(publicKey, paddings[n], (uint8_t*) data, strlen(data), signature, signatureLength);
173		ok_status(result, "SecKeyRawVerify");
174	}
175
176	// clean up
177	SecKeychainItemDelete((SecKeychainItemRef) publicKey);
178	SecKeychainItemDelete((SecKeychainItemRef) privateKey);
179
180	CFRelease(publicKey);
181	CFRelease(privateKey);
182	CFRelease(parameters);
183
184	return 0;
185}
186
187
188
189int EncryptDecryptTest()
190{
191	CFMutableDictionaryRef parameters;
192	SecKeyRef encryptionKey, decryptionKey;
193
194	// start out with an empty dictionary and see if it returns an error
195	parameters = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
196
197	// add the algorithm type
198	AddKeyCFTypePairToDictionary(parameters, kSecAttrKeyType, kSecAttrKeyTypeRSA);
199
200	// see if we can get a 2048 bit keypair
201	AddKeyNumberPairToDictionary(parameters, kSecAttrKeySizeInBits, 2048);
202
203	// put an application tag on the key
204	AddKeyStringPairToDictionary(parameters, kSecAttrApplicationTag, "This is a test.");
205
206	OSStatus result = SecKeyGeneratePair(parameters, &encryptionKey, &decryptionKey);
207	ok_status(result, "EncryptDecryptTest");
208
209	// Make a chunk of data
210	char data[] = "I want to keep this data secure.";
211
212	SecPadding paddings[] = {kSecPaddingPKCS1};
213	const int numberOfPaddings = sizeof(paddings) / sizeof (SecPadding);
214
215	// test each padding mode
216	int n;
217	for (n = 0; n < numberOfPaddings; ++n)
218	{
219		// encrypt that data with the public key
220		uint8 encryptedData[2048];
221		size_t encryptedDataLength = sizeof(encryptedData);
222		memset(encryptedData, 0xFF, encryptedDataLength);
223
224		result = SecKeyEncrypt(encryptionKey, paddings[n], (uint8_t*) data, sizeof(data), encryptedData, &encryptedDataLength);
225		if (result != noErr)
226		{
227			fprintf(stderr, "Error in encryption.\n");
228			cssmPerror(NULL, result);
229			return 1;
230		}
231
232		uint8 decryptedData[2048];
233		size_t decryptedDataLength = sizeof(decryptedData);
234
235		// decrypt with the private key
236		result = SecKeyDecrypt(decryptionKey, paddings[n], encryptedData, encryptedDataLength, decryptedData, &decryptedDataLength);
237		ok_status(result, "SecKeyDecrypt");
238
239		// what we got back had better equal what we put in
240		if (memcmp(data, decryptedData, sizeof(data)) != 0)
241		{
242			fprintf(stderr, "Decrypted text != original plain text.\n");
243			return 1;
244		}
245	}
246
247	// clean up
248	SecKeychainItemDelete((SecKeychainItemRef) encryptionKey);
249	SecKeychainItemDelete((SecKeychainItemRef) decryptionKey);
250
251	CFRelease(encryptionKey);
252	CFRelease(decryptionKey);
253	CFRelease(parameters);
254
255	return 0;
256}
257
258
259
260#define TEST_ITEM_ACCOUNT CFSTR("SecItemTest_Account")
261#define TEST_ITEM_SERVICE CFSTR("SecItemTest_Service")
262
263int SecItemTest()
264{
265	// create a dictionary to hold the item
266	CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
267
268	// create our item -- we are only testing generic passwords, since that is the scope of the bug
269	CFDictionaryAddValue(dict, kSecClass, kSecClassGenericPassword);
270	CFDictionaryAddValue(dict, kSecAttrAccount, TEST_ITEM_ACCOUNT);
271	CFDictionaryAddValue(dict, kSecAttrService, TEST_ITEM_SERVICE);
272
273	const char* data = "Shh!  It's a secret!!!";
274	CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*) data, strlen(data), NULL);
275	CFDictionaryAddValue(dict, kSecValueData, dataRef);
276
277	CFTypeRef itemRef;
278	OSStatus result = SecItemAdd(dict, &itemRef);
279	ok_status(result, "SecItemAdd");
280
281	// cleanup
282	CFRelease(dict);
283
284	// search for the item
285	dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
286
287	// create our item -- we are only testing generic passwords, since that is the scope of the bug
288	CFDictionaryAddValue(dict, kSecClass, kSecClassGenericPassword);
289	CFDictionaryAddValue(dict, kSecAttrAccount, TEST_ITEM_ACCOUNT);
290	CFDictionaryAddValue(dict, kSecAttrService, TEST_ITEM_SERVICE);
291	CFDictionaryAddValue(dict, kSecReturnAttributes, kCFBooleanTrue);
292
293	result = SecItemCopyMatching(dict, &itemRef);
294	ok_status(result, "SecItemCopyMatching");
295
296	return 0;
297}
298
299
300
301void tests()
302{
303	SecKeychainRef keychain = NULL;
304	ok_status(SecKeychainSetUserInteractionAllowed(FALSE), "SecKeychainSetUserInteractionAllowed(FALSE)");
305	ok_status(SecKeychainCreate("test", 4, "test", FALSE, NULL, &keychain), "SecKeychainCreate");
306
307	SignVerifyWithAsyncTest();
308	SignVerifyTest();
309	SecItemTest();
310
311	if (keychain) CFRelease(keychain);
312}
313
314
315
316int main(int argc, char * const *argv)
317{
318	plan_tests(34);
319	if (!tests_begin(argc, argv))
320		BAIL_OUT("tests_begin failed");
321	tests();
322	ok(tests_end(1), "cleanup");
323	ok_leaks("no leaks");
324	return 0;
325}
326