diff options
Diffstat (limited to 'onlineupdate/source/libmar/verify/MacVerifyCrypto.cpp')
-rw-r--r-- | onlineupdate/source/libmar/verify/MacVerifyCrypto.cpp | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/onlineupdate/source/libmar/verify/MacVerifyCrypto.cpp b/onlineupdate/source/libmar/verify/MacVerifyCrypto.cpp new file mode 100644 index 000000000..e86fac3c5 --- /dev/null +++ b/onlineupdate/source/libmar/verify/MacVerifyCrypto.cpp @@ -0,0 +1,414 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <CoreFoundation/CoreFoundation.h> +#include <Security/Security.h> +#include <dlfcn.h> + +#include "cryptox.h" + +// We declare the necessary parts of the Security Transforms API here since +// we're building with the 10.6 SDK, which doesn't know about Security +// Transforms. +extern "C" { + const CFStringRef kSecTransformInputAttributeName = CFSTR("INPUT"); + typedef CFTypeRef SecTransformRef; + typedef struct OpaqueSecKeyRef* SecKeyRef; + + typedef SecTransformRef (*SecTransformCreateReadTransformWithReadStreamFunc) + (CFReadStreamRef inputStream); + SecTransformCreateReadTransformWithReadStreamFunc + SecTransformCreateReadTransformWithReadStreamPtr = NULL; + typedef CFTypeRef (*SecTransformExecuteFunc)(SecTransformRef transform, + CFErrorRef* error); + SecTransformExecuteFunc SecTransformExecutePtr = NULL; + typedef SecTransformRef (*SecVerifyTransformCreateFunc)(SecKeyRef key, + CFDataRef signature, + CFErrorRef* error); + SecVerifyTransformCreateFunc SecVerifyTransformCreatePtr = NULL; + typedef Boolean (*SecTransformSetAttributeFunc)(SecTransformRef transform, + CFStringRef key, + CFTypeRef value, + CFErrorRef* error); + SecTransformSetAttributeFunc SecTransformSetAttributePtr = NULL; +} + +#define MAC_OS_X_VERSION_10_7_HEX 0x00001070 + +static int sOnLionOrLater = -1; + +static bool OnLionOrLater() +{ + if (sOnLionOrLater < 0) { + SInt32 major = 0, minor = 0; + + CFURLRef url = + CFURLCreateWithString(kCFAllocatorDefault, + CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"), + NULL); + CFReadStreamRef stream = + CFReadStreamCreateWithFile(kCFAllocatorDefault, url); + CFReadStreamOpen(stream); + CFDictionaryRef sysVersionPlist = (CFDictionaryRef) + CFPropertyListCreateWithStream(kCFAllocatorDefault, + stream, 0, kCFPropertyListImmutable, + NULL, NULL); + CFReadStreamClose(stream); + CFRelease(stream); + CFRelease(url); + + CFStringRef versionString = (CFStringRef) + CFDictionaryGetValue(sysVersionPlist, CFSTR("ProductVersion")); + CFArrayRef versions = + CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, + versionString, CFSTR(".")); + CFIndex count = CFArrayGetCount(versions); + if (count > 0) { + CFStringRef component = (CFStringRef) CFArrayGetValueAtIndex(versions, 0); + major = CFStringGetIntValue(component); + if (count > 1) { + component = (CFStringRef) CFArrayGetValueAtIndex(versions, 1); + minor = CFStringGetIntValue(component); + } + } + CFRelease(sysVersionPlist); + CFRelease(versions); + + if (major < 10) { + sOnLionOrLater = 0; + } else { + int version = 0x1000 + (minor << 4); + sOnLionOrLater = version >= MAC_OS_X_VERSION_10_7_HEX ? 1 : 0; + } + } + + return sOnLionOrLater > 0 ? true : false; +} + +static bool sCssmInitialized = false; +static CSSM_VERSION sCssmVersion = {2, 0}; +static const CSSM_GUID sMozCssmGuid = + { 0x9243121f, 0x5820, 0x4b41, + { 0xa6, 0x52, 0xba, 0xb6, 0x3f, 0x9d, 0x3d, 0x7f }}; +static CSSM_CSP_HANDLE sCspHandle = CSSM_INVALID_HANDLE; + +void* cssmMalloc (CSSM_SIZE aSize, void* aAllocRef) { + (void)aAllocRef; + return malloc(aSize); +} + +void cssmFree (void* aPtr, void* aAllocRef) { + (void)aAllocRef; + free(aPtr); + return; +} + +void* cssmRealloc (void* aPtr, CSSM_SIZE aSize, void* aAllocRef) { + (void)aAllocRef; + return realloc(aPtr, aSize); +} + +void* cssmCalloc (uint32 aNum, CSSM_SIZE aSize, void* aAllocRef) { + (void)aAllocRef; + return calloc(aNum, aSize); +} + +static CSSM_API_MEMORY_FUNCS cssmMemFuncs = { + &cssmMalloc, + &cssmFree, + &cssmRealloc, + &cssmCalloc, + NULL + }; + +CryptoX_Result +CryptoMac_InitCryptoProvider() +{ + if (!OnLionOrLater()) { + return CryptoX_Success; + } + + if (!SecTransformCreateReadTransformWithReadStreamPtr) { + SecTransformCreateReadTransformWithReadStreamPtr = + (SecTransformCreateReadTransformWithReadStreamFunc) + dlsym(RTLD_DEFAULT, "SecTransformCreateReadTransformWithReadStream"); + } + if (!SecTransformExecutePtr) { + SecTransformExecutePtr = (SecTransformExecuteFunc) + dlsym(RTLD_DEFAULT, "SecTransformExecute"); + } + if (!SecVerifyTransformCreatePtr) { + SecVerifyTransformCreatePtr = (SecVerifyTransformCreateFunc) + dlsym(RTLD_DEFAULT, "SecVerifyTransformCreate"); + } + if (!SecTransformSetAttributePtr) { + SecTransformSetAttributePtr = (SecTransformSetAttributeFunc) + dlsym(RTLD_DEFAULT, "SecTransformSetAttribute"); + } + if (!SecTransformCreateReadTransformWithReadStreamPtr || + !SecTransformExecutePtr || + !SecVerifyTransformCreatePtr || + !SecTransformSetAttributePtr) { + return CryptoX_Error; + } + return CryptoX_Success; +} + +CryptoX_Result +CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData) +{ + if (!aInputData) { + return CryptoX_Error; + } + + void* inputData = CFDataCreateMutable(kCFAllocatorDefault, 0); + if (!inputData) { + return CryptoX_Error; + } + + if (!OnLionOrLater()) { + CSSM_DATA_PTR cssmData = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA)); + if (!cssmData) { + CFRelease(inputData); + return CryptoX_Error; + } + cssmData->Data = (uint8*)inputData; + cssmData->Length = 0; + *aInputData = cssmData; + return CryptoX_Success; + } + + *aInputData = inputData; + return CryptoX_Success; +} + +CryptoX_Result +CryptoMac_VerifyUpdate(CryptoX_SignatureHandle* aInputData, void* aBuf, + unsigned int aLen) +{ + if (aLen == 0) { + return CryptoX_Success; + } + if (!aInputData || !*aInputData) { + return CryptoX_Error; + } + + CFMutableDataRef inputData; + if (!OnLionOrLater()) { + inputData = (CFMutableDataRef)((CSSM_DATA_PTR)*aInputData)->Data; + ((CSSM_DATA_PTR)*aInputData)->Length += aLen; + } else { + inputData = (CFMutableDataRef)*aInputData; + } + + CFDataAppendBytes(inputData, (const uint8*)aBuf, aLen); + return CryptoX_Success; +} + +CryptoX_Result +CryptoMac_LoadPublicKey(const unsigned char* aCertData, + unsigned int aDataSize, + CryptoX_PublicKey* aPublicKey) +{ + if (!aCertData || aDataSize == 0 || !aPublicKey) { + return CryptoX_Error; + } + *aPublicKey = NULL; + + if (!OnLionOrLater()) { + if (!sCspHandle) { + CSSM_RETURN rv; + if (!sCssmInitialized) { + CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE; + rv = CSSM_Init(&sCssmVersion, + CSSM_PRIVILEGE_SCOPE_PROCESS, + &sMozCssmGuid, + CSSM_KEY_HIERARCHY_NONE, + &pvcPolicy, + NULL); + if (rv != CSSM_OK) { + return CryptoX_Error; + } + sCssmInitialized = true; + } + + rv = CSSM_ModuleLoad(&gGuidAppleCSP, + CSSM_KEY_HIERARCHY_NONE, + NULL, + NULL); + if (rv != CSSM_OK) { + return CryptoX_Error; + } + + CSSM_CSP_HANDLE cspHandle; + rv = CSSM_ModuleAttach(&gGuidAppleCSP, + &sCssmVersion, + &cssmMemFuncs, + 0, + CSSM_SERVICE_CSP, + 0, + CSSM_KEY_HIERARCHY_NONE, + NULL, + 0, + NULL, + &cspHandle); + if (rv != CSSM_OK) { + return CryptoX_Error; + } + sCspHandle = cspHandle; + } + } + + CFDataRef certData = CFDataCreate(kCFAllocatorDefault, + aCertData, + aDataSize); + if (!certData) { + return CryptoX_Error; + } + + SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, + certData); + CFRelease(certData); + if (!cert) { + return CryptoX_Error; + } + + OSStatus status = SecCertificateCopyPublicKey(cert, + (SecKeyRef*)aPublicKey); + CFRelease(cert); + if (status != 0) { + return CryptoX_Error; + } + + return CryptoX_Success; +} + +CryptoX_Result +CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData, + CryptoX_PublicKey* aPublicKey, + const unsigned char* aSignature, + unsigned int aSignatureLen) +{ + if (!aInputData || !*aInputData || !aPublicKey || !*aPublicKey || + !aSignature || aSignatureLen == 0) { + return CryptoX_Error; + } + + if (!OnLionOrLater()) { + if (!sCspHandle) { + return CryptoX_Error; + } + + CSSM_KEY* publicKey; + OSStatus status = SecKeyGetCSSMKey((SecKeyRef)*aPublicKey, + (const CSSM_KEY**)&publicKey); + if (status) { + return CryptoX_Error; + } + + CSSM_CC_HANDLE ccHandle; + if (CSSM_CSP_CreateSignatureContext(sCspHandle, + CSSM_ALGID_SHA1WithRSA, + NULL, + publicKey, + &ccHandle) != CSSM_OK) { + return CryptoX_Error; + } + + CryptoX_Result result = CryptoX_Error; + CSSM_DATA signatureData; + signatureData.Data = (uint8*)aSignature; + signatureData.Length = aSignatureLen; + CSSM_DATA inputData; + inputData.Data = + CFDataGetMutableBytePtr((CFMutableDataRef) + (((CSSM_DATA_PTR)*aInputData)->Data)); + inputData.Length = ((CSSM_DATA_PTR)*aInputData)->Length; + if (CSSM_VerifyData(ccHandle, + &inputData, + 1, + CSSM_ALGID_NONE, + &signatureData) == CSSM_OK) { + result = CryptoX_Success; + } + return result; + } + + CFDataRef signatureData = CFDataCreate(kCFAllocatorDefault, + aSignature, aSignatureLen); + if (!signatureData) { + return CryptoX_Error; + } + + CFErrorRef error; + SecTransformRef verifier = + SecVerifyTransformCreatePtr((SecKeyRef)*aPublicKey, + signatureData, + &error); + if (!verifier || error) { + CFRelease(signatureData); + return CryptoX_Error; + } + + SecTransformSetAttributePtr(verifier, + kSecTransformInputAttributeName, + (CFDataRef)*aInputData, + &error); + if (error) { + CFRelease(signatureData); + CFRelease(verifier); + return CryptoX_Error; + } + + CryptoX_Result result = CryptoX_Error; + CFTypeRef rv = SecTransformExecutePtr(verifier, &error); + if (error) { + CFRelease(signatureData); + CFRelease(verifier); + return CryptoX_Error; + } + + if (CFGetTypeID(rv) == CFBooleanGetTypeID() && + CFBooleanGetValue((CFBooleanRef)rv) == true) { + result = CryptoX_Success; + } + + CFRelease(signatureData); + CFRelease(verifier); + + return result; +} + +void +CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData) +{ + if (!aInputData || !*aInputData) { + return; + } + + CFMutableDataRef inputData = NULL; + if (OnLionOrLater()) { + inputData = (CFMutableDataRef)*aInputData; + } else { + inputData = (CFMutableDataRef)((CSSM_DATA_PTR)*aInputData)->Data; + } + + CFRelease(inputData); + if (!OnLionOrLater()) { + free((CSSM_DATA_PTR)*aInputData); + } +} + +void +CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey) +{ + if (!aPublicKey || !*aPublicKey) { + return; + } + if (!OnLionOrLater() && sCspHandle != CSSM_INVALID_HANDLE) { + CSSM_ModuleDetach(sCspHandle); + sCspHandle = CSSM_INVALID_HANDLE; + } + CFRelease((SecKeyRef)*aPublicKey); +} |