5 // Created by Mitch Adler on 5/20/11.
6 // Copyright 2011 Apple Inc. All rights reserved.
13 * Created by Michael Brouwer on 1/29/07.
14 * Copyright (c) 2007-2009 Apple Inc. All Rights Reserved.
17 #include <TargetConditionals.h>
18 #include <CoreFoundation/CoreFoundation.h>
19 #include <Security/Security.h>
20 #include <Security/SecKeyPriv.h>
23 #include <Security/SecCertificate.h>
24 #include <Security/SecCertificateInternal.h>
25 #include <Security/SecKey.h>
26 #include <Security/SecKeyPriv.h>
27 #include <Security/SecItem.h>
28 #include <Security/SecAsn1Types.h>
29 #include <Security/oidsalg.h>
30 #include <Security/SecureTransport.h>
31 #include <Security/SecRandom.h>
32 #include <CommonCrypto/CommonDigest.h>
33 #include <libDER/libDER.h>
39 #include "keychain_regressions.h"
40 #include "utilities/SecCFRelease.h"
44 static void testdigestandsignalg(SecKeyRef privKey
, SecKeyRef pubKey
, const SecAsn1AlgId
*algId
) {
45 uint8_t dataToDigest
[256];
46 size_t dataToDigestLen
= sizeof(dataToDigest
);
47 size_t sigLen
= SecKeyGetSize(privKey
, kSecKeySignatureSize
);
51 oid
.length
= algId
->algorithm
.Length
;
52 oid
.data
= algId
->algorithm
.Data
;
54 /* Get the oid in decimal for display purposes. */
55 CFStringRef oidStr
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, &oid
);
57 CFStringGetCString(oidStr
, oidBuf
, sizeof(oidBuf
), kCFStringEncodingUTF8
);
64 ok_status(status
= SecKeyDigestAndSign(privKey
, algId
, dataToDigest
, dataToDigestLen
,
66 "digest and sign %s with %ld bit RSA key", oidBuf
, sigLen
* 8);
68 skip("SecKeyDigestAndSign failed", 3, status
== errSecSuccess
);
70 /* Verify the signature we just made. */
71 ok_status(SecKeyDigestAndVerify(pubKey
, algId
, dataToDigest
, dataToDigestLen
,
72 sig
, sigLen
), "digest and verify");
73 /* Invalidate the signature. */
75 is_status(SecKeyDigestAndVerify(pubKey
, algId
, dataToDigest
, dataToDigestLen
,
76 sig
, sigLen
), errSSLCrypto
, "digest and verify bad sig");
78 dataToDigest
[0] ^= 0xff;
79 is_status(SecKeyDigestAndVerify(pubKey
, algId
, dataToDigest
, dataToDigestLen
,
80 sig
, sigLen
), errSSLCrypto
, "digest and verify bad digest");
84 static void testdigestandsign(SecKeyRef privKey
, SecKeyRef pubKey
) {
85 static const SecAsn1Oid
*oids
[] = {
86 &CSSMOID_ECDSA_WithSHA1
,
88 &CSSMOID_ECDSA_WithSHA224
,
89 &CSSMOID_ECDSA_WithSHA256
,
90 &CSSMOID_ECDSA_WithSHA384
,
91 &CSSMOID_ECDSA_WithSHA512
,
96 SecAsn1AlgId algId
= {};
97 for (ix
= 0; ix
< sizeof(oids
) / sizeof(*oids
); ++ix
) {
99 algId
.algorithm
= *oids
[ix
];
101 algId
.algorithm
.Length
= 0;
102 algId
.algorithm
.Data
= NULL
;
105 testdigestandsignalg(privKey
, pubKey
, &algId
);
111 #if !TARGET_OS_IPHONE
112 /* This is part of Security.framework on iOS */
115 // kSecKeyKeySizeInBits = 0, // already exists on osx
116 kSecKeySignatureSize
= 101,
117 kSecKeyEncryptedDataSize
= 102,
118 // More might belong here, but we aren't settled on how
119 // to take into account padding and/or digest types.
123 size_t SecKeyGetSize(SecKeyRef key
, int whichSize
)
125 /* SecKeyGetBlockSize return the signature size on OS X -- smh */
126 size_t result
= SecKeyGetBlockSize(key
);
128 result
= (result
- 2)/2 - 3;
130 /* in this test, this is always an ECDSA key */
132 case kSecKeyEncryptedDataSize
:
135 case kSecKeySignatureSize
:
136 result
= (result
>= 66 ? 9 : 8) + 2 * result
;
138 case kSecKeyKeySizeInBits
:
143 if (whichSize
== kSecKeyKeySizeInBits
)
152 static void testkeygen(size_t keySizeInBits
) {
153 SecKeyRef pubKey
= NULL
, privKey
= NULL
;
154 size_t keySizeInBytes
= (keySizeInBits
+ 7) / 8;
157 kzib
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &keySizeInBits
);
158 CFMutableDictionaryRef kgp
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
159 CFDictionaryAddValue(kgp
, kSecAttrKeyType
, kSecAttrKeyTypeEC
);
160 CFDictionaryAddValue(kgp
, kSecAttrKeySizeInBits
, kzib
);
163 ok_status(status
= SecKeyGeneratePair(kgp
, &pubKey
, &privKey
),
164 "Generate %ld bit (%ld byte) EC keypair", keySizeInBits
,
170 skip("keygen failed", 8, status
== errSecSuccess
);
171 ok(pubKey
, "pubkey returned");
172 ok(privKey
, "privKey returned");
173 is(SecKeyGetSize(pubKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "public key size is ok");
174 is(SecKeyGetSize(privKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "private key size is ok");
176 /* Sign something. */
177 uint8_t something
[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
178 uint8_t sig
[8+2*keySizeInBytes
];
179 size_t sigLen
= sizeof(sig
);
180 ok_status(SecKeyRawSign(privKey
, kSecPaddingNone
,
181 something
, sizeof(something
), sig
, &sigLen
), "sign something");
182 ok_status(SecKeyRawVerify(pubKey
, kSecPaddingNone
,
183 something
, sizeof(something
), sig
, sigLen
), "verify sig on something");
186 testdigestandsign(privKey
, pubKey
);
189 const void *privkeys
[] = {
192 const void *privvalues
[] = {
195 CFDictionaryRef privitem
= CFDictionaryCreate(NULL
, privkeys
, privvalues
,
196 sizeof(privkeys
) / sizeof(*privkeys
), NULL
, NULL
);
198 ok_status(SecItemAdd(privitem
, NULL
), "add private key");
200 ok_status(SecItemDelete(privitem
), "delete private key");
201 CFReleaseNull(privitem
);
203 const void *pubkeys
[] = {
206 const void *pubvalues
[] = {
209 CFDictionaryRef pubitem
= CFDictionaryCreate(NULL
, pubkeys
, pubvalues
,
210 sizeof(pubkeys
) / sizeof(*pubkeys
), NULL
, NULL
);
212 ok_status(SecItemAdd(pubitem
, NULL
), "add public key");
214 ok_status(SecItemDelete(pubitem
), "delete public key");
215 CFReleaseNull(pubitem
);
218 CFReleaseNull(pubKey
);
219 CFReleaseNull(privKey
);
224 static void testkeygen2(size_t keySizeInBits
) {
225 SecKeyRef pubKey
= NULL
, privKey
= NULL
;
226 size_t keySizeInBytes
= (keySizeInBits
+ 7) / 8;
229 CFUUIDRef ourUUID
= CFUUIDCreate(kCFAllocatorDefault
);
230 CFStringRef uuidString
= CFUUIDCreateString(kCFAllocatorDefault
, ourUUID
);
231 CFMutableStringRef publicName
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, uuidString
);
232 CFMutableStringRef privateName
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, uuidString
);
234 CFReleaseNull(ourUUID
);
235 CFReleaseNull(uuidString
);
237 CFStringAppend(publicName
, CFSTR("-Public-41"));
238 CFStringAppend(privateName
, CFSTR("-Private-41"));
240 CFMutableDictionaryRef pubd
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
241 CFMutableDictionaryRef privd
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
242 CFDictionaryAddValue(pubd
, kSecAttrLabel
, publicName
);
243 CFDictionaryAddValue(privd
, kSecAttrLabel
, privateName
);
245 kzib
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &keySizeInBits
);
246 CFMutableDictionaryRef kgp
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
247 CFDictionaryAddValue(kgp
, kSecAttrKeyType
, kSecAttrKeyTypeEC
);
248 CFDictionaryAddValue(kgp
, kSecAttrKeySizeInBits
, kzib
);
249 CFDictionaryAddValue(kgp
, kSecAttrIsPermanent
, kCFBooleanTrue
);
250 CFDictionaryAddValue(kgp
, kSecPublicKeyAttrs
, pubd
);
251 CFDictionaryAddValue(kgp
, kSecPrivateKeyAttrs
, privd
);
254 ok_status(status
= SecKeyGeneratePair(kgp
, &pubKey
, &privKey
),
255 "Generate %ld bit (%ld byte) persistent RSA keypair",
256 keySizeInBits
, keySizeInBytes
);
261 skip("keygen failed", 8, status
== errSecSuccess
);
262 ok(pubKey
, "pubkey returned");
263 ok(privKey
, "privKey returned");
264 is(SecKeyGetSize(pubKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "public key size is ok");
265 is(SecKeyGetSize(privKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "private key size is ok");
267 SecKeyRef pubKey2
, privKey2
;
268 CFDictionaryAddValue(pubd
, kSecClass
, kSecClassKey
);
269 CFDictionaryAddValue(pubd
, kSecReturnRef
, kCFBooleanTrue
);
270 CFDictionaryAddValue(privd
, kSecClass
, kSecClassKey
);
271 CFDictionaryAddValue(privd
, kSecReturnRef
, kCFBooleanTrue
);
272 CFDictionaryAddValue(privd
, kSecAttrCanSign
, kCFBooleanTrue
);
273 ok_status(SecItemCopyMatching(pubd
, (CFTypeRef
*)&pubKey2
),
274 "retrieve pub key by label");
275 ok(pubKey2
, "got valid object");
276 ok_status(SecItemCopyMatching(privd
, (CFTypeRef
*)&privKey2
),
277 "retrieve priv key by label and kSecAttrCanSign");
278 ok(privKey2
, "got valid object");
280 /* Sign something. */
281 uint8_t something
[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
282 size_t sigLen
= SecKeyGetSize(privKey2
, kSecKeySignatureSize
);
284 ok_status(SecKeyRawSign(privKey2
, kSecPaddingPKCS1
,
285 something
, sizeof(something
), sig
, &sigLen
), "sign something");
286 ok_status(SecKeyRawVerify(pubKey2
, kSecPaddingPKCS1
,
287 something
, sizeof(something
), sig
, sigLen
), "verify sig on something");
290 CFReleaseNull(pubKey2
);
291 CFReleaseNull(privKey2
);
294 /* delete from keychain - note: do it before releasing publicName and privateName
295 because pubd and privd have no retain/release callbacks */
296 ok_status(SecItemDelete(pubd
), "delete generated pub key");
297 ok_status(SecItemDelete(privd
), "delete generated priv key");
300 CFReleaseNull(pubKey
);
301 CFReleaseNull(privKey
);
303 CFReleaseNull(publicName
);
304 CFReleaseNull(privateName
);
311 /* Test basic add delete update copy matching stuff. */
312 static void tests(void)
332 int kc_41_sececkey(int argc
, char *const *argv
)