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