]> git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/regressions/kc-40-seckey.c
Security-55471.14.tar.gz
[apple/security.git] / libsecurity_keychain / regressions / kc-40-seckey.c
1 /*
2 * si-40-seckey.c
3 * Security
4 *
5 * Created by Michael Brouwer on 1/29/07.
6 * Copyright (c) 2007-2009 Apple Inc. All Rights Reserved.
7 *
8 */
9
10 #include <TargetConditionals.h>
11 #include <CoreFoundation/CoreFoundation.h>
12 #include <Security/Security.h>
13 #include <Security/SecRandom.h>
14 #include <CommonCrypto/CommonDigest.h>
15 #include <Security/SecKeyPriv.h>
16
17 #if 0
18 #include <Security/SecCertificate.h>
19 #include <Security/SecCertificateInternal.h>
20 #include <Security/SecKey.h>
21 #include <Security/SecKeyPriv.h>
22 #include <Security/SecItem.h>
23 #include <Security/SecAsn1Types.h>
24 #include <Security/oidsalg.h>
25 #include <libDER/libDER.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #endif
29
30 #include "keychain_regressions.h"
31 #include "utilities/SecCFRelease.h"
32
33 #if TARGET_OS_IPHONE
34 static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecAsn1AlgId *algId) {
35 uint8_t dataToDigest[256];
36 size_t dataToDigestLen = sizeof(dataToDigest);
37 size_t sigLen = SecKeyGetSize(privKey, kSecKeySignatureSize);
38 uint8_t sig[sigLen];
39
40 DERItem oid;
41 oid.length = algId->algorithm.Length;
42 oid.data = algId->algorithm.Data;
43
44 /* Get the oid in decimal for display purposes. */
45 CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid);
46 char oidBuf[40];
47 CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8);
48 CFRelease(oidStr);
49
50 SKIP: {
51 OSStatus status;
52
53 /* Time to sign. */
54 ok_status(status = SecKeyDigestAndSign(privKey, algId, dataToDigest, dataToDigestLen,
55 sig, &sigLen), "digest and sign %s with %ld bit RSA key", oidBuf, sigLen * 8);
56
57 skip("SecKeyDigestAndSign failed", 3, status == errSecSuccess);
58
59 /* Verify the signature we just made. */
60 ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
61 sig, sigLen), "digest and verify");
62 /* Invalidate the signature. */
63 sig[0] ^= 0xff;
64 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
65 sig, sigLen), errSSLCrypto, "digest and verify bad sig");
66 sig[0] ^= 0xff;
67 dataToDigest[0] ^= 0xff;
68 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
69 sig, sigLen), errSSLCrypto, "digest and verify bad digest");
70 }
71 }
72
73 static void testdigestandsign(SecKeyRef privKey, SecKeyRef pubKey) {
74 static const SecAsn1Oid *oids[] = {
75 &CSSMOID_SHA1WithRSA,
76 &CSSMOID_SHA224WithRSA,
77 &CSSMOID_SHA256WithRSA,
78 &CSSMOID_SHA384WithRSA,
79 &CSSMOID_SHA512WithRSA,
80 #if 0
81 &CSSMOID_SHA1WithRSA_OIW,
82 &CSSMOID_SHA1WithDSA, // BSAFE
83 &CSSMOID_SHA1WithDSA_CMS, // X509/CMS
84 &CSSMOID_SHA1WithDSA_JDK, // JDK 1.1
85 #endif
86 };
87
88
89 uint32_t ix;
90 SecAsn1AlgId algId = {};
91 for (ix = 0; ix < sizeof(oids) / sizeof(*oids); ++ix) {
92 if (oids[ix]) {
93 algId.algorithm = *oids[ix];
94 } else {
95 algId.algorithm.Length = 0;
96 algId.algorithm.Data = NULL;
97 }
98
99 testdigestandsignalg(privKey, pubKey, &algId);
100 }
101 }
102 #endif
103
104 #if 0
105 static void dump_bytes(uint8_t* bytes, size_t amount)
106 {
107 while (amount > 0) {
108 printf("0x%02x ", *bytes);
109 ++bytes;
110 --amount;
111 }
112 }
113 #endif
114
115
116 #if !TARGET_OS_IPHONE
117 #define kEncryptDecryptTestCount 0
118 #else
119 #define kEncryptDecryptTestCount 5
120 static void test_encrypt_decrypt(SecKeyRef pubKey, SecKeyRef privKey, uint32_t padding, size_t keySizeInBytes)
121 {
122 SKIP: {
123 size_t max_len = keySizeInBytes;
124 switch (padding) {
125 case kSecPaddingNone: max_len = keySizeInBytes; break;
126 case kSecPaddingOAEP: max_len = keySizeInBytes - 2 - 2 * CC_SHA1_DIGEST_LENGTH; break;
127 case kSecPaddingPKCS1: max_len = keySizeInBytes - 11; break;
128 default: skip("what is the max_len for this padding?", 5, false);
129 }
130
131 uint8_t secret[max_len + 1], encrypted_secret[keySizeInBytes], decrypted_secret[keySizeInBytes];
132 uint8_t *secret_ptr = secret;
133 size_t secret_len = max_len;
134 size_t encrypted_secret_len = sizeof(encrypted_secret);
135 size_t decrypted_secret_len = sizeof(decrypted_secret);
136 memset(decrypted_secret, 0xff, decrypted_secret_len);
137 SecRandomCopyBytes(kSecRandomDefault, sizeof(secret), secret);
138
139 // zero pad, no accidental second zero byte
140 if (padding == kSecPaddingNone) {
141 secret[0] = 0;
142 secret[1] = 128;
143 }
144
145 is_status(SecKeyEncrypt(pubKey, padding,
146 secret, sizeof(secret),
147 encrypted_secret, &encrypted_secret_len), errSecParam, "encrypt secret (overflow)");
148 ok_status(SecKeyEncrypt(pubKey, padding,
149 secret, secret_len,
150 encrypted_secret, &encrypted_secret_len), "encrypt secret");
151
152 ok_status(SecKeyDecrypt(privKey, padding,
153 encrypted_secret, encrypted_secret_len,
154 decrypted_secret, &decrypted_secret_len), "decrypt secret");
155
156 // zero padding is removed on decode
157 if (padding == kSecPaddingNone) {
158 secret_len--;
159 secret_ptr++;
160 }
161
162 ok(decrypted_secret_len == secret_len, "correct length");
163 ok_status(memcmp(secret_ptr, decrypted_secret, secret_len), "verify secret");
164 }
165 }
166 #endif
167
168
169
170 #if !TARGET_OS_IPHONE
171 /* This is part of Security.framework on iOS */
172
173 enum {
174 // kSecKeyKeySizeInBits = 0, // already exists on osx
175 kSecKeySignatureSize = 101,
176 kSecKeyEncryptedDataSize = 102,
177 // More might belong here, but we aren't settled on how
178 // to take into account padding and/or digest types.
179 };
180
181 static
182 size_t SecKeyGetSize(SecKeyRef key, int whichSize)
183 {
184 size_t result = SecKeyGetBlockSize(key);
185
186 /* This is only RSA */
187 if (whichSize == kSecKeyKeySizeInBits)
188 result *= 8;
189
190 return result;
191 }
192 #endif
193
194 #define kKeyGenTestCount (11 + (3*kEncryptDecryptTestCount))
195 static void testkeygen(size_t keySizeInBits) {
196 SecKeyRef pubKey = NULL, privKey = NULL;
197 size_t keySizeInBytes = (keySizeInBits + 7) / 8;
198 CFNumberRef kzib;
199
200 kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keySizeInBits);
201 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
202 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeRSA);
203 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
204
205 OSStatus status;
206 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
207 "Generate %ld bit (%ld byte) RSA keypair", keySizeInBits,
208 keySizeInBytes);
209 CFRelease(kzib);
210 CFRelease(kgp);
211
212 SKIP: {
213 skip("keygen failed", 8, status == errSecSuccess);
214 ok(pubKey, "pubkey returned");
215 ok(privKey, "privKey returned");
216 is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
217 is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
218
219 /* Sign something. */
220 uint8_t something[keySizeInBytes];
221 size_t something_len = keySizeInBytes - 11;
222 SecRandomCopyBytes(kSecRandomDefault, sizeof(something), something);
223 uint8_t sig[keySizeInBytes];
224 size_t sigLen = sizeof(sig);
225 #if TARGET_OS_IPHONE
226 /* TODO: This is returning another error on OS X */
227 is_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
228 something, something_len + 1, sig, &sigLen),
229 errSecParam, "sign overflow");
230 #endif
231 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
232 something, something_len, sig, &sigLen), "sign something");
233 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1,
234 something, something_len, sig, sigLen), "verify sig on something");
235
236 // Torture test ASN.1 encoder by setting high bit to 1.
237 uint8_t digest[CC_SHA512_DIGEST_LENGTH] = {
238 0x80, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
239 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
240 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
241 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
242 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
243 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
244 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
245 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
246 };
247 #if TARGET_OS_IPHONE
248 /* Thoses tests are making sure that MD2 and MD5 are NOT supported,
249 but they still are on OS X */
250
251 //CC_MD2(something, sizeof(something), digest);
252 ok_status(!SecKeyRawSign(privKey, kSecPaddingPKCS1MD2,
253 digest, CC_MD2_DIGEST_LENGTH, sig, &sigLen),
254 "don't sign md2 digest"); //FAIL
255 ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1MD2,
256 digest, CC_MD2_DIGEST_LENGTH, sig, sigLen),
257 "verify sig on md2 digest fails"); //FAIL
258
259 //CC_MD5(something, sizeof(something), digest);
260 sigLen = sizeof(sig);
261 ok_status(!SecKeyRawSign(privKey, kSecPaddingPKCS1MD5,
262 digest, CC_MD5_DIGEST_LENGTH, sig, &sigLen),
263 "don't sign md5 digest"); //FAIL
264 ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1MD5,
265 digest, CC_MD5_DIGEST_LENGTH, sig, sigLen),
266 "verify sig on md5 digest fails"); //FAIL
267 #endif
268
269 //CCDigest(kCCDigestSHA1, something, sizeof(something), digest);
270 sigLen = sizeof(sig);
271 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA1,
272 digest, CC_SHA1_DIGEST_LENGTH, sig, &sigLen),
273 "sign sha1 digest");
274 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA1,
275 digest, CC_SHA1_DIGEST_LENGTH, sig, sigLen),
276 "verify sig on sha1 digest");
277
278 #if TARGET_OS_IPHONE
279 /* The assumptions in these tests are just wrong on OS X */
280 uint8_t signature[keySizeInBytes], *ptr = signature;
281 size_t signature_len = sizeof(signature);
282 ok_status(SecKeyEncrypt(pubKey, kSecPaddingNone, sig, sigLen, signature, &signature_len), "inspect signature");
283 is(signature_len, keySizeInBytes - 1, "got signature"); // FAIL for 2056
284 while(*ptr && ((size_t)(ptr - signature) < signature_len)) ptr++;
285 is(signature + signature_len - ptr, 16 /* length(\0 || OID_SHA1) */ + CC_SHA1_DIGEST_LENGTH, "successful decode");
286 #endif
287
288 #if TARGET_OS_IPHONE
289 /* Those are not supported on OS X */
290 /* PKCS1 padding is 00 01 PAD * 8 or more 00 data.
291 data is SEQ { SEQ { OID NULL } BIT STRING 00 DIGEST }
292 So min data + pad overhead is 11 + 9 + oidlen
293 oidlen = 11 for the sha2 family of oids, so we have 29 bytes; or
294 232 bits of minimum overhead. */
295 const size_t pkcs1Overhead = 232;
296 if (keySizeInBits > 224 + pkcs1Overhead) {
297 //CC_SHA224(something, sizeof(something), digest);
298 sigLen = sizeof(sig);
299 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA224,
300 digest, CC_SHA224_DIGEST_LENGTH, sig, &sigLen),
301 "sign sha224 digest");
302 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA224,
303 digest, CC_SHA224_DIGEST_LENGTH, sig, sigLen),
304 "verify sig on sha224 digest");
305 }
306
307 if (keySizeInBits > 256 + pkcs1Overhead) {
308 //CC_SHA256(something, sizeof(something), digest);
309 sigLen = sizeof(sig);
310 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA256,
311 digest, CC_SHA256_DIGEST_LENGTH, sig, &sigLen),
312 "sign sha256 digest");
313 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA256,
314 digest, CC_SHA256_DIGEST_LENGTH, sig, sigLen),
315 "verify sig on sha256 digest");
316 }
317
318 if (keySizeInBits > 384 + pkcs1Overhead) {
319 //CC_SHA384(something, sizeof(something), digest);
320 sigLen = sizeof(sig);
321 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA384,
322 digest, CC_SHA384_DIGEST_LENGTH, sig, &sigLen),
323 "sign sha384 digest");
324 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA384,
325 digest, CC_SHA384_DIGEST_LENGTH, sig, sigLen),
326 "verify sig on sha384 digest");
327 }
328
329 if (keySizeInBits > 512 + pkcs1Overhead) {
330 //CC_SHA512(something, sizeof(something), digest);
331 sigLen = sizeof(sig);
332 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA512,
333 digest, CC_SHA512_DIGEST_LENGTH, sig, &sigLen),
334 "sign sha512 digest");
335 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA512,
336 digest, CC_SHA512_DIGEST_LENGTH, sig, sigLen),
337 "verify sig on sha512 digest");
338 }
339
340 test_encrypt_decrypt(pubKey, privKey, kSecPaddingNone, keySizeInBytes);
341 test_encrypt_decrypt(pubKey, privKey, kSecPaddingPKCS1, keySizeInBytes);
342 test_encrypt_decrypt(pubKey, privKey, kSecPaddingOAEP, keySizeInBytes);
343
344 testdigestandsign(privKey, pubKey);
345 #endif
346
347 const void *privkeys[] = {
348 kSecValueRef
349 };
350 const void *privvalues[] = {
351 privKey
352 };
353 CFDictionaryRef privitem = CFDictionaryCreate(NULL, privkeys, privvalues,
354 sizeof(privkeys) / sizeof(*privkeys), NULL, NULL);
355 #if TARGET_OS_IPHONE
356 /* OS X: keys are always added to the keychain when generated */
357 ok_status(SecItemAdd(privitem, NULL), "add private key"); //FAIL
358 #endif
359 ok_status(SecItemDelete(privitem), "delete private key");
360 CFReleaseNull(privitem);
361
362 const void *pubkeys[] = {
363 kSecValueRef
364 };
365 const void *pubvalues[] = {
366 pubKey
367 };
368 CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubkeys, pubvalues,
369 sizeof(pubkeys) / sizeof(*pubkeys), NULL, NULL);
370 #if TARGET_OS_IPHONE
371 /* OS X: keys are always added to the keychain when generated */
372 ok_status(SecItemAdd(pubitem, NULL), "add public key"); //FAIL
373 #endif
374 ok_status(SecItemDelete(pubitem), "delete public key");
375 CFReleaseNull(pubitem);
376
377 /* Cleanup. */
378 CFReleaseNull(pubKey);
379 CFReleaseNull(privKey);
380 }
381 }
382
383 #define kKeyGen2TestCount 11
384 static void testkeygen2(size_t keySizeInBits) {
385 SecKeyRef pubKey = NULL, privKey = NULL;
386 size_t keySizeInBytes = (keySizeInBits + 7) / 8;
387 CFNumberRef kzib;
388
389 CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault);
390 CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID);
391 CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
392 CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
393
394 CFReleaseNull(ourUUID);
395 CFReleaseNull(uuidString);
396
397 CFStringAppend(publicName, CFSTR("-Public-40"));
398 CFStringAppend(privateName, CFSTR("-Private-40"));
399 CFMutableDictionaryRef pubd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
400 CFMutableDictionaryRef privd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
401
402 CFDictionaryAddValue(pubd, kSecAttrLabel, publicName);
403 CFDictionaryAddValue(privd, kSecAttrLabel, privateName);
404
405 kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keySizeInBits);
406 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
407 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeRSA);
408 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
409 CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanTrue);
410 CFDictionaryAddValue(kgp, kSecPublicKeyAttrs, pubd);
411 CFDictionaryAddValue(kgp, kSecPrivateKeyAttrs, privd);
412
413 OSStatus status;
414 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
415 "Generate %ld bit (%ld byte) persistent RSA keypair",
416 keySizeInBits, keySizeInBytes);
417 CFRelease(kzib);
418 CFRelease(kgp);
419
420 SKIP: {
421 skip("keygen failed", 8, status == errSecSuccess);
422 ok(pubKey, "pubkey returned");
423 ok(privKey, "privKey returned");
424 is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
425 is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
426
427 SecKeyRef pubKey2, privKey2;
428 CFDictionaryAddValue(pubd, kSecClass, kSecClassKey);
429 CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue);
430 CFDictionaryAddValue(privd, kSecClass, kSecClassKey);
431 CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue);
432 CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue);
433 ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2),
434 "retrieve pub key by label");
435 ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2),
436 "retrieve priv key by label and kSecAttrCanSign");
437
438 /* Sign something. */
439 uint8_t something[50] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
440 uint8_t sig[keySizeInBytes];
441 size_t sigLen = keySizeInBytes;
442 ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1,
443 something, sizeof(something), sig, &sigLen), "sign something");
444 ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1,
445 something, sizeof(something), sig, sigLen), "verify sig on something");
446
447 #if TARGET_OS_IPHONE
448 /* SecKeyEncrypt does not return errSecParam on OS X in that case */
449 sigLen = keySizeInBytes;
450 is_status(SecKeyEncrypt(pubKey2, kSecPaddingPKCS1SHA1,
451 something, sizeof(something), sig, &sigLen), errSecParam,
452 "encrypt something with invalid padding");
453 #endif
454
455 /* Cleanup. */
456 CFReleaseNull(pubKey2);
457 CFReleaseNull(privKey2);
458
459 /* delete from keychain - note: do it before releasing publicName and privateName
460 because pubd and privd have no retain/release callbacks */
461 ok_status(SecItemDelete(pubd), "delete generated pub key");
462 ok_status(SecItemDelete(privd), "delete generated priv key");
463 }
464
465 /* Cleanup. */
466 CFReleaseNull(pubKey);
467 CFReleaseNull(privKey);
468
469 CFReleaseNull(publicName);
470 CFReleaseNull(privateName);
471
472 CFRelease(pubd);
473 CFRelease(privd);
474 }
475
476 /* Test basic add delete update copy matching stuff. */
477 #define kTestCount ((2 * kKeyGenTestCount) + kKeyGen2TestCount)
478 static void tests(void)
479 {
480 /* Comment out lines below for testing generating all common key sizes,
481 disabled now for speed reasons. */
482 //testkeygen(512);
483 //testkeygen(768);
484 testkeygen(1024);
485 testkeygen(2056); // Stranged sized for edge cases in padding.
486 //testkeygen(2048);
487 //testkeygen(4096);
488
489 testkeygen2(1024); // lots of FAIL!
490 }
491
492 int kc_40_seckey(int argc, char *const *argv)
493 {
494 plan_tests(kTestCount);
495
496 tests();
497
498 return 0;
499 }