]>
Commit | Line | Data |
---|---|---|
427c49bc A |
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 | ||
39 | static 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 | ||
55 | SKIP: { | |
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 | ||
79 | static 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 | ||
104 | static 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 | ||
122 | SKIP: { | |
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 | ||
171 | static 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 | ||
208 | SKIP: { | |
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. */ | |
260 | static 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 | ||
276 | int si_41_sececkey(int argc, char *const *argv) | |
277 | { | |
278 | plan_tests(140); | |
279 | ||
280 | tests(); | |
281 | ||
282 | return 0; | |
283 | } |