зеркало из https://github.com/mozilla/gecko-dev.git
509 строки
14 KiB
C++
509 строки
14 KiB
C++
/* 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.
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
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;
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#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 = NULL;
|
|
|
|
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,
|
|
CryptoX_PublicKey* aPublicKey)
|
|
{
|
|
if (!aCertData || !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;
|
|
}
|
|
|
|
FILE* certFile = NULL;
|
|
long certFileSize = 0;
|
|
uint8* certBuffer = NULL;
|
|
|
|
certFile = fopen((char*)aCertData, "rb");
|
|
if (!certFile) {
|
|
return CryptoX_Error;
|
|
}
|
|
if (fseek(certFile, 0, SEEK_END)) {
|
|
fclose(certFile);
|
|
return CryptoX_Error;
|
|
}
|
|
certFileSize = ftell(certFile);
|
|
if (certFileSize < 0) {
|
|
fclose(certFile);
|
|
return CryptoX_Error;
|
|
}
|
|
certBuffer = (uint8*)malloc(certFileSize);
|
|
if (fseek(certFile, 0, SEEK_SET)) {
|
|
free(certBuffer);
|
|
fclose(certFile);
|
|
return CryptoX_Error;
|
|
}
|
|
uint readResult = fread(certBuffer, sizeof(uint8), certFileSize, certFile);
|
|
if (readResult != certFileSize) {
|
|
free(certBuffer);
|
|
fclose(certFile);
|
|
return CryptoX_Error;
|
|
}
|
|
fclose(certFile);
|
|
|
|
CFDataRef certData = CFDataCreate(kCFAllocatorDefault,
|
|
certBuffer,
|
|
certFileSize);
|
|
free(certBuffer);
|
|
if (!certData) {
|
|
return CryptoX_Error;
|
|
}
|
|
|
|
SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault,
|
|
certData);
|
|
CFRelease(certData);
|
|
if (!cert) {
|
|
return CryptoX_Error;
|
|
}
|
|
|
|
SecKeyRef publicKey;
|
|
OSStatus status = SecCertificateCopyPublicKey(cert, (SecKeyRef*)&publicKey);
|
|
CFRelease(cert);
|
|
if (status) {
|
|
return CryptoX_Error;
|
|
}
|
|
|
|
*aPublicKey = (void*)publicKey;
|
|
return CryptoX_Success;
|
|
}
|
|
|
|
CFURLRef url =
|
|
CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
|
|
aCertData,
|
|
strlen((char*)aCertData),
|
|
false);
|
|
if (!url) {
|
|
return CryptoX_Error;
|
|
}
|
|
|
|
CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
|
|
if (!stream) {
|
|
CFRelease(url);
|
|
return CryptoX_Error;
|
|
}
|
|
|
|
SecTransformRef readTransform =
|
|
SecTransformCreateReadTransformWithReadStreamPtr(stream);
|
|
if (!readTransform) {
|
|
CFRelease(url);
|
|
CFRelease(stream);
|
|
return CryptoX_Error;
|
|
}
|
|
|
|
CFErrorRef error;
|
|
CFDataRef tempCertData = (CFDataRef)SecTransformExecutePtr(readTransform,
|
|
&error);
|
|
if (!tempCertData || error) {
|
|
CFRelease(url);
|
|
CFRelease(stream);
|
|
CFRelease(readTransform);
|
|
return CryptoX_Error;
|
|
}
|
|
|
|
SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault,
|
|
tempCertData);
|
|
if (!cert) {
|
|
CFRelease(url);
|
|
CFRelease(stream);
|
|
CFRelease(readTransform);
|
|
CFRelease(tempCertData);
|
|
return CryptoX_Error;
|
|
}
|
|
|
|
CryptoX_Result result = CryptoX_Error;
|
|
OSStatus status = SecCertificateCopyPublicKey(cert,
|
|
(SecKeyRef*)aPublicKey);
|
|
if (status == 0) {
|
|
result = CryptoX_Success;
|
|
}
|
|
|
|
CFRelease(url);
|
|
CFRelease(stream);
|
|
CFRelease(readTransform);
|
|
CFRelease(tempCertData);
|
|
CFRelease(cert);
|
|
|
|
return result;
|
|
}
|
|
|
|
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_ModuleDetach(sCspHandle);
|
|
sCspHandle = NULL;
|
|
}
|
|
CFRelease((SecKeyRef)*aPublicKey);
|
|
}
|