]> git.saurik.com Git - apple/security.git/blame - sec/Security/Regressions/secitem/si-40-seckey.c
Security-55471.14.18.tar.gz
[apple/security.git] / sec / Security / Regressions / secitem / si-40-seckey.c
CommitLineData
427c49bc
A
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 <CoreFoundation/CoreFoundation.h>
11#include <Security/SecCertificate.h>
12#include <Security/SecCertificateInternal.h>
13#include <Security/SecKey.h>
14#include <Security/SecKeyPriv.h>
15#include <Security/SecItem.h>
16#include <Security/SecAsn1Types.h>
17#include <Security/oidsalg.h>
18#include <Security/SecureTransport.h>
19#include <Security/SecRandom.h>
20#include <utilities/array_size.h>
21#include <CommonCrypto/CommonDigest.h>
22#include <libDER/libDER.h>
23#include <stdlib.h>
24#include <unistd.h>
25
26#include "Security_regressions.h"
27
28#include "utilities/SecCFRelease.h"
29
30static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecAsn1AlgId *algId) {
31 uint8_t dataToDigest[256] = {0,};
32 size_t dataToDigestLen = sizeof(dataToDigest);
33 size_t sigLen = SecKeyGetSize(privKey, kSecKeySignatureSize);
34 uint8_t sig[sigLen];
35
36 DERItem oid;
37 oid.length = algId->algorithm.Length;
38 oid.data = algId->algorithm.Data;
39
40 /* Get the oid in decimal for display purposes. */
41 CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid);
42 char oidBuf[40];
43 CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8);
44 CFRelease(oidStr);
45
46 SKIP: {
47 OSStatus status;
48
49 /* Time to sign. */
50 ok_status(status = SecKeyDigestAndSign(privKey, algId, dataToDigest, dataToDigestLen,
51 sig, &sigLen), "digest and sign %s with %ld bit RSA key", oidBuf, sigLen * 8);
52
53 skip("SecKeyDigestAndSign failed", 3, status == errSecSuccess);
54
55 /* Verify the signature we just made. */
56 ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
57 sig, sigLen), "digest and verify");
58 /* Invalidate the signature. */
59 sig[0] ^= 0xff;
60 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
61 sig, sigLen), errSSLCrypto, "digest and verify bad sig");
62 sig[0] ^= 0xff;
63 dataToDigest[0] ^= 0xff;
64 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
65 sig, sigLen), errSSLCrypto, "digest and verify bad digest");
66 }
67}
68
69static void testdigestandsign(SecKeyRef privKey, SecKeyRef pubKey) {
70 static const SecAsn1Oid *oids[] = {
71 &CSSMOID_SHA1WithRSA,
72 &CSSMOID_SHA224WithRSA,
73 &CSSMOID_SHA256WithRSA,
74 &CSSMOID_SHA384WithRSA,
75 &CSSMOID_SHA512WithRSA,
76#if 0
77 &CSSMOID_SHA1WithRSA_OIW,
78 &CSSMOID_SHA1WithDSA, // BSAFE
79 &CSSMOID_SHA1WithDSA_CMS, // X509/CMS
80 &CSSMOID_SHA1WithDSA_JDK, // JDK 1.1
81#endif
82 };
83
84
85 uint32_t ix;
86 SecAsn1AlgId algId = {};
87 for (ix = 0; ix < array_size(oids); ++ix) {
88 if (oids[ix]) {
89 algId.algorithm = *oids[ix];
90 } else {
91 algId.algorithm.Length = 0;
92 algId.algorithm.Data = NULL;
93 }
94
95 testdigestandsignalg(privKey, pubKey, &algId);
96 }
97}
98
99#if 0
100static void dump_bytes(uint8_t* bytes, size_t amount)
101{
102 while (amount > 0) {
103 printf("0x%02x ", *bytes);
104 ++bytes;
105 --amount;
106 }
107}
108#endif
109
110#define kEncryptDecryptTestCount 5
111static void test_encrypt_decrypt(SecKeyRef pubKey, SecKeyRef privKey, uint32_t padding, size_t keySizeInBytes)
112{
113 SKIP: {
114 size_t max_len = keySizeInBytes;
115 switch (padding) {
116 case kSecPaddingNone: max_len = keySizeInBytes; break;
117 case kSecPaddingOAEP: max_len = keySizeInBytes - 2 - 2 * CC_SHA1_DIGEST_LENGTH; break;
118 case kSecPaddingPKCS1: max_len = keySizeInBytes - 11; break;
119 default: skip("what is the max_len for this padding?", 5, false);
120 }
121
122 uint8_t secret[max_len + 1], encrypted_secret[keySizeInBytes], decrypted_secret[keySizeInBytes];
123 uint8_t *secret_ptr = secret;
124 size_t secret_len = max_len;
125 size_t encrypted_secret_len = sizeof(encrypted_secret);
126 size_t decrypted_secret_len = sizeof(decrypted_secret);
127 memset(decrypted_secret, 0xff, decrypted_secret_len);
128 SecRandomCopyBytes(kSecRandomDefault, sizeof(secret), secret);
129
130 // zero pad, no accidental second zero byte
131 if (padding == kSecPaddingNone) {
132 secret[0] = 0;
133 secret[1] = 128;
134 }
135
136 is_status(SecKeyEncrypt(pubKey, padding,
137 secret, sizeof(secret),
138 encrypted_secret, &encrypted_secret_len), errSecParam, "encrypt secret (overflow)");
139 ok_status(SecKeyEncrypt(pubKey, padding,
140 secret, secret_len,
141 encrypted_secret, &encrypted_secret_len), "encrypt secret");
142
143 ok_status(SecKeyDecrypt(privKey, padding,
144 encrypted_secret, encrypted_secret_len,
145 decrypted_secret, &decrypted_secret_len), "decrypt secret");
146
147 // zero padding is removed on decode
148 if (padding == kSecPaddingNone) {
149 secret_len--;
150 secret_ptr++;
151 }
152
153 ok(decrypted_secret_len == secret_len, "correct length");
154 ok_status(memcmp(secret_ptr, decrypted_secret, secret_len), "verify secret");
155 }
156}
157
158#define kKeyGenTestCount (49 + (3*kEncryptDecryptTestCount))
159static void testkeygen(size_t keySizeInBits) {
160 SecKeyRef pubKey = NULL, privKey = NULL;
161 size_t keySizeInBytes = (keySizeInBits + 7) / 8;
162 CFNumberRef kzib;
163
164 kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keySizeInBits);
165 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
166 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeRSA);
167 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
168
169 OSStatus status;
170 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
171 "Generate %ld bit (%ld byte) RSA keypair", keySizeInBits,
172 keySizeInBytes);
173 CFRelease(kzib);
174 CFRelease(kgp);
175
176 SKIP: {
177 skip("keygen failed", 8, status == errSecSuccess);
178 ok(pubKey, "pubkey returned");
179 ok(privKey, "privKey returned");
180 is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
181 is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
182
183 /* Sign something. */
184 uint8_t something[keySizeInBytes];
185 size_t something_len = keySizeInBytes - 11;
186 SecRandomCopyBytes(kSecRandomDefault, sizeof(something), something);
187 uint8_t sig[keySizeInBytes];
188 size_t sigLen = sizeof(sig);
189 is_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
190 something, something_len + 1, sig, &sigLen),
191 errSecParam, "sign overflow");
192 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
193 something, something_len, sig, &sigLen), "sign something");
194 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1,
195 something, something_len, sig, sigLen), "verify sig on something");
196
197 // Torture test ASN.1 encoder by setting high bit to 1.
198 uint8_t digest[CC_SHA512_DIGEST_LENGTH] = {
199 0x80, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
200 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
201 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
202 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
203 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
204 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
205 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
206 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
207 };
208 //CC_MD2(something, sizeof(something), digest);
209 ok_status(!SecKeyRawSign(privKey, kSecPaddingPKCS1MD2,
210 digest, CC_MD2_DIGEST_LENGTH, sig, &sigLen),
211 "don't sign md2 digest");
212 ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1MD2,
213 digest, CC_MD2_DIGEST_LENGTH, sig, sigLen),
214 "verify sig on md2 digest fails");
215
216 //CC_MD5(something, sizeof(something), digest);
217 sigLen = sizeof(sig);
218 ok_status(!SecKeyRawSign(privKey, kSecPaddingPKCS1MD5,
219 digest, CC_MD5_DIGEST_LENGTH, sig, &sigLen),
220 "don't sign md5 digest");
221 ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1MD5,
222 digest, CC_MD5_DIGEST_LENGTH, sig, sigLen),
223 "verify sig on md5 digest fails");
224
225 //CCDigest(kCCDigestSHA1, something, sizeof(something), digest);
226 sigLen = sizeof(sig);
227 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA1,
228 digest, CC_SHA1_DIGEST_LENGTH, sig, &sigLen),
229 "sign sha1 digest");
230 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA1,
231 digest, CC_SHA1_DIGEST_LENGTH, sig, sigLen),
232 "verify sig on sha1 digest");
233
234 uint8_t signature[keySizeInBytes], *ptr = signature;
235 size_t signature_len = sizeof(signature);
236 ok_status(SecKeyDecrypt(pubKey, kSecPaddingNone, sig, sigLen, signature, &signature_len), "inspect signature");
237 is(signature_len, keySizeInBytes - 1, "got signature");
238 while(*ptr && ((size_t)(ptr - signature) < signature_len)) ptr++;
239 is(signature + signature_len - ptr, 16 /* length(\0 || OID_SHA1) */ + CC_SHA1_DIGEST_LENGTH, "successful decode");
240
241 /* PKCS1 padding is 00 01 PAD * 8 or more 00 data.
242 data is SEQ { SEQ { OID NULL } BIT STRING 00 DIGEST }
243 So min data + pad overhead is 11 + 9 + oidlen
244 oidlen = 11 for the sha2 family of oids, so we have 29 bytes; or
245 232 bits of minimum overhead. */
246 const size_t pkcs1Overhead = 232;
247 if (keySizeInBits > 224 + pkcs1Overhead) {
248 //CC_SHA224(something, sizeof(something), digest);
249 sigLen = sizeof(sig);
250 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA224,
251 digest, CC_SHA224_DIGEST_LENGTH, sig, &sigLen),
252 "sign sha224 digest");
253 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA224,
254 digest, CC_SHA224_DIGEST_LENGTH, sig, sigLen),
255 "verify sig on sha224 digest");
256 }
257
258 if (keySizeInBits > 256 + pkcs1Overhead) {
259 //CC_SHA256(something, sizeof(something), digest);
260 sigLen = sizeof(sig);
261 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA256,
262 digest, CC_SHA256_DIGEST_LENGTH, sig, &sigLen),
263 "sign sha256 digest");
264 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA256,
265 digest, CC_SHA256_DIGEST_LENGTH, sig, sigLen),
266 "verify sig on sha256 digest");
267 }
268
269 if (keySizeInBits > 384 + pkcs1Overhead) {
270 //CC_SHA384(something, sizeof(something), digest);
271 sigLen = sizeof(sig);
272 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA384,
273 digest, CC_SHA384_DIGEST_LENGTH, sig, &sigLen),
274 "sign sha384 digest");
275 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA384,
276 digest, CC_SHA384_DIGEST_LENGTH, sig, sigLen),
277 "verify sig on sha384 digest");
278 }
279
280 if (keySizeInBits > 512 + pkcs1Overhead) {
281 //CC_SHA512(something, sizeof(something), digest);
282 sigLen = sizeof(sig);
283 ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA512,
284 digest, CC_SHA512_DIGEST_LENGTH, sig, &sigLen),
285 "sign sha512 digest");
286 ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA512,
287 digest, CC_SHA512_DIGEST_LENGTH, sig, sigLen),
288 "verify sig on sha512 digest");
289 }
290
291 test_encrypt_decrypt(pubKey, privKey, kSecPaddingNone, keySizeInBytes);
292 test_encrypt_decrypt(pubKey, privKey, kSecPaddingPKCS1, keySizeInBytes);
293 test_encrypt_decrypt(pubKey, privKey, kSecPaddingOAEP, keySizeInBytes);
294
295 testdigestandsign(privKey, pubKey);
296
297 const void *privkeys[] = {
298 kSecValueRef
299 };
300 const void *privvalues[] = {
301 privKey
302 };
303 CFDictionaryRef privitem = CFDictionaryCreate(NULL, privkeys, privvalues,
304 array_size(privkeys), NULL, NULL);
305 ok_status(SecItemAdd(privitem, NULL), "add private key");
306 ok_status(SecItemDelete(privitem), "delete private key");
307 CFReleaseNull(privitem);
308
309 const void *pubkeys[] = {
310 kSecValueRef
311 };
312 const void *pubvalues[] = {
313 pubKey
314 };
315 CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubkeys, pubvalues,
316 array_size(pubkeys), NULL, NULL);
317 ok_status(SecItemAdd(pubitem, NULL), "add public key");
318 ok_status(SecItemDelete(pubitem), "delete public key");
319 CFReleaseNull(pubitem);
320
321 /* Cleanup. */
322 CFReleaseNull(pubKey);
323 CFReleaseNull(privKey);
324 }
325}
326
327#define kKeyGen2TestCount 12
328static void testkeygen2(size_t keySizeInBits) {
329 SecKeyRef pubKey = NULL, privKey = NULL;
330 size_t keySizeInBytes = (keySizeInBits + 7) / 8;
331 CFNumberRef kzib;
332
333 CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault);
334 CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID);
335 CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
336 CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
337
338 CFReleaseNull(ourUUID);
339 CFReleaseNull(uuidString);
340
341 CFStringAppend(publicName, CFSTR("-Public-40"));
342 CFStringAppend(privateName, CFSTR("-Private-40"));
343 CFMutableDictionaryRef pubd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
344 CFMutableDictionaryRef privd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
345
346 CFDictionaryAddValue(pubd, kSecAttrLabel, publicName);
347 CFDictionaryAddValue(privd, kSecAttrLabel, privateName);
348
349 kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keySizeInBits);
350 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
351 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeRSA);
352 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
353 CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanTrue);
354 CFDictionaryAddValue(kgp, kSecPublicKeyAttrs, pubd);
355 CFDictionaryAddValue(kgp, kSecPrivateKeyAttrs, privd);
356
357 OSStatus status;
358 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
359 "Generate %ld bit (%ld byte) persistent RSA keypair",
360 keySizeInBits, keySizeInBytes);
361 CFRelease(kzib);
362 CFRelease(kgp);
363
364 SKIP: {
365 skip("keygen failed", 8, status == errSecSuccess);
366 ok(pubKey, "pubkey returned");
367 ok(privKey, "privKey returned");
368 is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
369 is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
370
371 SecKeyRef pubKey2, privKey2;
372 CFDictionaryAddValue(pubd, kSecClass, kSecClassKey);
373 CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue);
374 CFDictionaryAddValue(privd, kSecClass, kSecClassKey);
375 CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue);
376 CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue);
377 ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2),
378 "retrieve pub key by label");
379 ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2),
380 "retrieve priv key by label and kSecAttrCanSign");
381
382 /* Sign something. */
383 uint8_t something[50] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
384 uint8_t sig[keySizeInBytes];
385 size_t sigLen = keySizeInBytes;
386 ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1,
387 something, sizeof(something), sig, &sigLen), "sign something");
388 ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1,
389 something, sizeof(something), sig, sigLen), "verify sig on something");
390
391 sigLen = keySizeInBytes;
392 is_status(SecKeyEncrypt(pubKey2, kSecPaddingPKCS1SHA1,
393 something, sizeof(something), sig, &sigLen), errSecParam,
394 "encrypt something with invalid padding");
395
396 /* Cleanup. */
397 CFReleaseNull(pubKey2);
398 CFReleaseNull(privKey2);
399
400 /* delete from keychain - note: do it before releasing publicName and privateName
401 because pubd and privd have no retain/release callbacks */
402 ok_status(SecItemDelete(pubd), "delete generated pub key");
403 ok_status(SecItemDelete(privd), "delete generated priv key");
404 }
405
406 /* Cleanup. */
407 CFReleaseNull(pubKey);
408 CFReleaseNull(privKey);
409
410 CFReleaseNull(publicName);
411 CFReleaseNull(privateName);
412
413 CFRelease(pubd);
414 CFRelease(privd);
415}
416
417/* Test basic add delete update copy matching stuff. */
418#define kTestCount ((3 * kKeyGenTestCount) + kKeyGen2TestCount)
419static void tests(void)
420{
421 /* Comment out lines below for testing generating all common key sizes,
422 disabled now for speed reasons. */
423 //testkeygen(512);
424 testkeygen(768);
425 testkeygen(1024);
426 testkeygen(2056); // Stranged sized for edge cases in padding.
427 //testkeygen(2048);
428 //testkeygen(4096);
429
430 testkeygen2(768);
431}
432
433int si_40_seckey(int argc, char *const *argv)
434{
435 plan_tests(kTestCount);
436
437 tests();
438
439 return 0;
440}