1/*
2 * Copyright (c) 2011,2013-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/*
26 *  si-40-seckey.c
27 *  Security
28 *
29 *  Copyright (c) 2007-2009,2013-2014 Apple Inc. All Rights Reserved.
30 *
31 */
32#include <TargetConditionals.h>
33#include <CoreFoundation/CoreFoundation.h>
34#include <Security/Security.h>
35#include <Security/SecKeyPriv.h>
36
37#if 0
38#include <Security/SecCertificate.h>
39#include <Security/SecCertificateInternal.h>
40#include <Security/SecKey.h>
41#include <Security/SecKeyPriv.h>
42#include <Security/SecItem.h>
43#include <Security/SecAsn1Types.h>
44#include <Security/oidsalg.h>
45#include <Security/SecureTransport.h>
46#include <Security/SecRandom.h>
47#include <CommonCrypto/CommonDigest.h>
48#include <libDER/libDER.h>
49#include <stdlib.h>
50#include <unistd.h>
51#endif
52
53
54#include "keychain_regressions.h"
55#include "utilities/SecCFRelease.h"
56
57
58#if TARGET_OS_IPHONE
59static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecAsn1AlgId *algId) {
60    uint8_t dataToDigest[256];
61    size_t dataToDigestLen = sizeof(dataToDigest);
62    size_t sigLen = SecKeyGetSize(privKey, kSecKeySignatureSize);
63    uint8_t sig[sigLen];
64
65    DERItem oid;
66    oid.length = algId->algorithm.Length;
67    oid.data = algId->algorithm.Data;
68
69    /* Get the oid in decimal for display purposes. */
70    CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid);
71	char oidBuf[40];
72    CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8);
73    CFRelease(oidStr);
74
75SKIP: {
76    OSStatus status;
77
78    /* Time to sign. */
79    ok_status(status = SecKeyDigestAndSign(privKey, algId, dataToDigest, dataToDigestLen,
80                                           sig, &sigLen),
81              "digest and sign %s with %ld bit RSA key", oidBuf, sigLen * 8);
82
83    skip("SecKeyDigestAndSign failed", 3, status == errSecSuccess);
84
85    /* Verify the signature we just made. */
86    ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
87                                    sig, sigLen), "digest and verify");
88    /* Invalidate the signature. */
89    sig[0] ^= 0xff;
90    is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
91                                    sig, sigLen), errSSLCrypto, "digest and verify bad sig");
92    sig[0] ^= 0xff;
93    dataToDigest[0] ^= 0xff;
94    is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
95                                    sig, sigLen), errSSLCrypto, "digest and verify bad digest");
96}
97}
98
99static void testdigestandsign(SecKeyRef privKey, SecKeyRef pubKey) {
100    static const SecAsn1Oid *oids[] = {
101        &CSSMOID_ECDSA_WithSHA1,
102#if 0
103        &CSSMOID_ECDSA_WithSHA224,
104        &CSSMOID_ECDSA_WithSHA256,
105        &CSSMOID_ECDSA_WithSHA384,
106        &CSSMOID_ECDSA_WithSHA512,
107#endif
108    };
109
110    uint32_t ix;
111    SecAsn1AlgId algId = {};
112    for (ix = 0; ix < sizeof(oids) / sizeof(*oids); ++ix) {
113        if (oids[ix]) {
114            algId.algorithm = *oids[ix];
115        } else {
116            algId.algorithm.Length = 0;
117            algId.algorithm.Data = NULL;
118        }
119
120        testdigestandsignalg(privKey, pubKey, &algId);
121    }
122}
123#endif
124
125
126#if !TARGET_OS_IPHONE
127/* This is part of Security.framework on iOS */
128
129enum {
130    // kSecKeyKeySizeInBits        = 0, // already exists on osx
131    kSecKeySignatureSize        = 101,
132    kSecKeyEncryptedDataSize    = 102,
133    // More might belong here, but we aren't settled on how
134    // to take into account padding and/or digest types.
135};
136
137static
138size_t SecKeyGetSize(SecKeyRef key, int whichSize)
139{
140    /* SecKeyGetBlockSize return the signature size on OS X -- smh */
141    size_t result = SecKeyGetBlockSize(key);
142
143    result = (result - 2)/2 - 3;
144
145    /* in this test, this is always an ECDSA key */
146    switch (whichSize) {
147        case kSecKeyEncryptedDataSize:
148            result = 0;
149            break;
150        case kSecKeySignatureSize:
151            result = (result >= 66 ? 9 : 8) + 2 * result;
152            break;
153        case kSecKeyKeySizeInBits:
154            if (result >= 66)
155                return 521;
156    }
157
158    if (whichSize == kSecKeyKeySizeInBits)
159        result *= 8;
160
161    return result;
162
163}
164#endif
165
166
167static void testkeygen(size_t keySizeInBits) {
168	SecKeyRef pubKey = NULL, privKey = NULL;
169	size_t keySizeInBytes = (keySizeInBits + 7) / 8;
170	CFNumberRef kzib;
171
172	kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keySizeInBits);
173	CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
174	CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC);
175	CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
176
177	OSStatus status;
178	ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
179              "Generate %ld bit (%ld byte) EC keypair", keySizeInBits,
180              keySizeInBytes);
181	CFRelease(kzib);
182	CFRelease(kgp);
183
184SKIP: {
185    skip("keygen failed", 8, status == errSecSuccess);
186    ok(pubKey, "pubkey returned");
187    ok(privKey, "privKey returned");
188    is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
189    is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
190
191    /* Sign something. */
192    uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
193    uint8_t sig[8+2*keySizeInBytes];
194    size_t sigLen = sizeof(sig);
195    ok_status(SecKeyRawSign(privKey, kSecPaddingNone,
196                            something, sizeof(something), sig, &sigLen), "sign something");
197    ok_status(SecKeyRawVerify(pubKey, kSecPaddingNone,
198                              something, sizeof(something), sig, sigLen), "verify sig on something");
199
200#if TARGET_OS_IPHONE
201    testdigestandsign(privKey, pubKey);
202#endif
203
204    const void *privkeys[] = {
205        kSecValueRef
206    };
207    const void *privvalues[] = {
208        privKey
209    };
210    CFDictionaryRef privitem = CFDictionaryCreate(NULL, privkeys, privvalues,
211                                                  sizeof(privkeys) / sizeof(*privkeys), NULL, NULL);
212#if TARGET_OS_IPHONE
213    ok_status(SecItemAdd(privitem, NULL), "add private key");
214#endif
215    ok_status(SecItemDelete(privitem), "delete private key");
216    CFReleaseNull(privitem);
217
218    const void *pubkeys[] = {
219        kSecValueRef
220    };
221    const void *pubvalues[] = {
222        pubKey
223    };
224    CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubkeys, pubvalues,
225                                                 sizeof(pubkeys) / sizeof(*pubkeys), NULL, NULL);
226#if TARGET_OS_IPHONE
227    ok_status(SecItemAdd(pubitem, NULL), "add public key");
228#endif
229    ok_status(SecItemDelete(pubitem), "delete public key");
230    CFReleaseNull(pubitem);
231
232    /* Cleanup. */
233    CFReleaseNull(pubKey);
234    CFReleaseNull(privKey);
235}
236}
237
238
239static void testkeygen2(size_t keySizeInBits) {
240	SecKeyRef pubKey = NULL, privKey = NULL;
241	size_t keySizeInBytes = (keySizeInBits + 7) / 8;
242	CFNumberRef kzib;
243
244    CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault);
245    CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID);
246    CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
247    CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
248
249    CFReleaseNull(ourUUID);
250    CFReleaseNull(uuidString);
251
252    CFStringAppend(publicName, CFSTR("-Public-41"));
253    CFStringAppend(privateName, CFSTR("-Private-41"));
254
255	CFMutableDictionaryRef pubd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
256	CFMutableDictionaryRef privd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
257	CFDictionaryAddValue(pubd, kSecAttrLabel, publicName);
258	CFDictionaryAddValue(privd, kSecAttrLabel, privateName);
259
260	kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keySizeInBits);
261	CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
262	CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC);
263	CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
264	CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanTrue);
265	CFDictionaryAddValue(kgp, kSecPublicKeyAttrs, pubd);
266	CFDictionaryAddValue(kgp, kSecPrivateKeyAttrs, privd);
267
268	OSStatus status;
269	ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
270              "Generate %ld bit (%ld byte) persistent RSA keypair",
271              keySizeInBits, keySizeInBytes);
272	CFRelease(kzib);
273	CFRelease(kgp);
274
275SKIP: {
276    skip("keygen failed", 8, status == errSecSuccess);
277    ok(pubKey, "pubkey returned");
278    ok(privKey, "privKey returned");
279    is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
280    is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
281
282    SecKeyRef pubKey2, privKey2;
283    CFDictionaryAddValue(pubd, kSecClass, kSecClassKey);
284    CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue);
285    CFDictionaryAddValue(privd, kSecClass, kSecClassKey);
286    CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue);
287    CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue);
288    ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2),
289              "retrieve pub key by label");
290    ok(pubKey2, "got valid object");
291    ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2),
292              "retrieve priv key by label and kSecAttrCanSign");
293    ok(privKey2, "got valid object");
294
295    /* Sign something. */
296    uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
297    size_t sigLen = SecKeyGetSize(privKey2, kSecKeySignatureSize);
298    uint8_t sig[sigLen];
299    ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1,
300                            something, sizeof(something), sig, &sigLen), "sign something");
301    ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1,
302                              something, sizeof(something), sig, sigLen), "verify sig on something");
303
304    /* Cleanup. */
305    CFReleaseNull(pubKey2);
306    CFReleaseNull(privKey2);
307}
308
309    /* delete from keychain - note: do it before releasing publicName and privateName
310       because pubd and privd have no retain/release callbacks */
311    ok_status(SecItemDelete(pubd), "delete generated pub key");
312    ok_status(SecItemDelete(privd), "delete generated priv key");
313
314	/* Cleanup. */
315	CFReleaseNull(pubKey);
316	CFReleaseNull(privKey);
317
318    CFReleaseNull(publicName);
319    CFReleaseNull(privateName);
320
321	CFRelease(pubd);
322	CFRelease(privd);
323}
324
325
326/* Test basic add delete update copy matching stuff. */
327static void tests(void)
328{
329	testkeygen(192);
330#if TARGET_OS_IPHONE
331	testkeygen(224);
332#endif
333	testkeygen(256);
334	testkeygen(384);
335	testkeygen(521);
336
337    testkeygen2(192);
338#if TARGET_OS_IPHONE
339    testkeygen2(224);
340#endif
341	testkeygen2(256);
342	testkeygen2(384);
343	testkeygen2(521);
344
345}
346
347int kc_41_sececkey(int argc, char *const *argv)
348{
349#if TARGET_OS_IPHONE
350	plan_tests(140);
351#else
352	plan_tests(88);
353#endif
354
355	tests();
356
357	return 0;
358}
359