1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/modules/libmar/verify/MacVerifyCrypto.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,508 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include <CoreFoundation/CoreFoundation.h> 1.9 +#include <Security/Security.h> 1.10 +#include <dlfcn.h> 1.11 + 1.12 +#include "cryptox.h" 1.13 + 1.14 +// We declare the necessary parts of the Security Transforms API here since 1.15 +// we're building with the 10.6 SDK, which doesn't know about Security 1.16 +// Transforms. 1.17 +#ifdef __cplusplus 1.18 +extern "C" { 1.19 +#endif 1.20 + const CFStringRef kSecTransformInputAttributeName = CFSTR("INPUT"); 1.21 + typedef CFTypeRef SecTransformRef; 1.22 + typedef struct OpaqueSecKeyRef* SecKeyRef; 1.23 + 1.24 + typedef SecTransformRef (*SecTransformCreateReadTransformWithReadStreamFunc) 1.25 + (CFReadStreamRef inputStream); 1.26 + SecTransformCreateReadTransformWithReadStreamFunc 1.27 + SecTransformCreateReadTransformWithReadStreamPtr = NULL; 1.28 + typedef CFTypeRef (*SecTransformExecuteFunc)(SecTransformRef transform, 1.29 + CFErrorRef* error); 1.30 + SecTransformExecuteFunc SecTransformExecutePtr = NULL; 1.31 + typedef SecTransformRef (*SecVerifyTransformCreateFunc)(SecKeyRef key, 1.32 + CFDataRef signature, 1.33 + CFErrorRef* error); 1.34 + SecVerifyTransformCreateFunc SecVerifyTransformCreatePtr = NULL; 1.35 + typedef Boolean (*SecTransformSetAttributeFunc)(SecTransformRef transform, 1.36 + CFStringRef key, 1.37 + CFTypeRef value, 1.38 + CFErrorRef* error); 1.39 + SecTransformSetAttributeFunc SecTransformSetAttributePtr = NULL; 1.40 +#ifdef __cplusplus 1.41 +} 1.42 +#endif 1.43 + 1.44 +#define MAC_OS_X_VERSION_10_7_HEX 0x00001070 1.45 + 1.46 +static int sOnLionOrLater = -1; 1.47 + 1.48 +static bool OnLionOrLater() 1.49 +{ 1.50 + if (sOnLionOrLater < 0) { 1.51 + SInt32 major = 0, minor = 0; 1.52 + 1.53 + CFURLRef url = 1.54 + CFURLCreateWithString(kCFAllocatorDefault, 1.55 + CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"), 1.56 + NULL); 1.57 + CFReadStreamRef stream = 1.58 + CFReadStreamCreateWithFile(kCFAllocatorDefault, url); 1.59 + CFReadStreamOpen(stream); 1.60 + CFDictionaryRef sysVersionPlist = (CFDictionaryRef) 1.61 + CFPropertyListCreateWithStream(kCFAllocatorDefault, 1.62 + stream, 0, kCFPropertyListImmutable, 1.63 + NULL, NULL); 1.64 + CFReadStreamClose(stream); 1.65 + CFRelease(stream); 1.66 + CFRelease(url); 1.67 + 1.68 + CFStringRef versionString = (CFStringRef) 1.69 + CFDictionaryGetValue(sysVersionPlist, CFSTR("ProductVersion")); 1.70 + CFArrayRef versions = 1.71 + CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, 1.72 + versionString, CFSTR(".")); 1.73 + CFIndex count = CFArrayGetCount(versions); 1.74 + if (count > 0) { 1.75 + CFStringRef component = (CFStringRef) CFArrayGetValueAtIndex(versions, 0); 1.76 + major = CFStringGetIntValue(component); 1.77 + if (count > 1) { 1.78 + component = (CFStringRef) CFArrayGetValueAtIndex(versions, 1); 1.79 + minor = CFStringGetIntValue(component); 1.80 + } 1.81 + } 1.82 + CFRelease(sysVersionPlist); 1.83 + CFRelease(versions); 1.84 + 1.85 + if (major < 10) { 1.86 + sOnLionOrLater = 0; 1.87 + } else { 1.88 + int version = 0x1000 + (minor << 4); 1.89 + sOnLionOrLater = version >= MAC_OS_X_VERSION_10_7_HEX ? 1 : 0; 1.90 + } 1.91 + } 1.92 + 1.93 + return sOnLionOrLater > 0 ? true : false; 1.94 +} 1.95 + 1.96 +static bool sCssmInitialized = false; 1.97 +static CSSM_VERSION sCssmVersion = {2, 0}; 1.98 +static const CSSM_GUID sMozCssmGuid = 1.99 + { 0x9243121f, 0x5820, 0x4b41, 1.100 + { 0xa6, 0x52, 0xba, 0xb6, 0x3f, 0x9d, 0x3d, 0x7f }}; 1.101 +static CSSM_CSP_HANDLE sCspHandle = NULL; 1.102 + 1.103 +void* cssmMalloc (CSSM_SIZE aSize, void* aAllocRef) { 1.104 + (void)aAllocRef; 1.105 + return malloc(aSize); 1.106 +} 1.107 + 1.108 +void cssmFree (void* aPtr, void* aAllocRef) { 1.109 + (void)aAllocRef; 1.110 + free(aPtr); 1.111 + return; 1.112 +} 1.113 + 1.114 +void* cssmRealloc (void* aPtr, CSSM_SIZE aSize, void* aAllocRef) { 1.115 + (void)aAllocRef; 1.116 + return realloc(aPtr, aSize); 1.117 +} 1.118 + 1.119 +void* cssmCalloc (uint32 aNum, CSSM_SIZE aSize, void* aAllocRef) { 1.120 + (void)aAllocRef; 1.121 + return calloc(aNum, aSize); 1.122 +} 1.123 + 1.124 +static CSSM_API_MEMORY_FUNCS cssmMemFuncs = { 1.125 + &cssmMalloc, 1.126 + &cssmFree, 1.127 + &cssmRealloc, 1.128 + &cssmCalloc, 1.129 + NULL 1.130 + }; 1.131 + 1.132 +CryptoX_Result 1.133 +CryptoMac_InitCryptoProvider() 1.134 +{ 1.135 + if (!OnLionOrLater()) { 1.136 + return CryptoX_Success; 1.137 + } 1.138 + 1.139 + if (!SecTransformCreateReadTransformWithReadStreamPtr) { 1.140 + SecTransformCreateReadTransformWithReadStreamPtr = 1.141 + (SecTransformCreateReadTransformWithReadStreamFunc) 1.142 + dlsym(RTLD_DEFAULT, "SecTransformCreateReadTransformWithReadStream"); 1.143 + } 1.144 + if (!SecTransformExecutePtr) { 1.145 + SecTransformExecutePtr = (SecTransformExecuteFunc) 1.146 + dlsym(RTLD_DEFAULT, "SecTransformExecute"); 1.147 + } 1.148 + if (!SecVerifyTransformCreatePtr) { 1.149 + SecVerifyTransformCreatePtr = (SecVerifyTransformCreateFunc) 1.150 + dlsym(RTLD_DEFAULT, "SecVerifyTransformCreate"); 1.151 + } 1.152 + if (!SecTransformSetAttributePtr) { 1.153 + SecTransformSetAttributePtr = (SecTransformSetAttributeFunc) 1.154 + dlsym(RTLD_DEFAULT, "SecTransformSetAttribute"); 1.155 + } 1.156 + if (!SecTransformCreateReadTransformWithReadStreamPtr || 1.157 + !SecTransformExecutePtr || 1.158 + !SecVerifyTransformCreatePtr || 1.159 + !SecTransformSetAttributePtr) { 1.160 + return CryptoX_Error; 1.161 + } 1.162 + return CryptoX_Success; 1.163 +} 1.164 + 1.165 +CryptoX_Result 1.166 +CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData) 1.167 +{ 1.168 + if (!aInputData) { 1.169 + return CryptoX_Error; 1.170 + } 1.171 + 1.172 + void* inputData = CFDataCreateMutable(kCFAllocatorDefault, 0); 1.173 + if (!inputData) { 1.174 + return CryptoX_Error; 1.175 + } 1.176 + 1.177 + if (!OnLionOrLater()) { 1.178 + CSSM_DATA_PTR cssmData = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA)); 1.179 + if (!cssmData) { 1.180 + CFRelease(inputData); 1.181 + return CryptoX_Error; 1.182 + } 1.183 + cssmData->Data = (uint8*)inputData; 1.184 + cssmData->Length = 0; 1.185 + *aInputData = cssmData; 1.186 + return CryptoX_Success; 1.187 + } 1.188 + 1.189 + *aInputData = inputData; 1.190 + return CryptoX_Success; 1.191 +} 1.192 + 1.193 +CryptoX_Result 1.194 +CryptoMac_VerifyUpdate(CryptoX_SignatureHandle* aInputData, void* aBuf, 1.195 + unsigned int aLen) 1.196 +{ 1.197 + if (aLen == 0) { 1.198 + return CryptoX_Success; 1.199 + } 1.200 + if (!aInputData || !*aInputData) { 1.201 + return CryptoX_Error; 1.202 + } 1.203 + 1.204 + CFMutableDataRef inputData; 1.205 + if (!OnLionOrLater()) { 1.206 + inputData = (CFMutableDataRef)((CSSM_DATA_PTR)*aInputData)->Data; 1.207 + ((CSSM_DATA_PTR)*aInputData)->Length += aLen; 1.208 + } else { 1.209 + inputData = (CFMutableDataRef)*aInputData; 1.210 + } 1.211 + 1.212 + CFDataAppendBytes(inputData, (const uint8*)aBuf, aLen); 1.213 + return CryptoX_Success; 1.214 +} 1.215 + 1.216 +CryptoX_Result 1.217 +CryptoMac_LoadPublicKey(const unsigned char* aCertData, 1.218 + CryptoX_PublicKey* aPublicKey) 1.219 +{ 1.220 + if (!aCertData || !aPublicKey) { 1.221 + return CryptoX_Error; 1.222 + } 1.223 + *aPublicKey = NULL; 1.224 + 1.225 + if (!OnLionOrLater()) { 1.226 + if (!sCspHandle) { 1.227 + CSSM_RETURN rv; 1.228 + if (!sCssmInitialized) { 1.229 + CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE; 1.230 + rv = CSSM_Init(&sCssmVersion, 1.231 + CSSM_PRIVILEGE_SCOPE_PROCESS, 1.232 + &sMozCssmGuid, 1.233 + CSSM_KEY_HIERARCHY_NONE, 1.234 + &pvcPolicy, 1.235 + NULL); 1.236 + if (rv != CSSM_OK) { 1.237 + return CryptoX_Error; 1.238 + } 1.239 + sCssmInitialized = true; 1.240 + } 1.241 + 1.242 + rv = CSSM_ModuleLoad(&gGuidAppleCSP, 1.243 + CSSM_KEY_HIERARCHY_NONE, 1.244 + NULL, 1.245 + NULL); 1.246 + if (rv != CSSM_OK) { 1.247 + return CryptoX_Error; 1.248 + } 1.249 + 1.250 + CSSM_CSP_HANDLE cspHandle; 1.251 + rv = CSSM_ModuleAttach(&gGuidAppleCSP, 1.252 + &sCssmVersion, 1.253 + &cssmMemFuncs, 1.254 + 0, 1.255 + CSSM_SERVICE_CSP, 1.256 + 0, 1.257 + CSSM_KEY_HIERARCHY_NONE, 1.258 + NULL, 1.259 + 0, 1.260 + NULL, 1.261 + &cspHandle); 1.262 + if (rv != CSSM_OK) { 1.263 + return CryptoX_Error; 1.264 + } 1.265 + sCspHandle = cspHandle; 1.266 + } 1.267 + 1.268 + FILE* certFile = NULL; 1.269 + long certFileSize = 0; 1.270 + uint8* certBuffer = NULL; 1.271 + 1.272 + certFile = fopen((char*)aCertData, "rb"); 1.273 + if (!certFile) { 1.274 + return CryptoX_Error; 1.275 + } 1.276 + if (fseek(certFile, 0, SEEK_END)) { 1.277 + fclose(certFile); 1.278 + return CryptoX_Error; 1.279 + } 1.280 + certFileSize = ftell(certFile); 1.281 + if (certFileSize < 0) { 1.282 + fclose(certFile); 1.283 + return CryptoX_Error; 1.284 + } 1.285 + certBuffer = (uint8*)malloc(certFileSize); 1.286 + if (fseek(certFile, 0, SEEK_SET)) { 1.287 + free(certBuffer); 1.288 + fclose(certFile); 1.289 + return CryptoX_Error; 1.290 + } 1.291 + uint readResult = fread(certBuffer, sizeof(uint8), certFileSize, certFile); 1.292 + if (readResult != certFileSize) { 1.293 + free(certBuffer); 1.294 + fclose(certFile); 1.295 + return CryptoX_Error; 1.296 + } 1.297 + fclose(certFile); 1.298 + 1.299 + CFDataRef certData = CFDataCreate(kCFAllocatorDefault, 1.300 + certBuffer, 1.301 + certFileSize); 1.302 + free(certBuffer); 1.303 + if (!certData) { 1.304 + return CryptoX_Error; 1.305 + } 1.306 + 1.307 + SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, 1.308 + certData); 1.309 + CFRelease(certData); 1.310 + if (!cert) { 1.311 + return CryptoX_Error; 1.312 + } 1.313 + 1.314 + SecKeyRef publicKey; 1.315 + OSStatus status = SecCertificateCopyPublicKey(cert, (SecKeyRef*)&publicKey); 1.316 + CFRelease(cert); 1.317 + if (status) { 1.318 + return CryptoX_Error; 1.319 + } 1.320 + 1.321 + *aPublicKey = (void*)publicKey; 1.322 + return CryptoX_Success; 1.323 + } 1.324 + 1.325 + CFURLRef url = 1.326 + CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 1.327 + aCertData, 1.328 + strlen((char*)aCertData), 1.329 + false); 1.330 + if (!url) { 1.331 + return CryptoX_Error; 1.332 + } 1.333 + 1.334 + CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url); 1.335 + if (!stream) { 1.336 + CFRelease(url); 1.337 + return CryptoX_Error; 1.338 + } 1.339 + 1.340 + SecTransformRef readTransform = 1.341 + SecTransformCreateReadTransformWithReadStreamPtr(stream); 1.342 + if (!readTransform) { 1.343 + CFRelease(url); 1.344 + CFRelease(stream); 1.345 + return CryptoX_Error; 1.346 + } 1.347 + 1.348 + CFErrorRef error; 1.349 + CFDataRef tempCertData = (CFDataRef)SecTransformExecutePtr(readTransform, 1.350 + &error); 1.351 + if (!tempCertData || error) { 1.352 + CFRelease(url); 1.353 + CFRelease(stream); 1.354 + CFRelease(readTransform); 1.355 + return CryptoX_Error; 1.356 + } 1.357 + 1.358 + SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, 1.359 + tempCertData); 1.360 + if (!cert) { 1.361 + CFRelease(url); 1.362 + CFRelease(stream); 1.363 + CFRelease(readTransform); 1.364 + CFRelease(tempCertData); 1.365 + return CryptoX_Error; 1.366 + } 1.367 + 1.368 + CryptoX_Result result = CryptoX_Error; 1.369 + OSStatus status = SecCertificateCopyPublicKey(cert, 1.370 + (SecKeyRef*)aPublicKey); 1.371 + if (status == 0) { 1.372 + result = CryptoX_Success; 1.373 + } 1.374 + 1.375 + CFRelease(url); 1.376 + CFRelease(stream); 1.377 + CFRelease(readTransform); 1.378 + CFRelease(tempCertData); 1.379 + CFRelease(cert); 1.380 + 1.381 + return result; 1.382 +} 1.383 + 1.384 +CryptoX_Result 1.385 +CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData, 1.386 + CryptoX_PublicKey* aPublicKey, 1.387 + const unsigned char* aSignature, 1.388 + unsigned int aSignatureLen) 1.389 +{ 1.390 + if (!aInputData || !*aInputData || !aPublicKey || !*aPublicKey || 1.391 + !aSignature || aSignatureLen == 0) { 1.392 + return CryptoX_Error; 1.393 + } 1.394 + 1.395 + if (!OnLionOrLater()) { 1.396 + if (!sCspHandle) { 1.397 + return CryptoX_Error; 1.398 + } 1.399 + 1.400 + CSSM_KEY* publicKey; 1.401 + OSStatus status = SecKeyGetCSSMKey((SecKeyRef)*aPublicKey, 1.402 + (const CSSM_KEY**)&publicKey); 1.403 + if (status) { 1.404 + return CryptoX_Error; 1.405 + } 1.406 + 1.407 + CSSM_CC_HANDLE ccHandle; 1.408 + if (CSSM_CSP_CreateSignatureContext(sCspHandle, 1.409 + CSSM_ALGID_SHA1WithRSA, 1.410 + NULL, 1.411 + publicKey, 1.412 + &ccHandle) != CSSM_OK) { 1.413 + return CryptoX_Error; 1.414 + } 1.415 + 1.416 + CryptoX_Result result = CryptoX_Error; 1.417 + CSSM_DATA signatureData; 1.418 + signatureData.Data = (uint8*)aSignature; 1.419 + signatureData.Length = aSignatureLen; 1.420 + CSSM_DATA inputData; 1.421 + inputData.Data = 1.422 + CFDataGetMutableBytePtr((CFMutableDataRef) 1.423 + (((CSSM_DATA_PTR)*aInputData)->Data)); 1.424 + inputData.Length = ((CSSM_DATA_PTR)*aInputData)->Length; 1.425 + if (CSSM_VerifyData(ccHandle, 1.426 + &inputData, 1.427 + 1, 1.428 + CSSM_ALGID_NONE, 1.429 + &signatureData) == CSSM_OK) { 1.430 + result = CryptoX_Success; 1.431 + } 1.432 + return result; 1.433 + } 1.434 + 1.435 + CFDataRef signatureData = CFDataCreate(kCFAllocatorDefault, 1.436 + aSignature, aSignatureLen); 1.437 + if (!signatureData) { 1.438 + return CryptoX_Error; 1.439 + } 1.440 + 1.441 + CFErrorRef error; 1.442 + SecTransformRef verifier = 1.443 + SecVerifyTransformCreatePtr((SecKeyRef)*aPublicKey, 1.444 + signatureData, 1.445 + &error); 1.446 + if (!verifier || error) { 1.447 + CFRelease(signatureData); 1.448 + return CryptoX_Error; 1.449 + } 1.450 + 1.451 + SecTransformSetAttributePtr(verifier, 1.452 + kSecTransformInputAttributeName, 1.453 + (CFDataRef)*aInputData, 1.454 + &error); 1.455 + if (error) { 1.456 + CFRelease(signatureData); 1.457 + CFRelease(verifier); 1.458 + return CryptoX_Error; 1.459 + } 1.460 + 1.461 + CryptoX_Result result = CryptoX_Error; 1.462 + CFTypeRef rv = SecTransformExecutePtr(verifier, &error); 1.463 + if (error) { 1.464 + CFRelease(signatureData); 1.465 + CFRelease(verifier); 1.466 + return CryptoX_Error; 1.467 + } 1.468 + 1.469 + if (CFGetTypeID(rv) == CFBooleanGetTypeID() && 1.470 + CFBooleanGetValue((CFBooleanRef)rv) == true) { 1.471 + result = CryptoX_Success; 1.472 + } 1.473 + 1.474 + CFRelease(signatureData); 1.475 + CFRelease(verifier); 1.476 + 1.477 + return result; 1.478 +} 1.479 + 1.480 +void 1.481 +CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData) 1.482 +{ 1.483 + if (!aInputData || !*aInputData) { 1.484 + return; 1.485 + } 1.486 + 1.487 + CFMutableDataRef inputData = NULL; 1.488 + if (OnLionOrLater()) { 1.489 + inputData = (CFMutableDataRef)*aInputData; 1.490 + } else { 1.491 + inputData = (CFMutableDataRef)((CSSM_DATA_PTR)*aInputData)->Data; 1.492 + } 1.493 + 1.494 + CFRelease(inputData); 1.495 + if (!OnLionOrLater()) { 1.496 + free((CSSM_DATA_PTR)*aInputData); 1.497 + } 1.498 +} 1.499 + 1.500 +void 1.501 +CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey) 1.502 +{ 1.503 + if (!aPublicKey || !*aPublicKey) { 1.504 + return; 1.505 + } 1.506 + if (!OnLionOrLater() && sCspHandle) { 1.507 + CSSM_ModuleDetach(sCspHandle); 1.508 + sCspHandle = NULL; 1.509 + } 1.510 + CFRelease((SecKeyRef)*aPublicKey); 1.511 +}