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.
32 #include <TargetConditionals.h>
33 #include <CoreFoundation/CoreFoundation.h>
34 #include <Security/Security.h>
35 #include <Security/SecKeyPriv.h>
38 #include <Security/SecCertificate.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <Security/SecKey.h>
41 #include <Security/SecKeyPriv.h>
42 #include <Security/SecItem.h>
43 #include <Security/SecAsn1Types.h>
44 #include <Security/oidsalg.h>
45 #include <Security/SecureTransport.h>
46 #include <Security/SecRandom.h>
47 #include <CommonCrypto/CommonDigest.h>
48 #include <libDER/libDER.h>
54 #include "keychain_regressions.h"
55 #include "utilities/SecCFRelease.h"
59 static void testdigestandsignalg(SecKeyRef privKey
, SecKeyRef pubKey
, const SecAsn1AlgId
*algId
) {
60 uint8_t dataToDigest
[256];
61 size_t dataToDigestLen
= sizeof(dataToDigest
);
62 size_t sigLen
= SecKeyGetSize(privKey
, kSecKeySignatureSize
);
66 oid
.length
= algId
->algorithm
.Length
;
67 oid
.data
= algId
->algorithm
.Data
;
69 /* Get the oid in decimal for display purposes. */
70 CFStringRef oidStr
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, &oid
);
72 CFStringGetCString(oidStr
, oidBuf
, sizeof(oidBuf
), kCFStringEncodingUTF8
);
79 ok_status(status
= SecKeyDigestAndSign(privKey
, algId
, dataToDigest
, dataToDigestLen
,
81 "digest and sign %s with %ld bit RSA key", oidBuf
, sigLen
* 8);
83 skip("SecKeyDigestAndSign failed", 3, status
== errSecSuccess
);
85 /* Verify the signature we just made. */
86 ok_status(SecKeyDigestAndVerify(pubKey
, algId
, dataToDigest
, dataToDigestLen
,
87 sig
, sigLen
), "digest and verify");
88 /* Invalidate the signature. */
90 is_status(SecKeyDigestAndVerify(pubKey
, algId
, dataToDigest
, dataToDigestLen
,
91 sig
, sigLen
), errSSLCrypto
, "digest and verify bad sig");
93 dataToDigest
[0] ^= 0xff;
94 is_status(SecKeyDigestAndVerify(pubKey
, algId
, dataToDigest
, dataToDigestLen
,
95 sig
, sigLen
), errSSLCrypto
, "digest and verify bad digest");
99 static void testdigestandsign(SecKeyRef privKey
, SecKeyRef pubKey
) {
100 static const SecAsn1Oid
*oids
[] = {
101 &CSSMOID_ECDSA_WithSHA1
,
103 &CSSMOID_ECDSA_WithSHA224
,
104 &CSSMOID_ECDSA_WithSHA256
,
105 &CSSMOID_ECDSA_WithSHA384
,
106 &CSSMOID_ECDSA_WithSHA512
,
111 SecAsn1AlgId algId
= {};
112 for (ix
= 0; ix
< sizeof(oids
) / sizeof(*oids
); ++ix
) {
114 algId
.algorithm
= *oids
[ix
];
116 algId
.algorithm
.Length
= 0;
117 algId
.algorithm
.Data
= NULL
;
120 testdigestandsignalg(privKey
, pubKey
, &algId
);
126 #if !TARGET_OS_IPHONE
127 /* This is part of Security.framework on iOS */
130 // kSecKeyKeySizeInBits = 0, // already exists on osx
131 kSecKeySignatureSize
= 101,
132 kSecKeyEncryptedDataSize
= 102,
133 // More might belong here, but we aren't settled on how
134 // to take into account padding and/or digest types.
138 size_t SecKeyGetSize(SecKeyRef key
, int whichSize
)
140 /* SecKeyGetBlockSize return the signature size on OS X -- smh */
141 size_t result
= SecKeyGetBlockSize(key
);
143 result
= (result
- 2)/2 - 3;
145 /* in this test, this is always an ECDSA key */
147 case kSecKeyEncryptedDataSize
:
150 case kSecKeySignatureSize
:
151 result
= (result
>= 66 ? 9 : 8) + 2 * result
;
153 case kSecKeyKeySizeInBits
:
158 if (whichSize
== kSecKeyKeySizeInBits
)
167 static void testkeygen(size_t keySizeInBits
) {
168 SecKeyRef pubKey
= NULL
, privKey
= NULL
;
169 size_t keySizeInBytes
= (keySizeInBits
+ 7) / 8;
172 kzib
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &keySizeInBits
);
173 CFMutableDictionaryRef kgp
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
174 CFDictionaryAddValue(kgp
, kSecAttrKeyType
, kSecAttrKeyTypeEC
);
175 CFDictionaryAddValue(kgp
, kSecAttrKeySizeInBits
, kzib
);
178 ok_status(status
= SecKeyGeneratePair(kgp
, &pubKey
, &privKey
),
179 "Generate %ld bit (%ld byte) EC keypair", keySizeInBits
,
185 skip("keygen failed", 8, status
== errSecSuccess
);
186 ok(pubKey
, "pubkey returned");
187 ok(privKey
, "privKey returned");
188 is(SecKeyGetSize(pubKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "public key size is ok");
189 is(SecKeyGetSize(privKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "private key size is ok");
191 /* Sign something. */
192 uint8_t something
[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
193 uint8_t sig
[8+2*keySizeInBytes
];
194 size_t sigLen
= sizeof(sig
);
195 ok_status(SecKeyRawSign(privKey
, kSecPaddingNone
,
196 something
, sizeof(something
), sig
, &sigLen
), "sign something");
197 ok_status(SecKeyRawVerify(pubKey
, kSecPaddingNone
,
198 something
, sizeof(something
), sig
, sigLen
), "verify sig on something");
201 testdigestandsign(privKey
, pubKey
);
204 const void *privkeys
[] = {
207 const void *privvalues
[] = {
210 CFDictionaryRef privitem
= CFDictionaryCreate(NULL
, privkeys
, privvalues
,
211 sizeof(privkeys
) / sizeof(*privkeys
), NULL
, NULL
);
213 ok_status(SecItemAdd(privitem
, NULL
), "add private key");
215 ok_status(SecItemDelete(privitem
), "delete private key");
216 CFReleaseNull(privitem
);
218 const void *pubkeys
[] = {
221 const void *pubvalues
[] = {
224 CFDictionaryRef pubitem
= CFDictionaryCreate(NULL
, pubkeys
, pubvalues
,
225 sizeof(pubkeys
) / sizeof(*pubkeys
), NULL
, NULL
);
227 ok_status(SecItemAdd(pubitem
, NULL
), "add public key");
229 ok_status(SecItemDelete(pubitem
), "delete public key");
230 CFReleaseNull(pubitem
);
233 CFReleaseNull(pubKey
);
234 CFReleaseNull(privKey
);
239 static void testkeygen2(size_t keySizeInBits
) {
240 SecKeyRef pubKey
= NULL
, privKey
= NULL
;
241 size_t keySizeInBytes
= (keySizeInBits
+ 7) / 8;
244 CFUUIDRef ourUUID
= CFUUIDCreate(kCFAllocatorDefault
);
245 CFStringRef uuidString
= CFUUIDCreateString(kCFAllocatorDefault
, ourUUID
);
246 CFMutableStringRef publicName
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, uuidString
);
247 CFMutableStringRef privateName
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, uuidString
);
249 CFReleaseNull(ourUUID
);
250 CFReleaseNull(uuidString
);
252 CFStringAppend(publicName
, CFSTR("-Public-41"));
253 CFStringAppend(privateName
, CFSTR("-Private-41"));
255 CFMutableDictionaryRef pubd
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
256 CFMutableDictionaryRef privd
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
257 CFDictionaryAddValue(pubd
, kSecAttrLabel
, publicName
);
258 CFDictionaryAddValue(privd
, kSecAttrLabel
, privateName
);
260 kzib
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &keySizeInBits
);
261 CFMutableDictionaryRef kgp
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
262 CFDictionaryAddValue(kgp
, kSecAttrKeyType
, kSecAttrKeyTypeEC
);
263 CFDictionaryAddValue(kgp
, kSecAttrKeySizeInBits
, kzib
);
264 CFDictionaryAddValue(kgp
, kSecAttrIsPermanent
, kCFBooleanTrue
);
265 CFDictionaryAddValue(kgp
, kSecPublicKeyAttrs
, pubd
);
266 CFDictionaryAddValue(kgp
, kSecPrivateKeyAttrs
, privd
);
269 ok_status(status
= SecKeyGeneratePair(kgp
, &pubKey
, &privKey
),
270 "Generate %ld bit (%ld byte) persistent RSA keypair",
271 keySizeInBits
, keySizeInBytes
);
276 skip("keygen failed", 8, status
== errSecSuccess
);
277 ok(pubKey
, "pubkey returned");
278 ok(privKey
, "privKey returned");
279 is(SecKeyGetSize(pubKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "public key size is ok");
280 is(SecKeyGetSize(privKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "private key size is ok");
282 SecKeyRef pubKey2
, privKey2
;
283 CFDictionaryAddValue(pubd
, kSecClass
, kSecClassKey
);
284 CFDictionaryAddValue(pubd
, kSecReturnRef
, kCFBooleanTrue
);
285 CFDictionaryAddValue(privd
, kSecClass
, kSecClassKey
);
286 CFDictionaryAddValue(privd
, kSecReturnRef
, kCFBooleanTrue
);
287 CFDictionaryAddValue(privd
, kSecAttrCanSign
, kCFBooleanTrue
);
288 ok_status(SecItemCopyMatching(pubd
, (CFTypeRef
*)&pubKey2
),
289 "retrieve pub key by label");
290 ok(pubKey2
, "got valid object");
291 ok_status(SecItemCopyMatching(privd
, (CFTypeRef
*)&privKey2
),
292 "retrieve priv key by label and kSecAttrCanSign");
293 ok(privKey2
, "got valid object");
295 /* Sign something. */
296 uint8_t something
[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
297 size_t sigLen
= SecKeyGetSize(privKey2
, kSecKeySignatureSize
);
299 ok_status(SecKeyRawSign(privKey2
, kSecPaddingPKCS1
,
300 something
, sizeof(something
), sig
, &sigLen
), "sign something");
301 ok_status(SecKeyRawVerify(pubKey2
, kSecPaddingPKCS1
,
302 something
, sizeof(something
), sig
, sigLen
), "verify sig on something");
305 CFReleaseNull(pubKey2
);
306 CFReleaseNull(privKey2
);
309 /* delete from keychain - note: do it before releasing publicName and privateName
310 because pubd and privd have no retain/release callbacks */
311 ok_status(SecItemDelete(pubd
), "delete generated pub key");
312 ok_status(SecItemDelete(privd
), "delete generated priv key");
315 CFReleaseNull(pubKey
);
316 CFReleaseNull(privKey
);
318 CFReleaseNull(publicName
);
319 CFReleaseNull(privateName
);
326 /* Test basic add delete update copy matching stuff. */
327 static void tests(void)
347 int kc_41_sececkey(int argc
, char *const *argv
)