|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include <CoreFoundation/CoreFoundation.h> |
|
6 #include <Security/Security.h> |
|
7 #include <dlfcn.h> |
|
8 |
|
9 #include "cryptox.h" |
|
10 |
|
11 // We declare the necessary parts of the Security Transforms API here since |
|
12 // we're building with the 10.6 SDK, which doesn't know about Security |
|
13 // Transforms. |
|
14 #ifdef __cplusplus |
|
15 extern "C" { |
|
16 #endif |
|
17 const CFStringRef kSecTransformInputAttributeName = CFSTR("INPUT"); |
|
18 typedef CFTypeRef SecTransformRef; |
|
19 typedef struct OpaqueSecKeyRef* SecKeyRef; |
|
20 |
|
21 typedef SecTransformRef (*SecTransformCreateReadTransformWithReadStreamFunc) |
|
22 (CFReadStreamRef inputStream); |
|
23 SecTransformCreateReadTransformWithReadStreamFunc |
|
24 SecTransformCreateReadTransformWithReadStreamPtr = NULL; |
|
25 typedef CFTypeRef (*SecTransformExecuteFunc)(SecTransformRef transform, |
|
26 CFErrorRef* error); |
|
27 SecTransformExecuteFunc SecTransformExecutePtr = NULL; |
|
28 typedef SecTransformRef (*SecVerifyTransformCreateFunc)(SecKeyRef key, |
|
29 CFDataRef signature, |
|
30 CFErrorRef* error); |
|
31 SecVerifyTransformCreateFunc SecVerifyTransformCreatePtr = NULL; |
|
32 typedef Boolean (*SecTransformSetAttributeFunc)(SecTransformRef transform, |
|
33 CFStringRef key, |
|
34 CFTypeRef value, |
|
35 CFErrorRef* error); |
|
36 SecTransformSetAttributeFunc SecTransformSetAttributePtr = NULL; |
|
37 #ifdef __cplusplus |
|
38 } |
|
39 #endif |
|
40 |
|
41 #define MAC_OS_X_VERSION_10_7_HEX 0x00001070 |
|
42 |
|
43 static int sOnLionOrLater = -1; |
|
44 |
|
45 static bool OnLionOrLater() |
|
46 { |
|
47 if (sOnLionOrLater < 0) { |
|
48 SInt32 major = 0, minor = 0; |
|
49 |
|
50 CFURLRef url = |
|
51 CFURLCreateWithString(kCFAllocatorDefault, |
|
52 CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"), |
|
53 NULL); |
|
54 CFReadStreamRef stream = |
|
55 CFReadStreamCreateWithFile(kCFAllocatorDefault, url); |
|
56 CFReadStreamOpen(stream); |
|
57 CFDictionaryRef sysVersionPlist = (CFDictionaryRef) |
|
58 CFPropertyListCreateWithStream(kCFAllocatorDefault, |
|
59 stream, 0, kCFPropertyListImmutable, |
|
60 NULL, NULL); |
|
61 CFReadStreamClose(stream); |
|
62 CFRelease(stream); |
|
63 CFRelease(url); |
|
64 |
|
65 CFStringRef versionString = (CFStringRef) |
|
66 CFDictionaryGetValue(sysVersionPlist, CFSTR("ProductVersion")); |
|
67 CFArrayRef versions = |
|
68 CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, |
|
69 versionString, CFSTR(".")); |
|
70 CFIndex count = CFArrayGetCount(versions); |
|
71 if (count > 0) { |
|
72 CFStringRef component = (CFStringRef) CFArrayGetValueAtIndex(versions, 0); |
|
73 major = CFStringGetIntValue(component); |
|
74 if (count > 1) { |
|
75 component = (CFStringRef) CFArrayGetValueAtIndex(versions, 1); |
|
76 minor = CFStringGetIntValue(component); |
|
77 } |
|
78 } |
|
79 CFRelease(sysVersionPlist); |
|
80 CFRelease(versions); |
|
81 |
|
82 if (major < 10) { |
|
83 sOnLionOrLater = 0; |
|
84 } else { |
|
85 int version = 0x1000 + (minor << 4); |
|
86 sOnLionOrLater = version >= MAC_OS_X_VERSION_10_7_HEX ? 1 : 0; |
|
87 } |
|
88 } |
|
89 |
|
90 return sOnLionOrLater > 0 ? true : false; |
|
91 } |
|
92 |
|
93 static bool sCssmInitialized = false; |
|
94 static CSSM_VERSION sCssmVersion = {2, 0}; |
|
95 static const CSSM_GUID sMozCssmGuid = |
|
96 { 0x9243121f, 0x5820, 0x4b41, |
|
97 { 0xa6, 0x52, 0xba, 0xb6, 0x3f, 0x9d, 0x3d, 0x7f }}; |
|
98 static CSSM_CSP_HANDLE sCspHandle = NULL; |
|
99 |
|
100 void* cssmMalloc (CSSM_SIZE aSize, void* aAllocRef) { |
|
101 (void)aAllocRef; |
|
102 return malloc(aSize); |
|
103 } |
|
104 |
|
105 void cssmFree (void* aPtr, void* aAllocRef) { |
|
106 (void)aAllocRef; |
|
107 free(aPtr); |
|
108 return; |
|
109 } |
|
110 |
|
111 void* cssmRealloc (void* aPtr, CSSM_SIZE aSize, void* aAllocRef) { |
|
112 (void)aAllocRef; |
|
113 return realloc(aPtr, aSize); |
|
114 } |
|
115 |
|
116 void* cssmCalloc (uint32 aNum, CSSM_SIZE aSize, void* aAllocRef) { |
|
117 (void)aAllocRef; |
|
118 return calloc(aNum, aSize); |
|
119 } |
|
120 |
|
121 static CSSM_API_MEMORY_FUNCS cssmMemFuncs = { |
|
122 &cssmMalloc, |
|
123 &cssmFree, |
|
124 &cssmRealloc, |
|
125 &cssmCalloc, |
|
126 NULL |
|
127 }; |
|
128 |
|
129 CryptoX_Result |
|
130 CryptoMac_InitCryptoProvider() |
|
131 { |
|
132 if (!OnLionOrLater()) { |
|
133 return CryptoX_Success; |
|
134 } |
|
135 |
|
136 if (!SecTransformCreateReadTransformWithReadStreamPtr) { |
|
137 SecTransformCreateReadTransformWithReadStreamPtr = |
|
138 (SecTransformCreateReadTransformWithReadStreamFunc) |
|
139 dlsym(RTLD_DEFAULT, "SecTransformCreateReadTransformWithReadStream"); |
|
140 } |
|
141 if (!SecTransformExecutePtr) { |
|
142 SecTransformExecutePtr = (SecTransformExecuteFunc) |
|
143 dlsym(RTLD_DEFAULT, "SecTransformExecute"); |
|
144 } |
|
145 if (!SecVerifyTransformCreatePtr) { |
|
146 SecVerifyTransformCreatePtr = (SecVerifyTransformCreateFunc) |
|
147 dlsym(RTLD_DEFAULT, "SecVerifyTransformCreate"); |
|
148 } |
|
149 if (!SecTransformSetAttributePtr) { |
|
150 SecTransformSetAttributePtr = (SecTransformSetAttributeFunc) |
|
151 dlsym(RTLD_DEFAULT, "SecTransformSetAttribute"); |
|
152 } |
|
153 if (!SecTransformCreateReadTransformWithReadStreamPtr || |
|
154 !SecTransformExecutePtr || |
|
155 !SecVerifyTransformCreatePtr || |
|
156 !SecTransformSetAttributePtr) { |
|
157 return CryptoX_Error; |
|
158 } |
|
159 return CryptoX_Success; |
|
160 } |
|
161 |
|
162 CryptoX_Result |
|
163 CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData) |
|
164 { |
|
165 if (!aInputData) { |
|
166 return CryptoX_Error; |
|
167 } |
|
168 |
|
169 void* inputData = CFDataCreateMutable(kCFAllocatorDefault, 0); |
|
170 if (!inputData) { |
|
171 return CryptoX_Error; |
|
172 } |
|
173 |
|
174 if (!OnLionOrLater()) { |
|
175 CSSM_DATA_PTR cssmData = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA)); |
|
176 if (!cssmData) { |
|
177 CFRelease(inputData); |
|
178 return CryptoX_Error; |
|
179 } |
|
180 cssmData->Data = (uint8*)inputData; |
|
181 cssmData->Length = 0; |
|
182 *aInputData = cssmData; |
|
183 return CryptoX_Success; |
|
184 } |
|
185 |
|
186 *aInputData = inputData; |
|
187 return CryptoX_Success; |
|
188 } |
|
189 |
|
190 CryptoX_Result |
|
191 CryptoMac_VerifyUpdate(CryptoX_SignatureHandle* aInputData, void* aBuf, |
|
192 unsigned int aLen) |
|
193 { |
|
194 if (aLen == 0) { |
|
195 return CryptoX_Success; |
|
196 } |
|
197 if (!aInputData || !*aInputData) { |
|
198 return CryptoX_Error; |
|
199 } |
|
200 |
|
201 CFMutableDataRef inputData; |
|
202 if (!OnLionOrLater()) { |
|
203 inputData = (CFMutableDataRef)((CSSM_DATA_PTR)*aInputData)->Data; |
|
204 ((CSSM_DATA_PTR)*aInputData)->Length += aLen; |
|
205 } else { |
|
206 inputData = (CFMutableDataRef)*aInputData; |
|
207 } |
|
208 |
|
209 CFDataAppendBytes(inputData, (const uint8*)aBuf, aLen); |
|
210 return CryptoX_Success; |
|
211 } |
|
212 |
|
213 CryptoX_Result |
|
214 CryptoMac_LoadPublicKey(const unsigned char* aCertData, |
|
215 CryptoX_PublicKey* aPublicKey) |
|
216 { |
|
217 if (!aCertData || !aPublicKey) { |
|
218 return CryptoX_Error; |
|
219 } |
|
220 *aPublicKey = NULL; |
|
221 |
|
222 if (!OnLionOrLater()) { |
|
223 if (!sCspHandle) { |
|
224 CSSM_RETURN rv; |
|
225 if (!sCssmInitialized) { |
|
226 CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE; |
|
227 rv = CSSM_Init(&sCssmVersion, |
|
228 CSSM_PRIVILEGE_SCOPE_PROCESS, |
|
229 &sMozCssmGuid, |
|
230 CSSM_KEY_HIERARCHY_NONE, |
|
231 &pvcPolicy, |
|
232 NULL); |
|
233 if (rv != CSSM_OK) { |
|
234 return CryptoX_Error; |
|
235 } |
|
236 sCssmInitialized = true; |
|
237 } |
|
238 |
|
239 rv = CSSM_ModuleLoad(&gGuidAppleCSP, |
|
240 CSSM_KEY_HIERARCHY_NONE, |
|
241 NULL, |
|
242 NULL); |
|
243 if (rv != CSSM_OK) { |
|
244 return CryptoX_Error; |
|
245 } |
|
246 |
|
247 CSSM_CSP_HANDLE cspHandle; |
|
248 rv = CSSM_ModuleAttach(&gGuidAppleCSP, |
|
249 &sCssmVersion, |
|
250 &cssmMemFuncs, |
|
251 0, |
|
252 CSSM_SERVICE_CSP, |
|
253 0, |
|
254 CSSM_KEY_HIERARCHY_NONE, |
|
255 NULL, |
|
256 0, |
|
257 NULL, |
|
258 &cspHandle); |
|
259 if (rv != CSSM_OK) { |
|
260 return CryptoX_Error; |
|
261 } |
|
262 sCspHandle = cspHandle; |
|
263 } |
|
264 |
|
265 FILE* certFile = NULL; |
|
266 long certFileSize = 0; |
|
267 uint8* certBuffer = NULL; |
|
268 |
|
269 certFile = fopen((char*)aCertData, "rb"); |
|
270 if (!certFile) { |
|
271 return CryptoX_Error; |
|
272 } |
|
273 if (fseek(certFile, 0, SEEK_END)) { |
|
274 fclose(certFile); |
|
275 return CryptoX_Error; |
|
276 } |
|
277 certFileSize = ftell(certFile); |
|
278 if (certFileSize < 0) { |
|
279 fclose(certFile); |
|
280 return CryptoX_Error; |
|
281 } |
|
282 certBuffer = (uint8*)malloc(certFileSize); |
|
283 if (fseek(certFile, 0, SEEK_SET)) { |
|
284 free(certBuffer); |
|
285 fclose(certFile); |
|
286 return CryptoX_Error; |
|
287 } |
|
288 uint readResult = fread(certBuffer, sizeof(uint8), certFileSize, certFile); |
|
289 if (readResult != certFileSize) { |
|
290 free(certBuffer); |
|
291 fclose(certFile); |
|
292 return CryptoX_Error; |
|
293 } |
|
294 fclose(certFile); |
|
295 |
|
296 CFDataRef certData = CFDataCreate(kCFAllocatorDefault, |
|
297 certBuffer, |
|
298 certFileSize); |
|
299 free(certBuffer); |
|
300 if (!certData) { |
|
301 return CryptoX_Error; |
|
302 } |
|
303 |
|
304 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, |
|
305 certData); |
|
306 CFRelease(certData); |
|
307 if (!cert) { |
|
308 return CryptoX_Error; |
|
309 } |
|
310 |
|
311 SecKeyRef publicKey; |
|
312 OSStatus status = SecCertificateCopyPublicKey(cert, (SecKeyRef*)&publicKey); |
|
313 CFRelease(cert); |
|
314 if (status) { |
|
315 return CryptoX_Error; |
|
316 } |
|
317 |
|
318 *aPublicKey = (void*)publicKey; |
|
319 return CryptoX_Success; |
|
320 } |
|
321 |
|
322 CFURLRef url = |
|
323 CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, |
|
324 aCertData, |
|
325 strlen((char*)aCertData), |
|
326 false); |
|
327 if (!url) { |
|
328 return CryptoX_Error; |
|
329 } |
|
330 |
|
331 CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url); |
|
332 if (!stream) { |
|
333 CFRelease(url); |
|
334 return CryptoX_Error; |
|
335 } |
|
336 |
|
337 SecTransformRef readTransform = |
|
338 SecTransformCreateReadTransformWithReadStreamPtr(stream); |
|
339 if (!readTransform) { |
|
340 CFRelease(url); |
|
341 CFRelease(stream); |
|
342 return CryptoX_Error; |
|
343 } |
|
344 |
|
345 CFErrorRef error; |
|
346 CFDataRef tempCertData = (CFDataRef)SecTransformExecutePtr(readTransform, |
|
347 &error); |
|
348 if (!tempCertData || error) { |
|
349 CFRelease(url); |
|
350 CFRelease(stream); |
|
351 CFRelease(readTransform); |
|
352 return CryptoX_Error; |
|
353 } |
|
354 |
|
355 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, |
|
356 tempCertData); |
|
357 if (!cert) { |
|
358 CFRelease(url); |
|
359 CFRelease(stream); |
|
360 CFRelease(readTransform); |
|
361 CFRelease(tempCertData); |
|
362 return CryptoX_Error; |
|
363 } |
|
364 |
|
365 CryptoX_Result result = CryptoX_Error; |
|
366 OSStatus status = SecCertificateCopyPublicKey(cert, |
|
367 (SecKeyRef*)aPublicKey); |
|
368 if (status == 0) { |
|
369 result = CryptoX_Success; |
|
370 } |
|
371 |
|
372 CFRelease(url); |
|
373 CFRelease(stream); |
|
374 CFRelease(readTransform); |
|
375 CFRelease(tempCertData); |
|
376 CFRelease(cert); |
|
377 |
|
378 return result; |
|
379 } |
|
380 |
|
381 CryptoX_Result |
|
382 CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData, |
|
383 CryptoX_PublicKey* aPublicKey, |
|
384 const unsigned char* aSignature, |
|
385 unsigned int aSignatureLen) |
|
386 { |
|
387 if (!aInputData || !*aInputData || !aPublicKey || !*aPublicKey || |
|
388 !aSignature || aSignatureLen == 0) { |
|
389 return CryptoX_Error; |
|
390 } |
|
391 |
|
392 if (!OnLionOrLater()) { |
|
393 if (!sCspHandle) { |
|
394 return CryptoX_Error; |
|
395 } |
|
396 |
|
397 CSSM_KEY* publicKey; |
|
398 OSStatus status = SecKeyGetCSSMKey((SecKeyRef)*aPublicKey, |
|
399 (const CSSM_KEY**)&publicKey); |
|
400 if (status) { |
|
401 return CryptoX_Error; |
|
402 } |
|
403 |
|
404 CSSM_CC_HANDLE ccHandle; |
|
405 if (CSSM_CSP_CreateSignatureContext(sCspHandle, |
|
406 CSSM_ALGID_SHA1WithRSA, |
|
407 NULL, |
|
408 publicKey, |
|
409 &ccHandle) != CSSM_OK) { |
|
410 return CryptoX_Error; |
|
411 } |
|
412 |
|
413 CryptoX_Result result = CryptoX_Error; |
|
414 CSSM_DATA signatureData; |
|
415 signatureData.Data = (uint8*)aSignature; |
|
416 signatureData.Length = aSignatureLen; |
|
417 CSSM_DATA inputData; |
|
418 inputData.Data = |
|
419 CFDataGetMutableBytePtr((CFMutableDataRef) |
|
420 (((CSSM_DATA_PTR)*aInputData)->Data)); |
|
421 inputData.Length = ((CSSM_DATA_PTR)*aInputData)->Length; |
|
422 if (CSSM_VerifyData(ccHandle, |
|
423 &inputData, |
|
424 1, |
|
425 CSSM_ALGID_NONE, |
|
426 &signatureData) == CSSM_OK) { |
|
427 result = CryptoX_Success; |
|
428 } |
|
429 return result; |
|
430 } |
|
431 |
|
432 CFDataRef signatureData = CFDataCreate(kCFAllocatorDefault, |
|
433 aSignature, aSignatureLen); |
|
434 if (!signatureData) { |
|
435 return CryptoX_Error; |
|
436 } |
|
437 |
|
438 CFErrorRef error; |
|
439 SecTransformRef verifier = |
|
440 SecVerifyTransformCreatePtr((SecKeyRef)*aPublicKey, |
|
441 signatureData, |
|
442 &error); |
|
443 if (!verifier || error) { |
|
444 CFRelease(signatureData); |
|
445 return CryptoX_Error; |
|
446 } |
|
447 |
|
448 SecTransformSetAttributePtr(verifier, |
|
449 kSecTransformInputAttributeName, |
|
450 (CFDataRef)*aInputData, |
|
451 &error); |
|
452 if (error) { |
|
453 CFRelease(signatureData); |
|
454 CFRelease(verifier); |
|
455 return CryptoX_Error; |
|
456 } |
|
457 |
|
458 CryptoX_Result result = CryptoX_Error; |
|
459 CFTypeRef rv = SecTransformExecutePtr(verifier, &error); |
|
460 if (error) { |
|
461 CFRelease(signatureData); |
|
462 CFRelease(verifier); |
|
463 return CryptoX_Error; |
|
464 } |
|
465 |
|
466 if (CFGetTypeID(rv) == CFBooleanGetTypeID() && |
|
467 CFBooleanGetValue((CFBooleanRef)rv) == true) { |
|
468 result = CryptoX_Success; |
|
469 } |
|
470 |
|
471 CFRelease(signatureData); |
|
472 CFRelease(verifier); |
|
473 |
|
474 return result; |
|
475 } |
|
476 |
|
477 void |
|
478 CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData) |
|
479 { |
|
480 if (!aInputData || !*aInputData) { |
|
481 return; |
|
482 } |
|
483 |
|
484 CFMutableDataRef inputData = NULL; |
|
485 if (OnLionOrLater()) { |
|
486 inputData = (CFMutableDataRef)*aInputData; |
|
487 } else { |
|
488 inputData = (CFMutableDataRef)((CSSM_DATA_PTR)*aInputData)->Data; |
|
489 } |
|
490 |
|
491 CFRelease(inputData); |
|
492 if (!OnLionOrLater()) { |
|
493 free((CSSM_DATA_PTR)*aInputData); |
|
494 } |
|
495 } |
|
496 |
|
497 void |
|
498 CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey) |
|
499 { |
|
500 if (!aPublicKey || !*aPublicKey) { |
|
501 return; |
|
502 } |
|
503 if (!OnLionOrLater() && sCspHandle) { |
|
504 CSSM_ModuleDetach(sCspHandle); |
|
505 sCspHandle = NULL; |
|
506 } |
|
507 CFRelease((SecKeyRef)*aPublicKey); |
|
508 } |