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
45static 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
84static 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
115static 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
126static 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))
174static 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
344static 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)
436static 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
450int si_40_seckey(int argc, char *const *argv)
451{
452	plan_tests(kTestCount);
453
454	tests();
455
456	return 0;
457}
458