1 #include <Security/Security.h>
2 #include <Security/SecKeyPriv.h>
3 #include <Security/SecItem.h>
4 #include <CoreFoundation/CoreFoundation.h>
11 #include "testleaks.h"
14 void AddKeyCFTypePairToDictionary(CFMutableDictionaryRef mdr
, CFTypeRef key
, CFTypeRef value
)
16 CFDictionaryAddValue(mdr
, key
, value
);
21 void AddKeyNumberPairToDictionary(CFMutableDictionaryRef mdr
, CFTypeRef key
, uint32 value
)
23 // make a CFNumber out of the value
24 CFNumberRef number
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &value
);
25 CFDictionaryAddValue(mdr
, key
, number
);
31 void AddKeyStringPairToDictionary(CFMutableDictionaryRef mdr
, CFTypeRef key
, const char* string
)
33 // We add the string as a CFData
34 CFDataRef data
= CFDataCreate(NULL
, (const UInt8
*) string
, strlen(string
));
35 CFDictionaryAddValue(mdr
, key
, data
);
43 CFMutableDictionaryRef parameters
;
44 SecKeyRef publicKey
, privateKey
;
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
);
50 ok(result
!= noErr
, "result is noErr");
52 // add the algorithm type
53 AddKeyCFTypePairToDictionary(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
55 // see if we can get a 2048 bit keypair
56 AddKeyNumberPairToDictionary(parameters
, kSecAttrKeySizeInBits
, 2048);
58 // put an application tag on the key
59 AddKeyStringPairToDictionary(parameters
, kSecAttrApplicationTag
, "This is a test.");
62 result
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
63 ok_status(result
, "SecKeyGeneratePair");
69 // Make a chunk of data
70 char data
[] = "This is a test of some data. Ain't it grand?";
72 SecPadding paddings
[] = {kSecPaddingNone
, kSecPaddingPKCS1
, kSecPaddingPKCS1MD2
, kSecPaddingPKCS1MD5
, kSecPaddingPKCS1SHA1
};
73 const int numberOfPaddings
= sizeof(paddings
) / sizeof (SecPadding
);
75 // test each padding mode
77 for (n
= 0; n
< numberOfPaddings
; ++n
)
79 // sign that data with the private key
81 size_t signatureLength
= sizeof(signature
);
83 result
= SecKeyRawSign(privateKey
, paddings
[n
], (uint8_t*) data
, strlen(data
), signature
, &signatureLength
);
84 ok_status(result
, "SecKeyRawSign");
86 // verify with the signature
87 result
= SecKeyRawVerify(publicKey
, paddings
[n
], (uint8_t*) data
, strlen(data
), signature
, signatureLength
);
88 ok_status(result
, "SecKeyRawVerify");
92 SecKeychainItemDelete((SecKeychainItemRef
) publicKey
);
93 SecKeychainItemDelete((SecKeychainItemRef
) privateKey
);
96 CFRelease(privateKey
);
97 CFRelease(parameters
);
102 int SignVerifyWithAsyncTest()
104 CFMutableDictionaryRef parameters
;
105 __block SecKeyRef publicKey
, privateKey
;
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();
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
);
119 // add the algorithm type
120 AddKeyCFTypePairToDictionary(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
122 // see if we can get a 2048 bit keypair
123 AddKeyNumberPairToDictionary(parameters
, kSecAttrKeySizeInBits
, 2048);
125 // put an application tag on the key
126 AddKeyStringPairToDictionary(parameters
, kSecAttrApplicationTag
, "This is a test.");
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
);
136 AddKeyCFTypePairToDictionary(parameters
, kSecAttrAccess
, access
);
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
);
148 dispatch_group_wait(everyone_called
, DISPATCH_TIME_FOREVER
);
149 if (NULL
== publicKey
|| NULL
== privateKey
)
154 // Make a chunk of data
155 char data
[] = "This is a test of some data. Ain't it grand?";
157 SecPadding paddings
[] = {kSecPaddingNone
, kSecPaddingPKCS1
, kSecPaddingPKCS1MD2
, kSecPaddingPKCS1MD5
, kSecPaddingPKCS1SHA1
};
158 const int numberOfPaddings
= sizeof(paddings
) / sizeof (SecPadding
);
160 // test each padding mode
162 for (n
= 0; n
< numberOfPaddings
; ++n
)
164 // sign that data with the private key
165 uint8 signature
[512];
166 size_t signatureLength
= sizeof(signature
);
168 result
= SecKeyRawSign(privateKey
, paddings
[n
], (uint8_t*) data
, strlen(data
), signature
, &signatureLength
);
169 ok_status(result
, "SecKeyRawSign");
171 // verify with the signature
172 result
= SecKeyRawVerify(publicKey
, paddings
[n
], (uint8_t*) data
, strlen(data
), signature
, signatureLength
);
173 ok_status(result
, "SecKeyRawVerify");
177 SecKeychainItemDelete((SecKeychainItemRef
) publicKey
);
178 SecKeychainItemDelete((SecKeychainItemRef
) privateKey
);
180 CFRelease(publicKey
);
181 CFRelease(privateKey
);
182 CFRelease(parameters
);
189 int EncryptDecryptTest()
191 CFMutableDictionaryRef parameters
;
192 SecKeyRef encryptionKey
, decryptionKey
;
194 // start out with an empty dictionary and see if it returns an error
195 parameters
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
197 // add the algorithm type
198 AddKeyCFTypePairToDictionary(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
200 // see if we can get a 2048 bit keypair
201 AddKeyNumberPairToDictionary(parameters
, kSecAttrKeySizeInBits
, 2048);
203 // put an application tag on the key
204 AddKeyStringPairToDictionary(parameters
, kSecAttrApplicationTag
, "This is a test.");
206 OSStatus result
= SecKeyGeneratePair(parameters
, &encryptionKey
, &decryptionKey
);
207 ok_status(result
, "EncryptDecryptTest");
209 // Make a chunk of data
210 char data
[] = "I want to keep this data secure.";
212 SecPadding paddings
[] = {kSecPaddingPKCS1
};
213 const int numberOfPaddings
= sizeof(paddings
) / sizeof (SecPadding
);
215 // test each padding mode
217 for (n
= 0; n
< numberOfPaddings
; ++n
)
219 // encrypt that data with the public key
220 uint8 encryptedData
[2048];
221 size_t encryptedDataLength
= sizeof(encryptedData
);
222 memset(encryptedData
, 0xFF, encryptedDataLength
);
224 result
= SecKeyEncrypt(encryptionKey
, paddings
[n
], (uint8_t*) data
, sizeof(data
), encryptedData
, &encryptedDataLength
);
227 fprintf(stderr
, "Error in encryption.\n");
228 cssmPerror(NULL
, result
);
232 uint8 decryptedData
[2048];
233 size_t decryptedDataLength
= sizeof(decryptedData
);
235 // decrypt with the private key
236 result
= SecKeyDecrypt(decryptionKey
, paddings
[n
], encryptedData
, encryptedDataLength
, decryptedData
, &decryptedDataLength
);
237 ok_status(result
, "SecKeyDecrypt");
239 // what we got back had better equal what we put in
240 if (memcmp(data
, decryptedData
, sizeof(data
)) != 0)
242 fprintf(stderr
, "Decrypted text != original plain text.\n");
248 SecKeychainItemDelete((SecKeychainItemRef
) encryptionKey
);
249 SecKeychainItemDelete((SecKeychainItemRef
) decryptionKey
);
251 CFRelease(encryptionKey
);
252 CFRelease(decryptionKey
);
253 CFRelease(parameters
);
260 #define TEST_ITEM_ACCOUNT CFSTR("SecItemTest_Account")
261 #define TEST_ITEM_SERVICE CFSTR("SecItemTest_Service")
265 // create a dictionary to hold the item
266 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
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
);
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
);
278 OSStatus result
= SecItemAdd(dict
, &itemRef
);
279 ok_status(result
, "SecItemAdd");
284 // search for the item
285 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
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
);
293 result
= SecItemCopyMatching(dict
, &itemRef
);
294 ok_status(result
, "SecItemCopyMatching");
303 SecKeychainRef keychain
= NULL
;
304 ok_status(SecKeychainSetUserInteractionAllowed(FALSE
), "SecKeychainSetUserInteractionAllowed(FALSE)");
305 ok_status(SecKeychainCreate("test", 4, "test", FALSE
, NULL
, &keychain
), "SecKeychainCreate");
307 SignVerifyWithAsyncTest();
311 if (keychain
) CFRelease(keychain
);
316 int main(int argc
, char * const *argv
)
319 if (!tests_begin(argc
, argv
))
320 BAIL_OUT("tests_begin failed");
322 ok(tests_end(1), "cleanup");
323 ok_leaks("no leaks");