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
34static 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
73static 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
105static 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
120static 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
173enum {
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
181static
182size_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))
195static 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
384static 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)
478static 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
492int kc_40_seckey(int argc, char *const *argv)
493{
494	plan_tests(kTestCount);
495
496	tests();
497
498	return 0;
499}
500