1//
2//  si-41-sececkey.c
3//  regressions
4//
5//  Created by Mitch Adler on 5/20/11.
6//  Copyright 2011 Apple Inc. All rights reserved.
7//
8
9/*
10 *  si-40-seckey.c
11 *  Security
12 *
13 *  Created by Michael Brouwer on 1/29/07.
14 *  Copyright (c) 2007-2009 Apple Inc. All Rights Reserved.
15 *
16 */
17
18#include <CoreFoundation/CoreFoundation.h>
19#include <Security/SecCertificate.h>
20#include <Security/SecCertificateInternal.h>
21#include <Security/SecKey.h>
22#include <Security/SecKeyPriv.h>
23#include <Security/SecItem.h>
24#include <Security/SecAsn1Types.h>
25#include <Security/oidsalg.h>
26#include <Security/SecureTransport.h>
27#include <Security/SecRandom.h>
28#include <utilities/array_size.h>
29#include <CommonCrypto/CommonDigest.h>
30#include <libDER/libDER.h>
31#include <stdlib.h>
32#include <unistd.h>
33
34#include "Security_regressions.h"
35
36#define CFReleaseNull(CF) { CFTypeRef _cf = (CF); if (_cf) {  (CF) = NULL; CFRelease(_cf); } }
37
38
39static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecAsn1AlgId *algId) {
40    uint8_t dataToDigest[256] = {0,};
41    size_t dataToDigestLen = sizeof(dataToDigest);
42    size_t sigLen = SecKeyGetSize(privKey, kSecKeySignatureSize);
43    uint8_t sig[sigLen];
44
45    DERItem oid;
46    oid.length = algId->algorithm.Length;
47    oid.data = algId->algorithm.Data;
48
49    /* Get the oid in decimal for display purposes. */
50    CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid);
51	char oidBuf[40];
52    CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8);
53    CFRelease(oidStr);
54
55SKIP: {
56    OSStatus status;
57
58    /* Time to sign. */
59    ok_status(status = SecKeyDigestAndSign(privKey, algId, dataToDigest, dataToDigestLen,
60                                           sig, &sigLen),
61              "digest and sign %s with %ld bit RSA key", oidBuf, sigLen * 8);
62
63    skip("SecKeyDigestAndSign failed", 3, status == errSecSuccess);
64
65    /* Verify the signature we just made. */
66    ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
67                                    sig, sigLen), "digest and verify");
68    /* Invalidate the signature. */
69    sig[0] ^= 0xff;
70    is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
71                                    sig, sigLen), errSSLCrypto, "digest and verify bad sig");
72    sig[0] ^= 0xff;
73    dataToDigest[0] ^= 0xff;
74    is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
75                                    sig, sigLen), errSSLCrypto, "digest and verify bad digest");
76}
77}
78
79static void testdigestandsign(SecKeyRef privKey, SecKeyRef pubKey) {
80    static const SecAsn1Oid *oids[] = {
81        &CSSMOID_ECDSA_WithSHA1,
82#if 0
83        &CSSMOID_ECDSA_WithSHA224,
84        &CSSMOID_ECDSA_WithSHA256,
85        &CSSMOID_ECDSA_WithSHA384,
86        &CSSMOID_ECDSA_WithSHA512,
87#endif
88    };
89
90    uint32_t ix;
91    SecAsn1AlgId algId = {};
92    for (ix = 0; ix < array_size(oids); ++ix) {
93        if (oids[ix]) {
94            algId.algorithm = *oids[ix];
95        } else {
96            algId.algorithm.Length = 0;
97            algId.algorithm.Data = NULL;
98        }
99
100        testdigestandsignalg(privKey, pubKey, &algId);
101    }
102}
103
104static void testkeygen(size_t keySizeInBits) {
105	SecKeyRef pubKey = NULL, privKey = NULL;
106	size_t keySizeInBytes = (keySizeInBits + 7) / 8;
107	CFNumberRef kzib;
108    int32_t keysz32 = (int32_t)keySizeInBits;
109
110	kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
111	CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
112	CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC);
113	CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
114
115	OSStatus status;
116	ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
117              "Generate %ld bit (%ld byte) EC keypair", keySizeInBits,
118              keySizeInBytes);
119	CFRelease(kzib);
120	CFRelease(kgp);
121
122SKIP: {
123    skip("keygen failed", 8, status == errSecSuccess);
124    ok(pubKey, "pubkey returned");
125    ok(privKey, "privKey returned");
126    is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
127    is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
128
129    /* Sign something. */
130    uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
131    uint8_t sig[8+2*keySizeInBytes];
132    size_t sigLen = sizeof(sig);
133    ok_status(SecKeyRawSign(privKey, kSecPaddingNone,
134                            something, sizeof(something), sig, &sigLen), "sign something");
135    ok_status(SecKeyRawVerify(pubKey, kSecPaddingNone,
136                              something, sizeof(something), sig, sigLen), "verify sig on something");
137
138    testdigestandsign(privKey, pubKey);
139
140    const void *privkeys[] = {
141        kSecValueRef
142    };
143    const void *privvalues[] = {
144        privKey
145    };
146    CFDictionaryRef privitem = CFDictionaryCreate(NULL, privkeys, privvalues,
147                                                  array_size(privkeys), NULL, NULL);
148    ok_status(SecItemAdd(privitem, NULL), "add private key");
149    ok_status(SecItemDelete(privitem), "delete public key");
150    CFReleaseNull(privitem);
151
152    const void *pubkeys[] = {
153        kSecValueRef
154    };
155    const void *pubvalues[] = {
156        pubKey
157    };
158    CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubkeys, pubvalues,
159                                                 array_size(pubkeys), NULL, NULL);
160    ok_status(SecItemAdd(pubitem, NULL), "add public key");
161    ok_status(SecItemDelete(pubitem), "delete public key");
162    CFReleaseNull(pubitem);
163
164    /* Cleanup. */
165    CFReleaseNull(pubKey);
166    CFReleaseNull(privKey);
167}
168}
169
170
171static void testkeygen2(size_t keySizeInBits) {
172	SecKeyRef pubKey = NULL, privKey = NULL;
173	size_t keySizeInBytes = (keySizeInBits + 7) / 8;
174	CFNumberRef kzib;
175    int32_t keysz32 = (int32_t)keySizeInBits;
176
177    CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault);
178    CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID);
179    CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
180    CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
181
182    CFReleaseNull(ourUUID);
183    CFReleaseNull(uuidString);
184
185    CFStringAppend(publicName, CFSTR("-Public-41"));
186    CFStringAppend(privateName, CFSTR("-Private-41"));
187
188	CFMutableDictionaryRef pubd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
189	CFMutableDictionaryRef privd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
190	CFDictionaryAddValue(pubd, kSecAttrLabel, publicName);
191	CFDictionaryAddValue(privd, kSecAttrLabel, privateName);
192
193	kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
194	CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
195	CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC);
196	CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
197	CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanTrue);
198	CFDictionaryAddValue(kgp, kSecPublicKeyAttrs, pubd);
199	CFDictionaryAddValue(kgp, kSecPrivateKeyAttrs, privd);
200
201	OSStatus status;
202	ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
203              "Generate %ld bit (%ld byte) persistent RSA keypair",
204              keySizeInBits, keySizeInBytes);
205	CFRelease(kzib);
206	CFRelease(kgp);
207
208SKIP: {
209    skip("keygen failed", 8, status == errSecSuccess);
210    ok(pubKey, "pubkey returned");
211    ok(privKey, "privKey returned");
212    is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
213    is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
214
215    SecKeyRef pubKey2, privKey2;
216    CFDictionaryAddValue(pubd, kSecClass, kSecClassKey);
217    CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue);
218    CFDictionaryAddValue(privd, kSecClass, kSecClassKey);
219    CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue);
220    CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue);
221    ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2),
222              "retrieve pub key by label");
223    ok(pubKey2, "got valid object");
224    ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2),
225              "retrieve priv key by label and kSecAttrCanSign");
226    ok(privKey2, "got valid object");
227
228    /* Sign something. */
229    uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
230    size_t sigLen = SecKeyGetSize(privKey2, kSecKeySignatureSize);
231    uint8_t sig[sigLen];
232    ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1,
233                            something, sizeof(something), sig, &sigLen), "sign something");
234    ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1,
235                              something, sizeof(something), sig, sigLen), "verify sig on something");
236
237    /* Cleanup. */
238    CFReleaseNull(pubKey2);
239    CFReleaseNull(privKey2);
240}
241
242    /* delete from keychain - note: do it before releasing publicName and privateName
243       because pubd and privd have no retain/release callbacks */
244    ok_status(SecItemDelete(pubd), "delete generated pub key");
245    ok_status(SecItemDelete(privd), "delete generated priv key");
246
247	/* Cleanup. */
248	CFReleaseNull(pubKey);
249	CFReleaseNull(privKey);
250
251    CFReleaseNull(publicName);
252    CFReleaseNull(privateName);
253
254	CFRelease(pubd);
255	CFRelease(privd);
256}
257
258
259/* Test basic add delete update copy matching stuff. */
260static void tests(void)
261{
262	testkeygen(192);
263	testkeygen(224);
264	testkeygen(256);
265	testkeygen(384);
266	testkeygen(521);
267
268    testkeygen2(192);
269    testkeygen2(224);
270	testkeygen2(256);
271	testkeygen2(384);
272	testkeygen2(521);
273
274}
275
276int si_41_sececkey(int argc, char *const *argv)
277{
278	plan_tests(140);
279
280	tests();
281
282	return 0;
283}
284