2 * Copyright (c) 2007-2009,2012-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@
25 #include <CoreFoundation/CoreFoundation.h>
26 #include <Security/SecCertificate.h>
27 #include <Security/SecCertificateInternal.h>
28 #include <Security/SecKey.h>
29 #include <Security/SecKeyPriv.h>
30 #include <Security/SecItem.h>
31 #include <Security/SecAsn1Types.h>
32 #include <Security/oidsalg.h>
33 #include <Security/SecureTransport.h>
34 #include <Security/SecRandom.h>
35 #include <utilities/array_size.h>
36 #include <CommonCrypto/CommonDigest.h>
37 #include <libDER/libDER.h>
41 #include "Security_regressions.h"
43 #include "utilities/SecCFRelease.h"
45 static void testdigestandsignalg(SecKeyRef privKey
, SecKeyRef pubKey
, const SecAsn1AlgId
*algId
) {
46 uint8_t dataToDigest
[256] = {0,};
47 size_t dataToDigestLen
= sizeof(dataToDigest
);
48 size_t sigLen
= SecKeyGetSize(privKey
, kSecKeySignatureSize
);
52 oid
.length
= algId
->algorithm
.Length
;
53 oid
.data
= algId
->algorithm
.Data
;
55 /* Get the oid in decimal for display purposes. */
56 CFStringRef oidStr
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, &oid
);
58 CFStringGetCString(oidStr
, oidBuf
, sizeof(oidBuf
), kCFStringEncodingUTF8
);
65 ok_status(status
= SecKeyDigestAndSign(privKey
, algId
, dataToDigest
, dataToDigestLen
,
66 sig
, &sigLen
), "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
[] = {
87 &CSSMOID_SHA224WithRSA
,
88 &CSSMOID_SHA256WithRSA
,
89 &CSSMOID_SHA384WithRSA
,
90 &CSSMOID_SHA512WithRSA
,
92 &CSSMOID_SHA1WithRSA_OIW
,
93 &CSSMOID_SHA1WithDSA
, // BSAFE
94 &CSSMOID_SHA1WithDSA_CMS
, // X509/CMS
95 &CSSMOID_SHA1WithDSA_JDK
, // JDK 1.1
101 SecAsn1AlgId algId
= {};
102 for (ix
= 0; ix
< array_size(oids
); ++ix
) {
104 algId
.algorithm
= *oids
[ix
];
106 algId
.algorithm
.Length
= 0;
107 algId
.algorithm
.Data
= NULL
;
110 testdigestandsignalg(privKey
, pubKey
, &algId
);
115 static void dump_bytes(uint8_t* bytes
, size_t amount
)
118 printf("0x%02x ", *bytes
);
125 #define kEncryptDecryptTestCount 5
126 static void test_encrypt_decrypt(SecKeyRef pubKey
, SecKeyRef privKey
, uint32_t padding
, size_t keySizeInBytes
)
129 size_t max_len
= keySizeInBytes
;
131 case kSecPaddingNone
: max_len
= keySizeInBytes
; break;
132 case kSecPaddingOAEP
: max_len
= keySizeInBytes
- 2 - 2 * CC_SHA1_DIGEST_LENGTH
; break;
133 case kSecPaddingPKCS1
: max_len
= keySizeInBytes
- 11; break;
134 default: skip("what is the max_len for this padding?", 5, false);
137 uint8_t secret
[max_len
+ 1], encrypted_secret
[keySizeInBytes
], decrypted_secret
[keySizeInBytes
];
138 uint8_t *secret_ptr
= secret
;
139 size_t secret_len
= max_len
;
140 size_t encrypted_secret_len
= sizeof(encrypted_secret
);
141 size_t decrypted_secret_len
= sizeof(decrypted_secret
);
142 memset(decrypted_secret
, 0xff, decrypted_secret_len
);
143 SecRandomCopyBytes(kSecRandomDefault
, sizeof(secret
), secret
);
145 // zero pad, no accidental second zero byte
146 if (padding
== kSecPaddingNone
) {
151 is_status(SecKeyEncrypt(pubKey
, padding
,
152 secret
, sizeof(secret
),
153 encrypted_secret
, &encrypted_secret_len
), errSecParam
, "encrypt secret (overflow)");
154 ok_status(SecKeyEncrypt(pubKey
, padding
,
156 encrypted_secret
, &encrypted_secret_len
), "encrypt secret");
158 ok_status(SecKeyDecrypt(privKey
, padding
,
159 encrypted_secret
, encrypted_secret_len
,
160 decrypted_secret
, &decrypted_secret_len
), "decrypt secret");
162 // zero padding is removed on decode
163 if (padding
== kSecPaddingNone
) {
168 ok(decrypted_secret_len
== secret_len
, "correct length");
169 ok_status(memcmp(secret_ptr
, decrypted_secret
, secret_len
), "verify secret");
173 #define kKeyGenTestCount (49 + (3*kEncryptDecryptTestCount))
174 static void testkeygen(size_t keySizeInBits
) {
175 SecKeyRef pubKey
= NULL
, privKey
= NULL
;
176 size_t keySizeInBytes
= (keySizeInBits
+ 7) / 8;
179 int32_t iKeySizeInBits
= (int32_t) keySizeInBits
;
180 kzib
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &iKeySizeInBits
);
181 CFMutableDictionaryRef kgp
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
182 CFDictionaryAddValue(kgp
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
183 CFDictionaryAddValue(kgp
, kSecAttrKeySizeInBits
, kzib
);
186 ok_status(status
= SecKeyGeneratePair(kgp
, &pubKey
, &privKey
),
187 "Generate %ld bit (%ld byte) RSA keypair", keySizeInBits
,
193 skip("keygen failed", 8, status
== errSecSuccess
);
194 ok(pubKey
, "pubkey returned");
195 ok(privKey
, "privKey returned");
196 is(SecKeyGetSize(pubKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "public key size is ok");
197 is(SecKeyGetSize(privKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "private key size is ok");
199 /* Sign something. */
200 uint8_t something
[keySizeInBytes
];
201 size_t something_len
= keySizeInBytes
- 11;
202 SecRandomCopyBytes(kSecRandomDefault
, sizeof(something
), something
);
203 uint8_t sig
[keySizeInBytes
];
204 size_t sigLen
= sizeof(sig
);
205 is_status(SecKeyRawSign(privKey
, kSecPaddingPKCS1
,
206 something
, something_len
+ 1, sig
, &sigLen
),
207 errSecParam
, "sign overflow");
208 ok_status(SecKeyRawSign(privKey
, kSecPaddingPKCS1
,
209 something
, something_len
, sig
, &sigLen
), "sign something");
210 ok_status(SecKeyRawVerify(pubKey
, kSecPaddingPKCS1
,
211 something
, something_len
, sig
, sigLen
), "verify sig on something");
213 // Torture test ASN.1 encoder by setting high bit to 1.
214 uint8_t digest
[CC_SHA512_DIGEST_LENGTH
] = {
215 0x80, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
216 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
217 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
218 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
219 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
220 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
221 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
222 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
224 //CC_MD2(something, sizeof(something), digest);
225 ok_status(!SecKeyRawSign(privKey
, kSecPaddingPKCS1MD2
,
226 digest
, CC_MD2_DIGEST_LENGTH
, sig
, &sigLen
),
227 "don't sign md2 digest");
228 ok_status(!SecKeyRawVerify(pubKey
, kSecPaddingPKCS1MD2
,
229 digest
, CC_MD2_DIGEST_LENGTH
, sig
, sigLen
),
230 "verify sig on md2 digest fails");
232 //CC_MD5(something, sizeof(something), digest);
233 sigLen
= sizeof(sig
);
234 ok_status(!SecKeyRawSign(privKey
, kSecPaddingPKCS1MD5
,
235 digest
, CC_MD5_DIGEST_LENGTH
, sig
, &sigLen
),
236 "don't sign md5 digest");
237 ok_status(!SecKeyRawVerify(pubKey
, kSecPaddingPKCS1MD5
,
238 digest
, CC_MD5_DIGEST_LENGTH
, sig
, sigLen
),
239 "verify sig on md5 digest fails");
241 //CCDigest(kCCDigestSHA1, something, sizeof(something), digest);
242 sigLen
= sizeof(sig
);
243 ok_status(SecKeyRawSign(privKey
, kSecPaddingPKCS1SHA1
,
244 digest
, CC_SHA1_DIGEST_LENGTH
, sig
, &sigLen
),
246 ok_status(SecKeyRawVerify(pubKey
, kSecPaddingPKCS1SHA1
,
247 digest
, CC_SHA1_DIGEST_LENGTH
, sig
, sigLen
),
248 "verify sig on sha1 digest");
250 uint8_t signature
[keySizeInBytes
], *ptr
= signature
;
251 size_t signature_len
= sizeof(signature
);
252 ok_status(SecKeyDecrypt(pubKey
, kSecPaddingNone
, sig
, sigLen
, signature
, &signature_len
), "inspect signature");
253 is(signature_len
, keySizeInBytes
- 1, "got signature");
254 while(*ptr
&& ((size_t)(ptr
- signature
) < signature_len
)) ptr
++;
255 is(signature
+ signature_len
- ptr
, 16 /* length(\0 || OID_SHA1) */ + CC_SHA1_DIGEST_LENGTH
, "successful decode");
257 /* PKCS1 padding is 00 01 PAD * 8 or more 00 data.
258 data is SEQ { SEQ { OID NULL } BIT STRING 00 DIGEST }
259 So min data + pad overhead is 11 + 9 + oidlen
260 oidlen = 11 for the sha2 family of oids, so we have 29 bytes; or
261 232 bits of minimum overhead. */
262 const size_t pkcs1Overhead
= 232;
263 if (keySizeInBits
> 224 + pkcs1Overhead
) {
264 //CC_SHA224(something, sizeof(something), digest);
265 sigLen
= sizeof(sig
);
266 ok_status(SecKeyRawSign(privKey
, kSecPaddingPKCS1SHA224
,
267 digest
, CC_SHA224_DIGEST_LENGTH
, sig
, &sigLen
),
268 "sign sha224 digest");
269 ok_status(SecKeyRawVerify(pubKey
, kSecPaddingPKCS1SHA224
,
270 digest
, CC_SHA224_DIGEST_LENGTH
, sig
, sigLen
),
271 "verify sig on sha224 digest");
274 if (keySizeInBits
> 256 + pkcs1Overhead
) {
275 //CC_SHA256(something, sizeof(something), digest);
276 sigLen
= sizeof(sig
);
277 ok_status(SecKeyRawSign(privKey
, kSecPaddingPKCS1SHA256
,
278 digest
, CC_SHA256_DIGEST_LENGTH
, sig
, &sigLen
),
279 "sign sha256 digest");
280 ok_status(SecKeyRawVerify(pubKey
, kSecPaddingPKCS1SHA256
,
281 digest
, CC_SHA256_DIGEST_LENGTH
, sig
, sigLen
),
282 "verify sig on sha256 digest");
285 if (keySizeInBits
> 384 + pkcs1Overhead
) {
286 //CC_SHA384(something, sizeof(something), digest);
287 sigLen
= sizeof(sig
);
288 ok_status(SecKeyRawSign(privKey
, kSecPaddingPKCS1SHA384
,
289 digest
, CC_SHA384_DIGEST_LENGTH
, sig
, &sigLen
),
290 "sign sha384 digest");
291 ok_status(SecKeyRawVerify(pubKey
, kSecPaddingPKCS1SHA384
,
292 digest
, CC_SHA384_DIGEST_LENGTH
, sig
, sigLen
),
293 "verify sig on sha384 digest");
296 if (keySizeInBits
> 512 + pkcs1Overhead
) {
297 //CC_SHA512(something, sizeof(something), digest);
298 sigLen
= sizeof(sig
);
299 ok_status(SecKeyRawSign(privKey
, kSecPaddingPKCS1SHA512
,
300 digest
, CC_SHA512_DIGEST_LENGTH
, sig
, &sigLen
),
301 "sign sha512 digest");
302 ok_status(SecKeyRawVerify(pubKey
, kSecPaddingPKCS1SHA512
,
303 digest
, CC_SHA512_DIGEST_LENGTH
, sig
, sigLen
),
304 "verify sig on sha512 digest");
307 test_encrypt_decrypt(pubKey
, privKey
, kSecPaddingNone
, keySizeInBytes
);
308 test_encrypt_decrypt(pubKey
, privKey
, kSecPaddingPKCS1
, keySizeInBytes
);
309 test_encrypt_decrypt(pubKey
, privKey
, kSecPaddingOAEP
, keySizeInBytes
);
311 testdigestandsign(privKey
, pubKey
);
313 const void *privkeys
[] = {
316 const void *privvalues
[] = {
319 CFDictionaryRef privitem
= CFDictionaryCreate(NULL
, privkeys
, privvalues
,
320 array_size(privkeys
), NULL
, NULL
);
321 ok_status(SecItemAdd(privitem
, NULL
), "add private key");
322 ok_status(SecItemDelete(privitem
), "delete private key");
323 CFReleaseNull(privitem
);
325 const void *pubkeys
[] = {
328 const void *pubvalues
[] = {
331 CFDictionaryRef pubitem
= CFDictionaryCreate(NULL
, pubkeys
, pubvalues
,
332 array_size(pubkeys
), NULL
, NULL
);
333 ok_status(SecItemAdd(pubitem
, NULL
), "add public key");
334 ok_status(SecItemDelete(pubitem
), "delete public key");
335 CFReleaseNull(pubitem
);
338 CFReleaseNull(pubKey
);
339 CFReleaseNull(privKey
);
343 #define kKeyGen2TestCount 12
344 static void testkeygen2(size_t keySizeInBits
) {
345 SecKeyRef pubKey
= NULL
, privKey
= NULL
;
346 size_t keySizeInBytes
= (keySizeInBits
+ 7) / 8;
349 CFUUIDRef ourUUID
= CFUUIDCreate(kCFAllocatorDefault
);
350 CFStringRef uuidString
= CFUUIDCreateString(kCFAllocatorDefault
, ourUUID
);
351 CFMutableStringRef publicName
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, uuidString
);
352 CFMutableStringRef privateName
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, uuidString
);
354 CFReleaseNull(ourUUID
);
355 CFReleaseNull(uuidString
);
357 CFStringAppend(publicName
, CFSTR("-Public-40"));
358 CFStringAppend(privateName
, CFSTR("-Private-40"));
359 CFMutableDictionaryRef pubd
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
360 CFMutableDictionaryRef privd
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
362 CFDictionaryAddValue(pubd
, kSecAttrLabel
, publicName
);
363 CFDictionaryAddValue(privd
, kSecAttrLabel
, privateName
);
365 int32_t iKeySizeInBits
= (int32_t) keySizeInBits
;
366 kzib
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &iKeySizeInBits
);
367 CFMutableDictionaryRef kgp
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
368 CFDictionaryAddValue(kgp
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
369 CFDictionaryAddValue(kgp
, kSecAttrKeySizeInBits
, kzib
);
370 CFDictionaryAddValue(kgp
, kSecAttrIsPermanent
, kCFBooleanTrue
);
371 CFDictionaryAddValue(kgp
, kSecPublicKeyAttrs
, pubd
);
372 CFDictionaryAddValue(kgp
, kSecPrivateKeyAttrs
, privd
);
375 ok_status(status
= SecKeyGeneratePair(kgp
, &pubKey
, &privKey
),
376 "Generate %ld bit (%ld byte) persistent RSA keypair",
377 keySizeInBits
, keySizeInBytes
);
382 skip("keygen failed", 8, status
== errSecSuccess
);
383 ok(pubKey
, "pubkey returned");
384 ok(privKey
, "privKey returned");
385 is(SecKeyGetSize(pubKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "public key size is ok");
386 is(SecKeyGetSize(privKey
, kSecKeyKeySizeInBits
), (size_t) keySizeInBits
, "private key size is ok");
388 SecKeyRef pubKey2
, privKey2
;
389 CFDictionaryAddValue(pubd
, kSecClass
, kSecClassKey
);
390 CFDictionaryAddValue(pubd
, kSecReturnRef
, kCFBooleanTrue
);
391 CFDictionaryAddValue(privd
, kSecClass
, kSecClassKey
);
392 CFDictionaryAddValue(privd
, kSecReturnRef
, kCFBooleanTrue
);
393 CFDictionaryAddValue(privd
, kSecAttrCanSign
, kCFBooleanTrue
);
394 ok_status(SecItemCopyMatching(pubd
, (CFTypeRef
*)&pubKey2
),
395 "retrieve pub key by label");
396 ok_status(SecItemCopyMatching(privd
, (CFTypeRef
*)&privKey2
),
397 "retrieve priv key by label and kSecAttrCanSign");
399 /* Sign something. */
400 uint8_t something
[50] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
401 uint8_t sig
[keySizeInBytes
];
402 size_t sigLen
= keySizeInBytes
;
403 ok_status(SecKeyRawSign(privKey2
, kSecPaddingPKCS1
,
404 something
, sizeof(something
), sig
, &sigLen
), "sign something");
405 ok_status(SecKeyRawVerify(pubKey2
, kSecPaddingPKCS1
,
406 something
, sizeof(something
), sig
, sigLen
), "verify sig on something");
408 sigLen
= keySizeInBytes
;
409 is_status(SecKeyEncrypt(pubKey2
, kSecPaddingPKCS1SHA1
,
410 something
, sizeof(something
), sig
, &sigLen
), errSecParam
,
411 "encrypt something with invalid padding");
414 CFReleaseNull(pubKey2
);
415 CFReleaseNull(privKey2
);
417 /* delete from keychain - note: do it before releasing publicName and privateName
418 because pubd and privd have no retain/release callbacks */
419 ok_status(SecItemDelete(pubd
), "delete generated pub key");
420 ok_status(SecItemDelete(privd
), "delete generated priv key");
424 CFReleaseNull(pubKey
);
425 CFReleaseNull(privKey
);
427 CFReleaseNull(publicName
);
428 CFReleaseNull(privateName
);
434 /* Test basic add delete update copy matching stuff. */
435 #define kTestCount ((3 * kKeyGenTestCount) + kKeyGen2TestCount)
436 static void tests(void)
438 /* Comment out lines below for testing generating all common key sizes,
439 disabled now for speed reasons. */
443 testkeygen(2056); // Stranged sized for edge cases in padding.
450 int si_40_seckey(int argc
, char *const *argv
)
452 plan_tests(kTestCount
);