2 * Copyright (c) 2011,2013-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
29 * Copyright (c) 2007-2009,2013-2014 Apple Inc. All Rights Reserved.
34 * This is to fool os services to not provide the Keychain manager
35 * interface that doens't work since we don't have unified headers
36 * between iOS and OS X. rdar://23405418/
38 #define __KEYCHAINCORE__ 1
39 #import <Foundation/Foundation.h>
41 #include <TargetConditionals.h>
42 #include <CoreFoundation/CoreFoundation.h>
43 #include <Security/Security.h>
44 #include <Security/SecKeyPriv.h>
45 #include <Security/SecItemPriv.h>
47 #include <Security/SecItem.h>
48 #include <Security/SecKey.h>
51 #include <Security/SecCertificate.h>
52 #include <Security/SecCertificateInternal.h>
53 #include <Security/SecKey.h>
54 #include <Security/SecKeyPriv.h>
55 #include <Security/SecItem.h>
56 #include <Security/SecAsn1Types.h>
57 #include <Security/oidsalg.h>
58 #include <Security/SecureTransport.h>
59 #include <Security/SecRandom.h>
60 #include <CommonCrypto/CommonDigest.h>
61 #include <libDER/libDER.h>
67 #include "keychain_regressions.h"
68 #include "utilities/SecCFRelease.h"
69 #include "utilities/array_size.h"
73 static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecAsn1AlgId *algId) {
74 uint8_t dataToDigest[256];
75 size_t dataToDigestLen = sizeof(dataToDigest);
76 size_t sigLen = SecKeyGetSize(privKey, kSecKeySignatureSize);
80 oid.length = algId->algorithm.Length;
81 oid.data = algId->algorithm.Data;
83 /* Get the oid in decimal for display purposes. */
84 CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid);
86 CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8);
93 ok_status(status = SecKeyDigestAndSign(privKey, algId, dataToDigest, dataToDigestLen,
95 "digest and sign %s with %ld bit RSA key", oidBuf, sigLen * 8);
97 skip("SecKeyDigestAndSign failed", 3, status == errSecSuccess);
99 /* Verify the signature we just made. */
100 ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
101 sig, sigLen), "digest and verify");
102 /* Invalidate the signature. */
104 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
105 sig, sigLen), errSSLCrypto, "digest and verify bad sig");
107 dataToDigest[0] ^= 0xff;
108 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
109 sig, sigLen), errSSLCrypto, "digest and verify bad digest");
113 static void testdigestandsign(SecKeyRef privKey, SecKeyRef pubKey) {
114 static const SecAsn1Oid *oids[] = {
115 &CSSMOID_ECDSA_WithSHA1,
117 &CSSMOID_ECDSA_WithSHA224,
118 &CSSMOID_ECDSA_WithSHA256,
119 &CSSMOID_ECDSA_WithSHA384,
120 &CSSMOID_ECDSA_WithSHA512,
125 SecAsn1AlgId algId = {};
126 for (ix = 0; ix < sizeof(oids) / sizeof(*oids); ++ix) {
128 algId.algorithm = *oids[ix];
130 algId.algorithm.Length = 0;
131 algId.algorithm.Data = NULL;
134 testdigestandsignalg(privKey, pubKey, &algId);
139 static void testkeygen(size_t keySizeInBits) {
140 SecKeyRef pubKey = NULL, privKey = NULL;
141 size_t keySizeInBytes = (keySizeInBits + 7) / 8;
144 kzib = CFNumberCreate(NULL, kCFNumberSInt64Type, &keySizeInBits);
145 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
146 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC);
147 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
150 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
151 "Generate %ld bit (%ld byte) EC keypair", keySizeInBits,
156 SecKeyRef pubKeybis = SecKeyCopyPublicKey(privKey);
158 is(CFGetRetainCount(pubKeybis),2); // pubKey + pubKeybis
159 CFDataRef PubKeyData = SecKeyCopyExternalRepresentation(pubKey, NULL);
160 CFDataRef PubKeybisData = SecKeyCopyExternalRepresentation(pubKeybis, NULL);
161 isnt(CFDataGetLength(PubKeyData),0);
162 ok(CFEqual(PubKeyData,PubKeybisData));
163 CFReleaseNull(PubKeyData);
164 CFReleaseNull(PubKeybisData);
165 CFReleaseNull(pubKeybis);
169 skip("keygen failed", 8, status == errSecSuccess);
170 ok(pubKey, "pubKey returned");
171 ok(privKey, "privKey returned");
173 /* Sign something. */
174 uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
175 uint8_t sig[8+2*keySizeInBytes];
176 size_t sigLen = sizeof(sig);
177 ok_status(SecKeyRawSign(privKey, kSecPaddingNone,
178 something, sizeof(something), sig, &sigLen), "sign something");
179 ok_status(SecKeyRawVerify(pubKey, kSecPaddingNone,
180 something, sizeof(something), sig, sigLen), "verify sig on something");
183 testdigestandsign(privKey, pubKey);
186 const void *privkeys[] = {
189 const void *privvalues[] = {
192 CFDictionaryRef privitem = CFDictionaryCreate(NULL, privkeys, privvalues,
193 sizeof(privkeys) / sizeof(*privkeys), NULL, NULL);
195 ok_status(SecItemAdd(privitem, NULL), "add private key");
197 ok_status(SecItemDelete(privitem), "delete private key");
198 CFReleaseNull(privitem);
200 const void *pubKeys[] = {
203 const void *pubvalues[] = {
206 CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubKeys, pubvalues,
207 sizeof(pubKeys) / sizeof(*pubKeys), NULL, NULL);
209 ok_status(SecItemAdd(pubitem, NULL), "add public key");
211 ok_status(SecItemDelete(pubitem), "delete public key");
212 CFReleaseNull(pubitem);
215 CFReleaseNull(pubKey);
216 CFReleaseNull(privKey);
221 static void testkeygen2(size_t keySizeInBits) {
222 SecKeyRef pubKey = NULL, privKey = NULL;
223 size_t keySizeInBytes = (keySizeInBits + 7) / 8;
226 CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault);
227 CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID);
228 CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
229 CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
231 CFReleaseNull(ourUUID);
232 CFReleaseNull(uuidString);
234 CFStringAppend(publicName, CFSTR("-Public-41"));
235 CFStringAppend(privateName, CFSTR("-Private-41"));
237 CFMutableDictionaryRef pubd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
238 CFMutableDictionaryRef privd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
239 CFDictionaryAddValue(pubd, kSecAttrLabel, publicName);
240 CFDictionaryAddValue(privd, kSecAttrLabel, privateName);
242 kzib = CFNumberCreate(NULL, kCFNumberSInt64Type, &keySizeInBits);
243 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
244 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC);
245 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
246 CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanTrue);
247 CFDictionaryAddValue(kgp, kSecPublicKeyAttrs, pubd);
248 CFDictionaryAddValue(kgp, kSecPrivateKeyAttrs, privd);
251 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
252 "Generate %ld bit (%ld byte) persistent RSA keypair",
253 keySizeInBits, keySizeInBytes);
258 skip("keygen failed", 8, status == errSecSuccess);
259 ok(pubKey, "pubKey returned");
260 ok(privKey, "privKey returned");
262 SecKeyRef pubKey2, privKey2;
263 CFDictionaryAddValue(pubd, kSecClass, kSecClassKey);
264 CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue);
265 CFDictionaryAddValue(privd, kSecClass, kSecClassKey);
266 CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue);
267 CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue);
268 ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2),
269 "retrieve pub key by label");
270 ok(pubKey2, "got valid object");
271 ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2),
272 "retrieve priv key by label and kSecAttrCanSign");
273 ok(privKey2, "got valid object");
275 /* Sign something. */
276 uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
277 size_t sigLen = (((keySizeInBits + 7) / 8) + 3) * 2 + 3;
279 ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1,
280 something, sizeof(something), sig, &sigLen), "sign something");
281 ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1,
282 something, sizeof(something), sig, sigLen), "verify sig on something");
285 CFReleaseNull(pubKey2);
286 CFReleaseNull(privKey2);
289 /* delete from keychain - note: do it before releasing publicName and privateName
290 because pubd and privd have no retain/release callbacks */
291 ok_status(SecItemDelete(pubd), "delete generated pub key");
292 ok_status(SecItemDelete(privd), "delete generated priv key");
295 CFReleaseNull(pubKey);
296 CFReleaseNull(privKey);
298 CFReleaseNull(publicName);
299 CFReleaseNull(privateName);
305 static void testkeygen3(size_t keySizeInBits) {
306 SecKeyRef pubKey = NULL, privKey = NULL;
307 size_t keySizeInBytes = (keySizeInBits + 7) / 8;
310 kzib = CFNumberCreate(NULL, kCFNumberSInt64Type, &keySizeInBits);
311 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
312 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom);
313 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
314 CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanFalse);
316 ok(privKey = SecKeyCreateRandomKey(kgp, NULL));
320 ok(pubKey = SecKeyCopyPublicKey(privKey));
321 is(CFGetRetainCount(pubKey),1);
323 /* Sign something. */
324 uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
325 uint8_t sig[8+2*keySizeInBytes];
326 size_t sigLen = sizeof(sig);
327 ok_status(SecKeyRawSign(privKey, kSecPaddingNone,
328 something, sizeof(something), sig, &sigLen), "sign something");
329 ok_status(SecKeyRawVerify(pubKey, kSecPaddingNone,
330 something, sizeof(something), sig, sigLen), "verify sig on something");
333 CFReleaseNull(pubKey);
334 CFReleaseNull(privKey);
340 const uint8_t EC_P256_KeyDER[]={
341 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, 0x86, 0x87, 0x79, 0x59, 0xd1,
342 0xc6, 0x3c, 0x50, 0x24, 0x30, 0xa4, 0xaf, 0x89, 0x1d, 0xd1, 0x94, 0x23,
343 0x56, 0x79, 0x46, 0x93, 0x72, 0x31, 0x39, 0x24, 0xe6, 0x01, 0x96, 0xc8,
344 0xeb, 0xf3, 0x88, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x8c, 0xfa, 0xd7,
345 0x8a, 0xf1, 0xb9, 0xad, 0xd7, 0x3a, 0x33, 0xb5, 0x9a, 0xad, 0x52, 0x0d,
346 0x14, 0xd6, 0x6b, 0x35, 0x56, 0x79, 0xd6, 0x74, 0x2a, 0x37, 0x7e, 0x2f,
347 0x33, 0xa6, 0xab, 0xee, 0x35, 0x00, 0x70, 0x82, 0x89, 0x9c, 0xfc, 0x97,
348 0xc4, 0x89, 0x5c, 0x16, 0x50, 0xad, 0x60, 0x55, 0xa6, 0x70, 0xee, 0x07,
349 0x1b, 0xfe, 0xe4, 0xf0, 0xa0, 0x63, 0xc0, 0x73, 0x24, 0x97, 0x92, 0x04,
352 // Open SSL Private Key
353 const uint8_t EC_P256_KeyDER_priv[]={
354 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x86, 0x87, 0x79, 0x59, 0xd1,
355 0xc6, 0x3c, 0x50, 0x24, 0x30, 0xa4, 0xaf, 0x89, 0x1d, 0xd1, 0x94, 0x23,
356 0x56, 0x79, 0x46, 0x93, 0x72, 0x31, 0x39, 0x24, 0xe6, 0x01, 0x96, 0xc8,
357 0xeb, 0xf3, 0x88, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
358 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x8c, 0xfa, 0xd7,
359 0x8a, 0xf1, 0xb9, 0xad, 0xd7, 0x3a, 0x33, 0xb5, 0x9a, 0xad, 0x52, 0x0d,
360 0x14, 0xd6, 0x6b, 0x35, 0x56, 0x79, 0xd6, 0x74, 0x2a, 0x37, 0x7e, 0x2f,
361 0x33, 0xa6, 0xab, 0xee, 0x35, 0x00, 0x70, 0x82, 0x89, 0x9c, 0xfc, 0x97,
362 0xc4, 0x89, 0x5c, 0x16, 0x50, 0xad, 0x60, 0x55, 0xa6, 0x70, 0xee, 0x07,
363 0x1b, 0xfe, 0xe4, 0xf0, 0xa0, 0x63, 0xc0, 0x73, 0x24, 0x97, 0x92, 0x04,
366 // Open SSL Public Key
367 const uint8_t EC_P256_KeyDER_pub[]={
368 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
369 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
370 0x42, 0x00, 0x04, 0x8c, 0xfa, 0xd7, 0x8a, 0xf1, 0xb9, 0xad, 0xd7, 0x3a,
371 0x33, 0xb5, 0x9a, 0xad, 0x52, 0x0d, 0x14, 0xd6, 0x6b, 0x35, 0x56, 0x79,
372 0xd6, 0x74, 0x2a, 0x37, 0x7e, 0x2f, 0x33, 0xa6, 0xab, 0xee, 0x35, 0x00,
373 0x70, 0x82, 0x89, 0x9c, 0xfc, 0x97, 0xc4, 0x89, 0x5c, 0x16, 0x50, 0xad,
374 0x60, 0x55, 0xa6, 0x70, 0xee, 0x07, 0x1b, 0xfe, 0xe4, 0xf0, 0xa0, 0x63,
375 0xc0, 0x73, 0x24, 0x97, 0x92, 0x04, 0xc7};
378 const uint8_t EC_P256_SigDER[]={
379 0x30, 0x45, 0x02, 0x20, 0x4b, 0x37, 0x7f, 0x45, 0xd0, 0x5d, 0xa6, 0x53,
380 0xb3, 0x62, 0x6f, 0x32, 0xdb, 0xfc, 0xf6, 0x3b, 0x84, 0xfa, 0x5a, 0xd9,
381 0x17, 0x67, 0x03, 0x73, 0x48, 0x0c, 0xad, 0x89, 0x13, 0x69, 0x61, 0xb3,
382 0x02, 0x21, 0x00, 0xd6, 0x23, 0xaf, 0xd9, 0x7d, 0x72, 0xba, 0x3b, 0x90,
383 0xc1, 0x23, 0x7d, 0xdb, 0x2c, 0xd1, 0x0d, 0xbb, 0xb4, 0x0f, 0x67, 0x26,
384 0xff, 0x3f, 0xa6, 0x47, 0xa4, 0x13, 0x0d, 0xe0, 0x45, 0xd5, 0x6b};
386 const uint8_t EC_P256_SigRaw[]= {
387 0x4b, 0x37, 0x7f, 0x45, 0xd0, 0x5d, 0xa6, 0x53, 0xb3, 0x62, 0x6f, 0x32,
388 0xdb, 0xfc, 0xf6, 0x3b, 0x84, 0xfa, 0x5a, 0xd9, 0x17, 0x67, 0x03, 0x73,
389 0x48, 0x0c, 0xad, 0x89, 0x13, 0x69, 0x61, 0xb3, 0xd6, 0x23, 0xaf, 0xd9,
390 0x7d, 0x72, 0xba, 0x3b, 0x90, 0xc1, 0x23, 0x7d, 0xdb, 0x2c, 0xd1, 0x0d,
391 0xbb, 0xb4, 0x0f, 0x67, 0x26, 0xff, 0x3f, 0xa6, 0x47, 0xa4, 0x13, 0x0d,
392 0xe0, 0x45, 0xd5, 0x6b};
394 const uint8_t EC_SigDigest[24] = "012345678912345678901234";
396 /* r is 72 bytes longer than it should be */
397 const uint8_t EC_P256_SigDER_LargeInt[]={
398 0x30, 0x81, 0x8D, 0x02, 0x68,
399 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
402 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x37, 0x7f, 0x45, 0xd0, 0x5d, 0xa6, 0x53,
404 0xb3, 0x62, 0x6f, 0x32, 0xdb, 0xfc, 0xf6, 0x3b, 0x84, 0xfa, 0x5a, 0xd9, 0x17, 0x67, 0x03, 0x73,
405 0x48, 0x0c, 0xad, 0x89, 0x13, 0x69, 0x61, 0xb3,
407 0x00, 0xd6, 0x23, 0xaf, 0xd9, 0x7d, 0x72, 0xba, 0x3b, 0x90, 0xc1, 0x23, 0x7d, 0xdb, 0x2c, 0xd1,
408 0x0d, 0xbb, 0xb4, 0x0f, 0x67, 0x26, 0xff, 0x3f, 0xa6, 0x47, 0xa4, 0x13, 0x0d, 0xe0, 0x45, 0xd5,
411 static void testsignformat(void)
413 SecKeyRef privKey = NULL;
414 SecKeyRef pubKey = NULL;
415 CFArrayRef KeyArrayPub=NULL;
416 CFArrayRef KeyArrayPriv=NULL;
417 uint8_t EC_signature_DER[72];
418 uint8_t EC_signature_RAW[64];
419 size_t EC_signature_DER_size=sizeof(EC_signature_DER);
420 size_t EC_signature_RAW_size=sizeof(EC_signature_RAW);
423 // Key import for iOS
425 ok((privKey = SecKeyCreateECPrivateKey(kCFAllocatorDefault,
426 EC_P256_KeyDER, sizeof(EC_P256_KeyDER),
427 kSecKeyEncodingPkcs1)) != NULL, "import privkey");
428 CFDataRef pubdata = NULL;
429 ok_status(SecKeyCopyPublicBytes(privKey, &pubdata), "pub key from priv key");
431 ok((pubKey = SecKeyCreateECPublicKey(kCFAllocatorDefault,
432 CFDataGetBytePtr(pubdata), CFDataGetLength(pubdata),
433 kSecKeyEncodingBytes))!=NULL,
435 CFReleaseNull(pubdata);
438 // Key import for MacOS
441 SecExternalFormat sef=kSecFormatOpenSSL;
442 SecExternalItemType seit;
445 DER_key = CFDataCreate(kCFAllocatorDefault, EC_P256_KeyDER_pub, sizeof(EC_P256_KeyDER_pub));
446 seit=kSecItemTypePublicKey;
447 ok_status(SecItemImport(DER_key,NULL,&sef,&seit,0,NULL,NULL,&KeyArrayPub), "Import DER key");
448 ok((!(KeyArrayPub==NULL) && CFArrayGetCount(KeyArrayPub)==1), "One key imported");
449 pubKey=(SecKeyRef)CFArrayGetValueAtIndex(KeyArrayPub,0);
450 CFReleaseNull(DER_key);
453 DER_key = CFDataCreate(kCFAllocatorDefault, EC_P256_KeyDER_priv, sizeof(EC_P256_KeyDER_priv));
454 seit=kSecItemTypePrivateKey;
455 ok_status(SecItemImport(DER_key,NULL,&sef,&seit,0,NULL,NULL,&KeyArrayPriv), "Import DER key");
456 ok((!(KeyArrayPriv==NULL) && CFArrayGetCount(KeyArrayPriv)==1), "One key imported");
457 privKey=(SecKeyRef)CFArrayGetValueAtIndex(KeyArrayPriv,0);
458 CFReleaseNull(DER_key);
462 // Verify fixed signature
463 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1,
464 EC_SigDigest, sizeof(EC_SigDigest), EC_P256_SigDER, sizeof(EC_P256_SigDER)), "verify DER sig on something");
466 ok_status(SecKeyRawVerify(pubKey, kSecPaddingSigRaw,
467 EC_SigDigest, sizeof(EC_SigDigest), EC_P256_SigRaw, sizeof(EC_P256_SigRaw)), "verify RAW sig on something");
469 // Verify signature with mismatching format
470 ok_status(!SecKeyRawVerify(pubKey, kSecPaddingSigRaw,
471 EC_SigDigest, sizeof(EC_SigDigest), EC_P256_SigDER, sizeof(EC_P256_SigDER)), "verify DER sig with RAW option");
473 ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1,
474 EC_SigDigest, sizeof(EC_SigDigest), EC_P256_SigRaw, sizeof(EC_P256_SigRaw)), "verify RAW sig with DER something");
476 // Sign something in each format
477 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
478 EC_SigDigest, sizeof(EC_SigDigest), EC_signature_DER, &EC_signature_DER_size), "sign DER sig on something");
480 ok_status(SecKeyRawSign(privKey, kSecPaddingSigRaw,
481 EC_SigDigest, sizeof(EC_SigDigest), EC_signature_RAW, &EC_signature_RAW_size), "sign RAW sig on something");
483 // Verify expecting that verification does the right thing.
484 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1,
485 EC_SigDigest, sizeof(EC_SigDigest), EC_signature_DER, EC_signature_DER_size), "verify DER sig on something");
487 ok_status(SecKeyRawVerify(pubKey, kSecPaddingSigRaw,
488 EC_SigDigest, sizeof(EC_SigDigest), EC_signature_RAW, EC_signature_RAW_size), "verify RAW sig on something");
490 // Verify signature with one integer larger than it should be
491 ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1,
492 EC_SigDigest, sizeof(EC_SigDigest), EC_P256_SigDER_LargeInt, sizeof(EC_P256_SigDER_LargeInt)),
493 "verify DER sig with large integer");
495 CFReleaseNull(KeyArrayPub);
496 CFReleaseNull(KeyArrayPriv);
499 #if !TARGET_OS_IPHONE
500 static inline bool CFEqualSafe(CFTypeRef left, CFTypeRef right)
502 if (left == NULL || right == NULL)
503 return left == right;
505 return CFEqual(left, right);
509 static void testkeyexchange(unsigned long keySizeInBits)
511 size_t keySizeInBytes = (keySizeInBits + 7) / 8;
514 SecKeyRef pubKey1 = NULL, privKey1 = NULL;
515 NSDictionary *kgp1 = @{
516 (id)kSecAttrKeyType: (id)kSecAttrKeyTypeEC,
517 (id)kSecAttrKeySizeInBits: @(keySizeInBits),
518 (id)kSecAttrIsPermanent: @NO,
519 (id)kSecAttrLabel: @"sectests:kc-41-sececkey:testkeyexchange",
520 (id)kSecUseDataProtectionKeychain: @YES,
522 ok_status(status = SecKeyGeneratePair((CFDictionaryRef)kgp1, &pubKey1, &privKey1),
523 "Generate %ld bit (%ld byte) EC keypair (status = %d)",
524 keySizeInBits, keySizeInBytes, (int)status);
526 SecKeyRef pubKey1bis = SecKeyCopyPublicKey(privKey1);
527 ok(pubKey1bis!=NULL);
528 is(CFGetRetainCount(pubKey1bis),1);
529 CFDataRef PubKey1Data = SecKeyCopyExternalRepresentation(pubKey1, NULL);
530 CFDataRef PubKey1bisData = SecKeyCopyExternalRepresentation(pubKey1bis, NULL);
531 isnt(CFDataGetLength(PubKey1Data),0);
532 ok(CFEqual(PubKey1Data,PubKey1bisData));
533 CFReleaseNull(PubKey1Data);
534 CFReleaseNull(PubKey1bisData);
535 CFReleaseNull(pubKey1bis);
537 SecKeyRef pubKey2 = NULL, privKey2 = NULL;
538 NSDictionary *kgp2 = @{
539 (id)kSecAttrKeyType: (id)kSecAttrKeyTypeEC,
540 (id)kSecAttrKeySizeInBits: @(keySizeInBits),
541 (id)kSecAttrIsPermanent: @NO,
542 (id)kSecAttrLabel: @"sectests:kc-41-sececkey:testkeyexchange",
543 (id)kSecUseDataProtectionKeychain: @NO,
545 ok_status(status = SecKeyGeneratePair((CFDictionaryRef)kgp2, &pubKey2, &privKey2),
546 "Generate %ld bit (%ld byte) EC keypair (status = %d)",
547 keySizeInBits, keySizeInBytes, (int)status);
549 const SecKeyAlgorithm algos[] = {
550 kSecKeyAlgorithmECDHKeyExchangeStandard,
551 kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1,
552 kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224,
553 kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256,
554 kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384,
555 kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512,
556 kSecKeyAlgorithmECDHKeyExchangeCofactor,
557 kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1,
558 kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224,
559 kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256,
560 kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384,
561 kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512,
564 // Strange size to test borderline conditions.
565 const CFIndex requestedSize = 273;
566 NSDictionary *params = @{
567 (id)kSecKeyKeyExchangeParameterRequestedSize: @(requestedSize),
568 (id)kSecKeyKeyExchangeParameterSharedInfo: [NSData dataWithBytes:"shared" length:5],
571 for (size_t ix = 0; ix < array_size(algos); ++ix) {
572 CFErrorRef error = NULL;
574 NSData *secret1 = (__bridge_transfer NSData *)SecKeyCopyKeyExchangeResult(privKey1, algos[ix], pubKey2, (CFDictionaryRef)params, &error);
575 ok(secret1 != NULL && CFGetTypeID((__bridge CFTypeRef) secret1) == CFDataGetTypeID());
576 CFReleaseNull(error);
578 NSData *secret2 = (__bridge_transfer NSData *)SecKeyCopyKeyExchangeResult(privKey2, algos[ix], pubKey1, (CFDictionaryRef)params, &error);
579 ok(secret2 != NULL && CFGetTypeID((__bridge CFTypeRef) secret2) == CFDataGetTypeID());
580 CFReleaseNull(error);
582 eq_cf((__bridge CFTypeRef) secret1, (__bridge CFTypeRef) secret2, "results of key exchange are equal");
583 if (algos[ix] != kSecKeyAlgorithmECDHKeyExchangeCofactor && algos[ix] != kSecKeyAlgorithmECDHKeyExchangeStandard) {
584 is(secret1.length, requestedSize, "generated response has expected length");
588 // Test proper failure modes.
591 res = CFBridgingRelease(SecKeyCopyKeyExchangeResult(privKey1, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1, pubKey2, (CFDictionaryRef)@{}, (void *)&error));
592 is(res, nil, "keyExchange with missing required attributes did not fail");
593 res = CFBridgingRelease(SecKeyCopyKeyExchangeResult(privKey1, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1, pubKey2, (CFDictionaryRef)@{(id)kSecKeyKeyExchangeParameterRequestedSize: @"16"}, (void *)&error));
594 is(res, nil, "keyExchange with improper typed attributes did not fail");
595 res = CFBridgingRelease(SecKeyCopyKeyExchangeResult(privKey1, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1, pubKey2, (CFDictionaryRef)@{(id)kSecKeyKeyExchangeParameterRequestedSize: @16, (id)kSecKeyKeyExchangeParameterSharedInfo: @"sharedInfo"}, (void *)&error));
596 is(res, nil, "keyExchange with improper typed attributes did not fail");
598 CFReleaseNull(privKey1);
599 CFReleaseNull(pubKey1);
600 CFReleaseNull(privKey2);
601 CFReleaseNull(pubKey2);
603 SecItemDelete((CFDictionaryRef)@{
604 (id)kSecClass: (id)kSecClassKey,
605 (id)kSecAttrLabel: @"sectests:kc-41-sececkey:testkeyexchange",
609 /* Test basic add delete update copy matching stuff. */
610 static void tests(void)
634 testkeyexchange(256);
635 testkeyexchange(384);
636 testkeyexchange(521);
639 int kc_41_sececkey(int argc, char *const *argv)