2 * Copyright (c) 2011-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,2012-2014 Apple Inc. All Rights Reserved.
33 #include <CoreFoundation/CoreFoundation.h>
34 #include <Security/SecCertificate.h>
35 #include <Security/SecCertificateInternal.h>
36 #include <Security/SecKey.h>
37 #include <Security/SecECKey.h>
38 #include <Security/SecKeyPriv.h>
39 #include <Security/SecItem.h>
40 #include <Security/SecAsn1Types.h>
41 #include <Security/oidsalg.h>
42 #include <Security/SecureTransport.h>
43 #include <Security/SecRandom.h>
44 #include <utilities/array_size.h>
45 #include <utilities/SecCFRelease.h>
46 #include <utilities/SecCFWrappers.h>
47 #include <CommonCrypto/CommonDigest.h>
48 #include <libDER/libDER.h>
52 #include "Security_regressions.h"
54 static void testdigestandsignalg(SecKeyRef privKey
, SecKeyRef pubKey
, const SecAsn1AlgId
*algId
) {
55 uint8_t dataToDigest
[256] = {0,};
56 size_t dataToDigestLen
= sizeof(dataToDigest
);
57 size_t sigLen
= SecKeyGetSize(privKey
, kSecKeySignatureSize
);
61 oid
.length
= algId
->algorithm
.Length
;
62 oid
.data
= algId
->algorithm
.Data
;
64 /* Get the oid in decimal for display purposes. */
65 CFStringRef oidStr
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, &oid
);
67 CFStringGetCString(oidStr
, oidBuf
, sizeof(oidBuf
), kCFStringEncodingUTF8
);
74 ok_status(status
= SecKeyDigestAndSign(privKey
, algId
, dataToDigest
, dataToDigestLen
,
76 "digest and sign %s with %ld bit RSA key", oidBuf
, sigLen
* 8);
78 skip("SecKeyDigestAndSign failed", 3, status
== errSecSuccess
);
80 /* Verify the signature we just made. */
81 ok_status(SecKeyDigestAndVerify(pubKey
, algId
, dataToDigest
, dataToDigestLen
,
82 sig
, sigLen
), "digest and verify");
83 /* Invalidate the signature. */
85 is_status(SecKeyDigestAndVerify(pubKey
, algId
, dataToDigest
, dataToDigestLen
,
86 sig
, sigLen
), errSSLCrypto
, "digest and verify bad sig");
88 dataToDigest
[0] ^= 0xff;
89 is_status(SecKeyDigestAndVerify(pubKey
, algId
, dataToDigest
, dataToDigestLen
,
90 sig
, sigLen
), errSSLCrypto
, "digest and verify bad digest");
94 static void testdigestandsign(SecKeyRef privKey
, SecKeyRef pubKey
) {
95 static const SecAsn1Oid
*oids
[] = {
96 &CSSMOID_ECDSA_WithSHA1
,
98 &CSSMOID_ECDSA_WithSHA224
,
99 &CSSMOID_ECDSA_WithSHA256
,
100 &CSSMOID_ECDSA_WithSHA384
,
101 &CSSMOID_ECDSA_WithSHA512
,
106 SecAsn1AlgId algId
= {};
107 for (ix
= 0; ix
< array_size(oids
); ++ix
) {
109 algId
.algorithm
= *oids
[ix
];
111 algId
.algorithm
.Length
= 0;
112 algId
.algorithm
.Data
= NULL
;
115 testdigestandsignalg(privKey
, pubKey
, &algId
);
119 static void testkeygen(size_t keySizeInBits
) {
120 SecKeyRef pubKey
= NULL
, privKey
= NULL
;
121 size_t keySizeInBytes
= (keySizeInBits
+ 7) / 8;
123 int32_t keysz32
= (int32_t)keySizeInBits
;
125 kzib
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &keysz32
);
126 CFMutableDictionaryRef kgp
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
127 CFDictionaryAddValue(kgp
, kSecAttrKeyType
, kSecAttrKeyTypeEC
);
128 CFDictionaryAddValue(kgp
, kSecAttrKeySizeInBits
, kzib
);
131 ok_status(status
= SecKeyGeneratePair(kgp
, &pubKey
, &privKey
),
132 "Generate %ld bit (%ld byte) EC keypair", keySizeInBits
,
138 skip("keygen failed", 8, status
== errSecSuccess
);
139 ok(pubKey
, "pubkey returned");
140 ok(privKey
, "privKey returned");
141 is(SecKeyGetSize(pubKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "public key size is ok");
142 is(SecKeyGetSize(privKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "private key size is ok");
144 /* Sign something. */
145 uint8_t something
[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
146 uint8_t sig
[8+2*keySizeInBytes
];
147 size_t sigLen
= sizeof(sig
);
148 ok_status(SecKeyRawSign(privKey
, kSecPaddingNone
,
149 something
, sizeof(something
), sig
, &sigLen
), "sign something");
150 ok_status(SecKeyRawVerify(pubKey
, kSecPaddingNone
,
151 something
, sizeof(something
), sig
, sigLen
), "verify sig on something");
153 testdigestandsign(privKey
, pubKey
);
155 const void *privkeys
[] = {
158 const void *privvalues
[] = {
161 CFDictionaryRef privitem
= CFDictionaryCreate(NULL
, privkeys
, privvalues
,
162 array_size(privkeys
), NULL
, NULL
);
163 ok_status(SecItemAdd(privitem
, NULL
), "add private key");
164 ok_status(SecItemDelete(privitem
), "delete public key");
165 CFReleaseNull(privitem
);
167 const void *pubkeys
[] = {
170 const void *pubvalues
[] = {
173 CFDictionaryRef pubitem
= CFDictionaryCreate(NULL
, pubkeys
, pubvalues
,
174 array_size(pubkeys
), NULL
, NULL
);
175 ok_status(SecItemAdd(pubitem
, NULL
), "add public key");
176 ok_status(SecItemDelete(pubitem
), "delete public key");
177 CFReleaseNull(pubitem
);
180 CFReleaseNull(pubKey
);
181 CFReleaseNull(privKey
);
186 static void testkeygen2(size_t keySizeInBits
) {
187 SecKeyRef pubKey
= NULL
, privKey
= NULL
;
188 size_t keySizeInBytes
= (keySizeInBits
+ 7) / 8;
190 int32_t keysz32
= (int32_t)keySizeInBits
;
192 CFUUIDRef ourUUID
= CFUUIDCreate(kCFAllocatorDefault
);
193 CFStringRef uuidString
= CFUUIDCreateString(kCFAllocatorDefault
, ourUUID
);
194 CFMutableStringRef publicName
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, uuidString
);
195 CFMutableStringRef privateName
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, uuidString
);
197 CFReleaseNull(ourUUID
);
198 CFReleaseNull(uuidString
);
200 CFStringAppend(publicName
, CFSTR("-Public-41"));
201 CFStringAppend(privateName
, CFSTR("-Private-41"));
203 CFMutableDictionaryRef pubd
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
,
204 kSecAttrLabel
, publicName
,
206 CFMutableDictionaryRef privd
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
,
207 kSecAttrLabel
, privateName
,
210 kzib
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &keysz32
);
211 CFDictionaryRef kgp
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
212 kSecAttrKeyType
, kSecAttrKeyTypeEC
,
213 kSecAttrKeySizeInBits
, kzib
,
214 kSecAttrIsPermanent
, kCFBooleanTrue
,
215 kSecPublicKeyAttrs
, pubd
,
216 kSecPrivateKeyAttrs
, privd
,
222 ok_status(status
= SecKeyGeneratePair(kgp
, &pubKey
, &privKey
),
223 "Generate %ld bit (%ld byte) persistent RSA keypair",
224 keySizeInBits
, keySizeInBytes
);
229 skip("keygen failed", 8, status
== errSecSuccess
);
230 ok(pubKey
, "pubkey returned");
231 ok(privKey
, "privKey returned");
232 is(SecKeyGetSize(pubKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "public key size is ok");
233 is(SecKeyGetSize(privKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "private key size is ok");
235 SecKeyRef pubKey2
, privKey2
;
236 CFDictionaryAddValue(pubd
, kSecClass
, kSecClassKey
);
237 CFDictionaryAddValue(pubd
, kSecReturnRef
, kCFBooleanTrue
);
238 CFDictionaryAddValue(privd
, kSecClass
, kSecClassKey
);
239 CFDictionaryAddValue(privd
, kSecReturnRef
, kCFBooleanTrue
);
240 CFDictionaryAddValue(privd
, kSecAttrCanSign
, kCFBooleanTrue
);
241 ok_status(SecItemCopyMatching(pubd
, (CFTypeRef
*)&pubKey2
),
242 "retrieve pub key by label");
243 ok(pubKey2
, "got valid object");
244 ok_status(SecItemCopyMatching(privd
, (CFTypeRef
*)&privKey2
),
245 "retrieve priv key by label and kSecAttrCanSign");
246 ok(privKey2
, "got valid object");
248 /* Sign something. */
249 uint8_t something
[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
250 size_t sigLen
= SecKeyGetSize(privKey2
, kSecKeySignatureSize
);
252 ok_status(SecKeyRawSign(privKey2
, kSecPaddingPKCS1
,
253 something
, sizeof(something
), sig
, &sigLen
), "sign something");
254 ok_status(SecKeyRawVerify(pubKey2
, kSecPaddingPKCS1
,
255 something
, sizeof(something
), sig
, sigLen
), "verify sig on something");
258 CFReleaseNull(pubKey2
);
259 CFReleaseNull(privKey2
);
262 /* delete from keychain - note: do it before releasing publicName and privateName
263 because pubd and privd have no retain/release callbacks */
264 ok_status(SecItemDelete(pubd
), "delete generated pub key");
265 ok_status(SecItemDelete(privd
), "delete generated priv key");
268 CFReleaseNull(pubKey
);
269 CFReleaseNull(privKey
);
271 CFReleaseNull(publicName
);
272 CFReleaseNull(privateName
);
275 CFReleaseNull(privd
);
278 static void testkeywrap(unsigned long keySizeInBits
, CFTypeRef alg
)
280 SecKeyRef pubKey
= NULL
, privKey
= NULL
;
281 size_t keySizeInBytes
= (keySizeInBits
+ 7) / 8;
283 int32_t keysz32
= (int32_t)keySizeInBits
;
285 CFUUIDRef ourUUID
= CFUUIDCreate(kCFAllocatorDefault
);
286 CFStringRef uuidString
= CFUUIDCreateString(kCFAllocatorDefault
, ourUUID
);
287 CFMutableStringRef publicName
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, uuidString
);
288 CFMutableStringRef privateName
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, uuidString
);
290 CFReleaseNull(ourUUID
);
291 CFReleaseNull(uuidString
);
293 CFStringAppend(publicName
, CFSTR("-Public-41"));
294 CFStringAppend(privateName
, CFSTR("-Private-41"));
296 CFDictionaryRef pubd
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
297 kSecAttrLabel
, publicName
,
299 CFDictionaryRef privd
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
300 kSecAttrLabel
, privateName
,
303 CFReleaseNull(publicName
);
304 CFReleaseNull(privateName
);
306 kzib
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &keysz32
);
307 CFDictionaryRef kgp
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
308 kSecAttrKeyType
, kSecAttrKeyTypeEC
,
309 kSecAttrKeySizeInBits
, kzib
,
310 kSecAttrIsPermanent
, kCFBooleanFalse
,
311 kSecPublicKeyAttrs
, pubd
,
312 kSecPrivateKeyAttrs
, privd
,
315 CFReleaseNull(privd
);
319 ok_status(status
= SecKeyGeneratePair(kgp
, &pubKey
, &privKey
),
320 "Generate %ld bit (%ld byte) persistent RSA keypair (status = %d)",
321 keySizeInBits
, keySizeInBytes
, (int)status
);
324 CFErrorRef localError
= NULL
;
326 CFDataRef secret
= CFDataCreate(NULL
, (void *)"0123456789012345", 16);
327 ok(secret
, "secret");
329 CFDataRef fp
= CFDataCreate(NULL
, (void *)"01234567890123456789", 20);
330 ok(fp
, "fingerprint");
333 int8_t sym_alg_data
= 8;
334 CFNumberRef symalg
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &sym_alg_data
);
335 CFDictionaryRef param
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
336 _kSecKeyWrapPGPWrapAlg
, alg
,
337 _kSecKeyWrapPGPSymAlg
, symalg
,
338 _kSecKeyWrapPGPFingerprint
, fp
,
341 CFDataRef wrapped
= _SecKeyCopyWrapKey(pubKey
, kSecKeyWrapPublicKeyPGP
, secret
, param
, NULL
, &localError
);
342 ok(wrapped
, "wrap key: %@", localError
);
344 CFDataRef unwrapped
= _SecKeyCopyUnwrapKey(privKey
, kSecKeyWrapPublicKeyPGP
, wrapped
, param
, NULL
, &localError
);
345 ok(unwrapped
, "unwrap key: %@", localError
);
347 CFReleaseNull(symalg
);
349 ok(CFEqual(unwrapped
, secret
), "keys still same");
352 CFReleaseNull(secret
);
353 CFReleaseNull(unwrapped
);
354 CFReleaseNull(wrapped
);
355 CFReleaseNull(param
);
356 CFReleaseNull(privKey
);
357 CFReleaseNull(pubKey
);
360 const uint8_t EC_P256_KeyDER
[]={
361 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, 0x86, 0x87, 0x79, 0x59, 0xd1,
362 0xc6, 0x3c, 0x50, 0x24, 0x30, 0xa4, 0xaf, 0x89, 0x1d, 0xd1, 0x94, 0x23,
363 0x56, 0x79, 0x46, 0x93, 0x72, 0x31, 0x39, 0x24, 0xe6, 0x01, 0x96, 0xc8,
364 0xeb, 0xf3, 0x88, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x8c, 0xfa, 0xd7,
365 0x8a, 0xf1, 0xb9, 0xad, 0xd7, 0x3a, 0x33, 0xb5, 0x9a, 0xad, 0x52, 0x0d,
366 0x14, 0xd6, 0x6b, 0x35, 0x56, 0x79, 0xd6, 0x74, 0x2a, 0x37, 0x7e, 0x2f,
367 0x33, 0xa6, 0xab, 0xee, 0x35, 0x00, 0x70, 0x82, 0x89, 0x9c, 0xfc, 0x97,
368 0xc4, 0x89, 0x5c, 0x16, 0x50, 0xad, 0x60, 0x55, 0xa6, 0x70, 0xee, 0x07,
369 0x1b, 0xfe, 0xe4, 0xf0, 0xa0, 0x63, 0xc0, 0x73, 0x24, 0x97, 0x92, 0x04,
372 const uint8_t EC_P256_SigDER
[]={
373 0x30, 0x45, 0x02, 0x20, 0x4b, 0x37, 0x7f, 0x45, 0xd0, 0x5d, 0xa6, 0x53,
374 0xb3, 0x62, 0x6f, 0x32, 0xdb, 0xfc, 0xf6, 0x3b, 0x84, 0xfa, 0x5a, 0xd9,
375 0x17, 0x67, 0x03, 0x73, 0x48, 0x0c, 0xad, 0x89, 0x13, 0x69, 0x61, 0xb3,
376 0x02, 0x21, 0x00, 0xd6, 0x23, 0xaf, 0xd9, 0x7d, 0x72, 0xba, 0x3b, 0x90,
377 0xc1, 0x23, 0x7d, 0xdb, 0x2c, 0xd1, 0x0d, 0xbb, 0xb4, 0x0f, 0x67, 0x26,
378 0xff, 0x3f, 0xa6, 0x47, 0xa4, 0x13, 0x0d, 0xe0, 0x45, 0xd5, 0x6b};
380 const uint8_t EC_P256_SigRaw
[]= {
381 0x4b, 0x37, 0x7f, 0x45, 0xd0, 0x5d, 0xa6, 0x53, 0xb3, 0x62, 0x6f, 0x32,
382 0xdb, 0xfc, 0xf6, 0x3b, 0x84, 0xfa, 0x5a, 0xd9, 0x17, 0x67, 0x03, 0x73,
383 0x48, 0x0c, 0xad, 0x89, 0x13, 0x69, 0x61, 0xb3, 0xd6, 0x23, 0xaf, 0xd9,
384 0x7d, 0x72, 0xba, 0x3b, 0x90, 0xc1, 0x23, 0x7d, 0xdb, 0x2c, 0xd1, 0x0d,
385 0xbb, 0xb4, 0x0f, 0x67, 0x26, 0xff, 0x3f, 0xa6, 0x47, 0xa4, 0x13, 0x0d,
386 0xe0, 0x45, 0xd5, 0x6b};
388 const uint8_t EC_SigDigest
[24] = "012345678912345678901234";
390 static void testsignformat(void)
392 SecKeyRef pkey
= NULL
;
393 SecKeyRef pubkey
= NULL
;
394 CFDataRef pubdata
= NULL
;
395 uint8_t EC_signature_DER
[72];
396 uint8_t EC_signature_RAW
[64];
397 size_t EC_signature_DER_size
=sizeof(EC_signature_DER
);
398 size_t EC_signature_RAW_size
=sizeof(EC_signature_RAW
);
400 ok((pkey
= SecKeyCreateECPrivateKey(kCFAllocatorDefault
,
401 EC_P256_KeyDER
, sizeof(EC_P256_KeyDER
),
402 kSecKeyEncodingPkcs1
)) != NULL
, "import privkey");
404 ok_status(SecKeyCopyPublicBytes(pkey
, &pubdata
), "pub key from priv key");
406 ok((pubkey
= SecKeyCreateECPublicKey(kCFAllocatorDefault
,
407 CFDataGetBytePtr(pubdata
), CFDataGetLength(pubdata
),
408 kSecKeyEncodingBytes
))!=NULL
,
411 // Verify fixed signature
412 ok_status(SecKeyRawVerify(pubkey
, kSecPaddingPKCS1
,
413 EC_SigDigest
, sizeof(EC_SigDigest
), EC_P256_SigDER
, sizeof(EC_P256_SigDER
)), "verify DER sig on something");
415 ok_status(SecKeyRawVerify(pubkey
, kSecPaddingSigRaw
,
416 EC_SigDigest
, sizeof(EC_SigDigest
), EC_P256_SigRaw
, sizeof(EC_P256_SigRaw
)), "verify RAW sig on something");
418 // Verify signature with mismatching format
419 ok_status(!SecKeyRawVerify(pubkey
, kSecPaddingSigRaw
,
420 EC_SigDigest
, sizeof(EC_SigDigest
), EC_P256_SigDER
, sizeof(EC_P256_SigDER
)), "verify DER sig with RAW option");
422 ok_status(!SecKeyRawVerify(pubkey
, kSecPaddingPKCS1
,
423 EC_SigDigest
, sizeof(EC_SigDigest
), EC_P256_SigRaw
, sizeof(EC_P256_SigRaw
)), "verify RAW sig with DER something");
425 // Sign something in each format
426 ok_status(SecKeyRawSign(pkey
, kSecPaddingPKCS1
,
427 EC_SigDigest
, sizeof(EC_SigDigest
), EC_signature_DER
, &EC_signature_DER_size
), "sign DER sig on something");
429 ok_status(SecKeyRawSign(pkey
, kSecPaddingSigRaw
,
430 EC_SigDigest
, sizeof(EC_SigDigest
), EC_signature_RAW
, &EC_signature_RAW_size
), "sign RAW sig on something");
432 // Verify expecting that verification does the right thing.
433 ok_status(SecKeyRawVerify(pubkey
, kSecPaddingPKCS1
,
434 EC_SigDigest
, sizeof(EC_SigDigest
), EC_signature_DER
, EC_signature_DER_size
), "verify DER sig on something");
436 ok_status(SecKeyRawVerify(pubkey
, kSecPaddingSigRaw
,
437 EC_SigDigest
, sizeof(EC_SigDigest
), EC_signature_RAW
, EC_signature_RAW_size
), "verify RAW sig on something");
440 CFReleaseNull(pubkey
);
441 CFReleaseNull(pubdata
);
444 /* Test basic add delete update copy matching stuff. */
445 static void tests(void)
461 testkeywrap(256, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
);
462 testkeywrap(521, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
);
463 testkeywrap(256, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
);
464 testkeywrap(521, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
);
468 int si_41_sececkey(int argc
, char *const *argv
)