]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/Regressions/secitem/si-40-seckey.c
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / sec / Security / Regressions / secitem / si-40-seckey.c
1 /*
2 * Copyright (c) 2007-2009,2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
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>
38 #include <stdlib.h>
39 #include <unistd.h>
40
41 #include "Security_regressions.h"
42
43 #include "utilities/SecCFRelease.h"
44
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);
49 uint8_t sig[sigLen];
50
51 DERItem oid;
52 oid.length = algId->algorithm.Length;
53 oid.data = algId->algorithm.Data;
54
55 /* Get the oid in decimal for display purposes. */
56 CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid);
57 char oidBuf[40];
58 CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8);
59 CFRelease(oidStr);
60
61 SKIP: {
62 OSStatus status;
63
64 /* Time to sign. */
65 ok_status(status = SecKeyDigestAndSign(privKey, algId, dataToDigest, dataToDigestLen,
66 sig, &sigLen), "digest and sign %s with %ld bit RSA key", oidBuf, sigLen * 8);
67
68 skip("SecKeyDigestAndSign failed", 3, status == errSecSuccess);
69
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. */
74 sig[0] ^= 0xff;
75 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
76 sig, sigLen), errSSLCrypto, "digest and verify bad sig");
77 sig[0] ^= 0xff;
78 dataToDigest[0] ^= 0xff;
79 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
80 sig, sigLen), errSSLCrypto, "digest and verify bad digest");
81 }
82 }
83
84 static void testdigestandsign(SecKeyRef privKey, SecKeyRef pubKey) {
85 static const SecAsn1Oid *oids[] = {
86 &CSSMOID_SHA1WithRSA,
87 &CSSMOID_SHA224WithRSA,
88 &CSSMOID_SHA256WithRSA,
89 &CSSMOID_SHA384WithRSA,
90 &CSSMOID_SHA512WithRSA,
91 #if 0
92 &CSSMOID_SHA1WithRSA_OIW,
93 &CSSMOID_SHA1WithDSA, // BSAFE
94 &CSSMOID_SHA1WithDSA_CMS, // X509/CMS
95 &CSSMOID_SHA1WithDSA_JDK, // JDK 1.1
96 #endif
97 };
98
99
100 uint32_t ix;
101 SecAsn1AlgId algId = {};
102 for (ix = 0; ix < array_size(oids); ++ix) {
103 if (oids[ix]) {
104 algId.algorithm = *oids[ix];
105 } else {
106 algId.algorithm.Length = 0;
107 algId.algorithm.Data = NULL;
108 }
109
110 testdigestandsignalg(privKey, pubKey, &algId);
111 }
112 }
113
114 #if 0
115 static void dump_bytes(uint8_t* bytes, size_t amount)
116 {
117 while (amount > 0) {
118 printf("0x%02x ", *bytes);
119 ++bytes;
120 --amount;
121 }
122 }
123 #endif
124
125 #define kEncryptDecryptTestCount 5
126 static void test_encrypt_decrypt(SecKeyRef pubKey, SecKeyRef privKey, uint32_t padding, size_t keySizeInBytes)
127 {
128 SKIP: {
129 size_t max_len = keySizeInBytes;
130 switch (padding) {
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);
135 }
136
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);
144
145 // zero pad, no accidental second zero byte
146 if (padding == kSecPaddingNone) {
147 secret[0] = 0;
148 secret[1] = 128;
149 }
150
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,
155 secret, secret_len,
156 encrypted_secret, &encrypted_secret_len), "encrypt secret");
157
158 ok_status(SecKeyDecrypt(privKey, padding,
159 encrypted_secret, encrypted_secret_len,
160 decrypted_secret, &decrypted_secret_len), "decrypt secret");
161
162 // zero padding is removed on decode
163 if (padding == kSecPaddingNone) {
164 secret_len--;
165 secret_ptr++;
166 }
167
168 ok(decrypted_secret_len == secret_len, "correct length");
169 ok_status(memcmp(secret_ptr, decrypted_secret, secret_len), "verify secret");
170 }
171 }
172
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;
177 CFNumberRef kzib;
178
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);
184
185 OSStatus status;
186 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
187 "Generate %ld bit (%ld byte) RSA keypair", keySizeInBits,
188 keySizeInBytes);
189 CFRelease(kzib);
190 CFRelease(kgp);
191
192 SKIP: {
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");
198
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");
212
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,
223 };
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");
231
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");
240
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),
245 "sign sha1 digest");
246 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA1,
247 digest, CC_SHA1_DIGEST_LENGTH, sig, sigLen),
248 "verify sig on sha1 digest");
249
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");
256
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");
272 }
273
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");
283 }
284
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");
294 }
295
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");
305 }
306
307 test_encrypt_decrypt(pubKey, privKey, kSecPaddingNone, keySizeInBytes);
308 test_encrypt_decrypt(pubKey, privKey, kSecPaddingPKCS1, keySizeInBytes);
309 test_encrypt_decrypt(pubKey, privKey, kSecPaddingOAEP, keySizeInBytes);
310
311 testdigestandsign(privKey, pubKey);
312
313 const void *privkeys[] = {
314 kSecValueRef
315 };
316 const void *privvalues[] = {
317 privKey
318 };
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);
324
325 const void *pubkeys[] = {
326 kSecValueRef
327 };
328 const void *pubvalues[] = {
329 pubKey
330 };
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);
336
337 /* Cleanup. */
338 CFReleaseNull(pubKey);
339 CFReleaseNull(privKey);
340 }
341 }
342
343 #define kKeyGen2TestCount 12
344 static void testkeygen2(size_t keySizeInBits) {
345 SecKeyRef pubKey = NULL, privKey = NULL;
346 size_t keySizeInBytes = (keySizeInBits + 7) / 8;
347 CFNumberRef kzib;
348
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);
353
354 CFReleaseNull(ourUUID);
355 CFReleaseNull(uuidString);
356
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);
361
362 CFDictionaryAddValue(pubd, kSecAttrLabel, publicName);
363 CFDictionaryAddValue(privd, kSecAttrLabel, privateName);
364
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);
373
374 OSStatus status;
375 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
376 "Generate %ld bit (%ld byte) persistent RSA keypair",
377 keySizeInBits, keySizeInBytes);
378 CFRelease(kzib);
379 CFRelease(kgp);
380
381 SKIP: {
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");
387
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");
398
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");
407
408 sigLen = keySizeInBytes;
409 is_status(SecKeyEncrypt(pubKey2, kSecPaddingPKCS1SHA1,
410 something, sizeof(something), sig, &sigLen), errSecParam,
411 "encrypt something with invalid padding");
412
413 /* Cleanup. */
414 CFReleaseNull(pubKey2);
415 CFReleaseNull(privKey2);
416
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");
421 }
422
423 /* Cleanup. */
424 CFReleaseNull(pubKey);
425 CFReleaseNull(privKey);
426
427 CFReleaseNull(publicName);
428 CFReleaseNull(privateName);
429
430 CFRelease(pubd);
431 CFRelease(privd);
432 }
433
434 /* Test basic add delete update copy matching stuff. */
435 #define kTestCount ((3 * kKeyGenTestCount) + kKeyGen2TestCount)
436 static void tests(void)
437 {
438 /* Comment out lines below for testing generating all common key sizes,
439 disabled now for speed reasons. */
440 //testkeygen(512);
441 testkeygen(768);
442 testkeygen(1024);
443 testkeygen(2056); // Stranged sized for edge cases in padding.
444 //testkeygen(2048);
445 //testkeygen(4096);
446
447 testkeygen2(768);
448 }
449
450 int si_40_seckey(int argc, char *const *argv)
451 {
452 plan_tests(kTestCount);
453
454 tests();
455
456 return 0;
457 }