Bug 978597: Implement native MAR verification for OS X 10.6. r=smichaud
authorStephen Pohl <spohl.mozilla.bugs@gmail.com>
Tue, 22 Apr 2014 20:45:59 -0400
changeset 198172 4fca4b6565d87b19402f2cece5aa7e8d380c9299
parent 198171 b06254e402b23951a18a151047a11ef448fd9406
child 198173 0f8076e2165992a141bb0f3c01d9f0147a2a7ee4
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmichaud
bugs978597
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 978597: Implement native MAR verification for OS X 10.6. r=smichaud
modules/libmar/moz.build
modules/libmar/tests/unit/test_sign_verify.js
modules/libmar/tool/mar.c
modules/libmar/tool/moz.build
modules/libmar/verify/MacVerifyCrypto.cpp
modules/libmar/verify/cryptox.h
modules/libmar/verify/mar_verify.c
modules/libmar/verify/moz.build
--- a/modules/libmar/moz.build
+++ b/modules/libmar/moz.build
@@ -8,14 +8,14 @@ DIRS += ['src']
 
 if CONFIG['MOZ_ENABLE_SIGNMAR']:
     DIRS += ['sign', 'verify']
     TEST_DIRS += ['tests']
 elif CONFIG['OS_ARCH'] == 'WINNT':
     # On Windows we don't verify with NSS and updater needs to link to it
     DIRS += ['verify']
 elif CONFIG['OS_ARCH'] == 'Darwin':
-    # On OSX 10.7+ we don't verify with NSS and updater needs to link to it
+    # On OSX we don't verify with NSS and updater needs to link to it.
     DIRS += ['verify']
 
 # If we are building ./sign and ./verify then ./tool must come after it
 DIRS += ['tool']
 
--- a/modules/libmar/tests/unit/test_sign_verify.js
+++ b/modules/libmar/tests/unit/test_sign_verify.js
@@ -20,17 +20,17 @@ function run_test() {
     do_check_true(signmarBin.isExecutable());
 
     // Setup the command line arguments to sign the MAR.
     let NSSConfigDir = do_get_file("data");
     let args = ["-d", NSSConfigDir.path];
     if (certs.length == 1 && useShortHandCmdLine) {
       args.push("-n", certs[0]);
     } else {
-      for (i = 0; i < certs.length; i++) {
+      for (var i = 0; i < certs.length; i++) {
         args.push("-n" + i, certs[i]);
       }
     }
     args.push("-s", inMAR.path, outMAR.path);
 
     process.init(signmarBin);
     try {
       process.run(true, args, args.length);
@@ -145,39 +145,38 @@ function run_test() {
     // The XPCShell test wiki indicates this is the preferred way for
     // Windows and OSX detection.
     var isWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
     var isOSX = ("nsILocalFileMac" in Components.interfaces);
 
     // Setup the command line arguments to create the MAR.
     // Windows & Mac vs. Linux/... have different command line for verification
     // since on Windows we verify with CryptoAPI, on Mac with Security
-    // Transforms or NSS and on all other platforms we verify with NSS. So on
-    // Windows and Mac we use an exported DER file and on other platforms we use
-    // the NSS config db.
-    if (!isWindows) {
+    // Transforms or CDSA/CSSM and on all other platforms we verify with NSS. So
+    // on Windows and Mac we use an exported DER file and on other platforms we
+    // use the NSS config db.
+    if (isWindows || isOSX) {
+      if (certs.length == 1 && useShortHandCmdLine) {
+        args.push("-D", "data/" + certs[0] + ".der");
+      } else {
+        for (var i = 0; i < certs.length; i++) {
+          args.push("-D" + i, "data/" + certs[i] + ".der");
+        }
+      }
+    } else {
       let NSSConfigDir = do_get_file("data");
       args = ["-d", NSSConfigDir.path];
       if (certs.length == 1 && useShortHandCmdLine) {
         args.push("-n", certs[0]);
       } else {
         for (var i = 0; i < certs.length; i++) {
           args.push("-n" + i, certs[i]);
         }
       }
     }
-    if (isWindows || isOSX) {
-      if (certs.length == 1 && useShortHandCmdLine) {
-        args.push("-D", "data/" + certs[0] + ".der");
-      } else {
-        for (var i = 0; i < certs.length; i++) {
-          args.push("-D" + i, "data/" + certs[i] + ".der");
-        }
-      }
-    }
     args.push("-v", signedMAR.path);
 
     process.init(signmarBin);
     try {
       // We put this in a try block because nsIProcess doesn't like -1 returns
       process.run(true, args, args.length);
     } catch (e) {
       // On Windows negative return value throws an exception
--- a/modules/libmar/tool/mar.c
+++ b/modules/libmar/tool/mar.c
@@ -54,29 +54,21 @@ static void print_usage() {
   printf("  mar [-C workingDir] -n(i) -X "
          "signed_input_archive.mar base_64_encoded_signature_file\n");
 
   printf("Import a MAR signature:\n");
   printf("  mar [-C workingDir] -n(i) -I "
          "signed_input_archive.mar base_64_encoded_signature_file "
          "changed_signed_output.mar\n");
   printf("(i) is the index of the certificate to extract\n");
-#if defined(XP_WIN) && !defined(MAR_NSS)
+#if defined(XP_MACOSX) || (defined(XP_WIN) && !defined(MAR_NSS))
   printf("Verify a MAR file:\n");
   printf("  mar [-C workingDir] -D DERFilePath -v signed_archive.mar\n");
   printf("At most %d signature certificate DER files are specified by "
          "-D0 DERFilePath1 -D1 DERFilePath2, ...\n", MAX_SIGNATURES);
-#elif defined(XP_MACOSX)
-  printf("Verify a MAR file:\n");
-  printf("  mar [-C workingDir] -d NSSConfigDir -n certname "
-         "-v signed_archive.mar -D DERFilePath\n");
-  printf("At most %d signature certificate names are specified by "
-         "-n0 certName -n1 certName2, ...\n", MAX_SIGNATURES);
-  printf("At most %d signature certificate DER files are specified by "
-         "-D0 DERFilePath1 -D1 DERFilePath2, ...\n", MAX_SIGNATURES);
 #else
   printf("Verify a MAR file:\n");
   printf("  mar [-C workingDir] -d NSSConfigDir -n certname "
          "-v signed_archive.mar\n");
   printf("At most %d signature certificate names are specified by "
          "-n0 certName -n1 certName2, ...\n", MAX_SIGNATURES);
 #endif
   printf("At most %d verification certificate names are specified by "
@@ -121,39 +113,38 @@ static int mar_test(const char *path) {
 int main(int argc, char **argv) {
   char *NSSConfigDir = NULL;
   const char *certNames[MAX_SIGNATURES];
   char *MARChannelID = MAR_CHANNEL_ID;
   char *productVersion = MOZ_APP_VERSION;
   uint32_t i, k;
   int rv = -1;
   uint32_t certCount = 0;
-  uint32_t derCount = 0;
   int32_t sigIndex = -1;
-  char* DERFilePaths[MAX_SIGNATURES];
 
 #if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
   HANDLE certFile;
   uint8_t *certBuffers[MAX_SIGNATURES];
 #endif
 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
                                  defined(XP_MACOSX))
+  char* DERFilePaths[MAX_SIGNATURES];
   uint32_t fileSizes[MAX_SIGNATURES];
   uint32_t read;
 #endif
 
   memset(certNames, 0, sizeof(certNames));
 #if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
   memset(certBuffers, 0, sizeof(certBuffers));
 #endif
 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
                                  defined(XP_MACOSX))
+  memset(DERFilePaths, 0, sizeof(DERFilePaths));
   memset(fileSizes, 0, sizeof(fileSizes));
 #endif
-  memset(DERFilePaths, 0, sizeof(DERFilePaths));
 
   if (argc > 1 && 0 == strcmp(argv[1], "--version")) {
     print_version();
     return 0;
   }
 
   if (argc < 3) {
     print_usage();
@@ -176,22 +167,22 @@ int main(int argc, char **argv) {
     } 
 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
                                  defined(XP_MACOSX))
     /* -D DERFilePath, also matches -D[index] DERFilePath
        We allow an index for verifying to be symmetric
        with the import and export command line arguments. */
     else if (argv[1][0] == '-' &&
              argv[1][1] == 'D' &&
-             (argv[1][2] == (char)('0' + derCount) || argv[1][2] == '\0')) {
-      if (derCount >= MAX_SIGNATURES) {
+             (argv[1][2] == (char)('0' + certCount) || argv[1][2] == '\0')) {
+      if (certCount >= MAX_SIGNATURES) {
         print_usage();
         return -1;
       }
-      DERFilePaths[derCount++] = argv[2];
+      DERFilePaths[certCount++] = argv[2];
       argv += 2;
       argc -= 2;
     }
 #endif
     /* -d NSSConfigdir */
     else if (argv[1][0] == '-' && argv[1][1] == 'd') {
       NSSConfigDir = argv[2];
       argv += 2;
@@ -325,22 +316,22 @@ int main(int argc, char **argv) {
       print_usage();
       return -1;
     }
     return import_signature(argv[2], sigIndex, argv[3], argv[4]);
 
   case 'v':
 
 #if defined(XP_WIN) && !defined(MAR_NSS)
-    if (derCount == 0) {
+    if (certCount == 0) {
       print_usage();
       return -1;
     }
 
-    for (k = 0; k < derCount; ++k) {
+    for (k = 0; k < certCount; ++k) {
       /* If the mar program was built using CryptoAPI, then read in the buffer
         containing the cert from disk. */
       certFile = CreateFileA(DERFilePaths[k], GENERIC_READ,
                              FILE_SHARE_READ |
                              FILE_SHARE_WRITE |
                              FILE_SHARE_DELETE,
                              NULL,
                              OPEN_EXISTING,
@@ -357,18 +348,18 @@ int main(int argc, char **argv) {
           free(certBuffers[i]);
         }
         return -1;
       }
       CloseHandle(certFile);
     }
 
     rv = mar_verify_signatures(argv[2], certBuffers, fileSizes,
-                               NULL, derCount);
-    for (k = 0; k < derCount; ++k) {
+                               NULL, certCount);
+    for (k = 0; k < certCount; ++k) {
       free(certBuffers[k]);
     }
     if (rv) {
       /* Determine if the source MAR file has the new fields for signing */
       int hasSignatureBlock;
       if (get_mar_file_info(argv[2], &hasSignatureBlock, 
                             NULL, NULL, NULL, NULL)) {
         fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
@@ -376,29 +367,31 @@ int main(int argc, char **argv) {
         fprintf(stderr, "ERROR: The MAR file is in the old format so has"
                         " no signature to verify.\n");
       }
       return -1;
     }
 
     return 0;
 
+#elif defined(XP_MACOSX)
+    return mar_verify_signatures(argv[2], (const uint8_t* const*)DERFilePaths,
+                                 0, NULL, certCount);
 #else
     if (!NSSConfigDir || certCount == 0) {
       print_usage();
       return -1;
     }
 
     if (NSSInitCryptoContext(NSSConfigDir)) {
       fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
       return -1;
     }
 
-    return mar_verify_signatures(argv[2], (const uint8_t* const*)DERFilePaths,
-                                 0, certNames, certCount);
+    return mar_verify_signatures(argv[2], NULL, 0, certNames, certCount);
 
 #endif /* defined(XP_WIN) && !defined(MAR_NSS) */
   case 's':
     if (!NSSConfigDir || certCount == 0 || argc < 4) {
       print_usage();
       return -1;
     }
     return mar_repackage_and_sign(NSSConfigDir, certNames, certCount,
--- a/modules/libmar/tool/moz.build
+++ b/modules/libmar/tool/moz.build
@@ -17,8 +17,12 @@ HOST_PROGRAM = 'mar'
 for var in ('MAR_CHANNEL_ID', 'MOZ_APP_VERSION'):
     DEFINES[var] = '"%s"' % CONFIG[var]
 
 if not CONFIG['MOZ_ENABLE_SIGNMAR']:
     DEFINES['NO_SIGN_VERIFY'] = True
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     USE_STATIC_LIBS = True
+elif CONFIG['OS_ARCH'] == 'Darwin':
+    LDFLAGS += [
+      '-framework Security',
+    ]
--- a/modules/libmar/verify/MacVerifyCrypto.cpp
+++ b/modules/libmar/verify/MacVerifyCrypto.cpp
@@ -29,24 +29,16 @@ extern "C" {
                                                           CFDataRef signature,
                                                           CFErrorRef* error);
   SecVerifyTransformCreateFunc SecVerifyTransformCreatePtr = NULL;
   typedef Boolean (*SecTransformSetAttributeFunc)(SecTransformRef transform,
                                                   CFStringRef key,
                                                   CFTypeRef value,
                                                   CFErrorRef* error);
   SecTransformSetAttributeFunc SecTransformSetAttributePtr = NULL;
-  typedef SecCertificateRef (*SecCertificateCreateWithDataFunc)
-                              (CFAllocatorRef allocator,
-                               CFDataRef data);
-  SecCertificateCreateWithDataFunc SecCertificateCreateWithDataPtr = NULL;
-  typedef OSStatus (*SecCertificateCopyPublicKeyFunc)
-                     (SecCertificateRef certificate,
-                      SecKeyRef* key);
-  SecCertificateCopyPublicKeyFunc SecCertificateCopyPublicKeyPtr = NULL;
 #ifdef __cplusplus
 }
 #endif
 
 #define MAC_OS_X_VERSION_10_7_HEX 0x00001070
 
 static int sOnLionOrLater = -1;
 
@@ -93,16 +85,52 @@ static bool OnLionOrLater()
       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) {
@@ -117,99 +145,183 @@ CryptoMac_InitCryptoProvider()
   if (!SecVerifyTransformCreatePtr) {
     SecVerifyTransformCreatePtr = (SecVerifyTransformCreateFunc)
       dlsym(RTLD_DEFAULT, "SecVerifyTransformCreate");
   }
   if (!SecTransformSetAttributePtr) {
     SecTransformSetAttributePtr = (SecTransformSetAttributeFunc)
       dlsym(RTLD_DEFAULT, "SecTransformSetAttribute");
   }
-  if (!SecCertificateCreateWithDataPtr) {
-    SecCertificateCreateWithDataPtr = (SecCertificateCreateWithDataFunc)
-      dlsym(RTLD_DEFAULT, "SecCertificateCreateWithData");
-  }
-  if (!SecCertificateCopyPublicKeyPtr) {
-    SecCertificateCopyPublicKeyPtr = (SecCertificateCopyPublicKeyFunc)
-      dlsym(RTLD_DEFAULT, "SecCertificateCopyPublicKey");
-  }
   if (!SecTransformCreateReadTransformWithReadStreamPtr ||
       !SecTransformExecutePtr ||
       !SecVerifyTransformCreatePtr ||
-      !SecTransformSetAttributePtr ||
-      !SecCertificateCreateWithDataPtr ||
-      !SecCertificateCopyPublicKeyPtr) {
+      !SecTransformSetAttributePtr) {
     return CryptoX_Error;
   }
   return CryptoX_Success;
 }
 
 CryptoX_Result
-CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData,
-                      CryptoX_PublicKey* aPublicKey)
+CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData)
 {
-  if (!OnLionOrLater()) {
-    return NSS_VerifyBegin((VFYContext**)aInputData,
-                           (SECKEYPublicKey* const*)aPublicKey);
-  }
-
-  (void)aPublicKey;
   if (!aInputData) {
     return CryptoX_Error;
   }
 
-  CryptoX_Result result = CryptoX_Error;
-  *aInputData = CFDataCreateMutable(kCFAllocatorDefault, 0);
-  if (*aInputData) {
-    result = CryptoX_Success;
+  void* inputData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+  if (!inputData) {
+    return CryptoX_Error;
   }
 
-  return result;
+  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 (!OnLionOrLater()) {
-    return VFY_Update((VFYContext*)*aInputData,
-                      (const unsigned char*)aBuf, aLen);
-  }
-
   if (aLen == 0) {
     return CryptoX_Success;
   }
   if (!aInputData || !*aInputData) {
     return CryptoX_Error;
   }
 
-  CryptoX_Result result = CryptoX_Error;
-  CFDataAppendBytes((CFMutableDataRef)*aInputData, (const UInt8 *) aBuf, aLen);
-  if (*aInputData) {
-    result = CryptoX_Success;
+  CFMutableDataRef inputData;
+  if (!OnLionOrLater()) {
+    inputData = (CFMutableDataRef)((CSSM_DATA_PTR)*aInputData)->Data;
+    ((CSSM_DATA_PTR)*aInputData)->Length += aLen;
+  } else {
+    inputData = (CFMutableDataRef)*aInputData;
   }
 
-  return result;
+  CFDataAppendBytes(inputData, (const uint8*)aBuf, aLen);
+  return CryptoX_Success;
 }
 
 CryptoX_Result
 CryptoMac_LoadPublicKey(const unsigned char* aCertData,
-                        CryptoX_PublicKey* aPublicKey,
-                        const char* aCertName,
-                        CryptoX_Certificate* aCert)
+                        CryptoX_PublicKey* aPublicKey)
 {
-  if (!aPublicKey ||
-      (OnLionOrLater() && !aCertData) ||
-      (!OnLionOrLater() && !aCertName)) {
+  if (!aCertData || !aPublicKey) {
     return CryptoX_Error;
   }
+  *aPublicKey = NULL;
 
   if (!OnLionOrLater()) {
-    return NSS_LoadPublicKey(aCertName,
-                             (SECKEYPublicKey**)aPublicKey,
-                             (CERTCertificate**)aCert);
+    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) {
@@ -235,29 +347,29 @@ CryptoMac_LoadPublicKey(const unsigned c
                                                              &error);
   if (!tempCertData || error) {
     CFRelease(url);
     CFRelease(stream);
     CFRelease(readTransform);
     return CryptoX_Error;
   }
 
-  SecCertificateRef cert = SecCertificateCreateWithDataPtr(kCFAllocatorDefault,
-                                                           tempCertData);
+  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 = SecCertificateCopyPublicKeyPtr(cert,
-                                                   (SecKeyRef*)aPublicKey);
+  OSStatus status = SecCertificateCopyPublicKey(cert,
+                                                (SecKeyRef*)aPublicKey);
   if (status == 0) {
     result = CryptoX_Success;
   }
 
   CFRelease(url);
   CFRelease(stream);
   CFRelease(readTransform);
   CFRelease(tempCertData);
@@ -267,26 +379,61 @@ CryptoMac_LoadPublicKey(const unsigned c
 }
 
 CryptoX_Result
 CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData,
                           CryptoX_PublicKey* aPublicKey,
                           const unsigned char* aSignature,
                           unsigned int aSignatureLen)
 {
-  if (!OnLionOrLater()) {
-    return NSS_VerifySignature((VFYContext* const*)aInputData, aSignature,
-                               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 =
@@ -325,43 +472,37 @@ CryptoMac_VerifySignature(CryptoX_Signat
   CFRelease(verifier);
 
   return result;
 }
 
 void
 CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData)
 {
-  if (!OnLionOrLater()) {
-    return VFY_DestroyContext((VFYContext*)aInputData, PR_TRUE);
-  }
-
   if (!aInputData || !*aInputData) {
     return;
   }
-  CFRelease((CFMutableDataRef)*aInputData);
+
+  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 (!OnLionOrLater()) {
-    return SECKEY_DestroyPublicKey((SECKEYPublicKey*)*aPublicKey);
-  }
-
   if (!aPublicKey || !*aPublicKey) {
     return;
   }
+  if (!OnLionOrLater() && sCspHandle) {
+    CSSM_ModuleDetach(sCspHandle);
+    sCspHandle = NULL;
+  }
   CFRelease((SecKeyRef)*aPublicKey);
 }
-
-void
-CryptoMac_FreeCertificate(CryptoX_Certificate* aCertificate)
-{
-  if (!OnLionOrLater()) {
-    return CERT_DestroyCertificate((CERTCertificate*)*aCertificate);
-  }
-
-  if (!aCertificate || !*aCertificate) {
-    return;
-  }
-  CFRelease((SecKeyRef)*aCertificate);
-}
--- a/modules/libmar/verify/cryptox.h
+++ b/modules/libmar/verify/cryptox.h
@@ -14,105 +14,98 @@
 #define CryptoX_Failed(X) ((X) != CryptoX_Success)
 
 #if defined(MAR_NSS)
 
 #include "nss_secutil.h"
 
 #define CryptoX_InvalidHandleValue NULL
 #define CryptoX_ProviderHandle void*
+#define CryptoX_SignatureHandle VFYContext *
+#define CryptoX_PublicKey SECKEYPublicKey *
+#define CryptoX_Certificate CERTCertificate *
 
 #ifdef __cplusplus
 extern "C" {
 #endif
-CryptoX_Result NSS_LoadPublicKey(const char *certNickname, 
-                                 SECKEYPublicKey **publicKey, 
+CryptoX_Result NSS_LoadPublicKey(const char *certNickname,
+                                 SECKEYPublicKey **publicKey,
                                  CERTCertificate **cert);
-CryptoX_Result NSS_VerifyBegin(VFYContext **ctx, 
+CryptoX_Result NSS_VerifyBegin(VFYContext **ctx,
                                SECKEYPublicKey * const *publicKey);
-CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx , 
-                                   const unsigned char *signature, 
+CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx ,
+                                   const unsigned char *signature,
                                    unsigned int signatureLen);
 #ifdef __cplusplus
 } // extern "C"
 #endif
 
-#ifdef XP_MACOSX
-
-#define CryptoX_SignatureHandle void*
-#define CryptoX_PublicKey void*
-#define CryptoX_Certificate void*
-
-// Forward-declare Objective-C functions implemented in MacVerifyCrypto.mm.
-#ifdef __cplusplus
-extern "C" {
-#endif
-CryptoX_Result CryptoMac_InitCryptoProvider();
-CryptoX_Result CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData,
-                                     CryptoX_PublicKey* aPublicKey);
-CryptoX_Result CryptoMac_VerifyUpdate(CryptoX_SignatureHandle* aInputData,
-                                      void* aBuf, unsigned int aLen);
-CryptoX_Result CryptoMac_LoadPublicKey(const unsigned char* aCertData,
-                                       CryptoX_PublicKey* aPublicKey,
-                                       const char* aCertName,
-                                       CryptoX_Certificate* aCert);
-CryptoX_Result CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData,
-                                         CryptoX_PublicKey* aPublicKey,
-                                         const unsigned char* aSignature,
-                                         unsigned int aSignatureLen);
-void CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData);
-void CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey);
-void CryptoMac_FreeCertificate(CryptoX_Certificate* aCertificate);
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#define CryptoX_InitCryptoProvider(aCryptoHandle) \
-  CryptoMac_InitCryptoProvider()
-#define CryptoX_VerifyBegin(aCryptoHandle, aInputData, aPublicKey) \
-  CryptoMac_VerifyBegin(aInputData, aPublicKey)
-#define CryptoX_VerifyUpdate(aInputData, aBuf, aLen) \
-  CryptoMac_VerifyUpdate(aInputData, aBuf, aLen)
-#define CryptoX_LoadPublicKey(aCryptoHandle, aCertData, aDataSize, \
-                              aPublicKey, aCertName, aCert) \
-  CryptoMac_LoadPublicKey(aCertData, aPublicKey, aCertName, aCert)
-#define CryptoX_VerifySignature(aInputData, aPublicKey, aSignature, \
-                                aSignatureLen) \
-  CryptoMac_VerifySignature(aInputData, aPublicKey, aSignature, aSignatureLen)
-#define CryptoX_FreeSignatureHandle(aInputData) \
-  CryptoMac_FreeSignatureHandle(aInputData)
-#define CryptoX_FreePublicKey(aPublicKey) \
-  CryptoMac_FreePublicKey(aPublicKey)
-#define CryptoX_FreeCertificate(aCertificate) \
-  CryptoMac_FreeCertificate(aCertificate)
-
-#else
-
-#define CryptoX_SignatureHandle VFYContext *
-#define CryptoX_PublicKey SECKEYPublicKey *
-#define CryptoX_Certificate CERTCertificate *
 #define CryptoX_InitCryptoProvider(CryptoHandle) \
   CryptoX_Success
 #define CryptoX_VerifyBegin(CryptoHandle, SignatureHandle, PublicKey) \
   NSS_VerifyBegin(SignatureHandle, PublicKey)
 #define CryptoX_FreeSignatureHandle(SignatureHandle) \
-  VFY_DestroyContext(SignatureHandle, PR_TRUE)
+  VFY_DestroyContext(*SignatureHandle, PR_TRUE)
 #define CryptoX_VerifyUpdate(SignatureHandle, buf, len) \
   VFY_Update(*SignatureHandle, (const unsigned char*)(buf), len)
 #define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
                               publicKey, certName, cert) \
   NSS_LoadPublicKey(certName, publicKey, cert)
 #define CryptoX_VerifySignature(hash, publicKey, signedData, len) \
   NSS_VerifySignature(hash, (const unsigned char *)(signedData), len)
 #define CryptoX_FreePublicKey(key) \
   SECKEY_DestroyPublicKey(*key)
 #define CryptoX_FreeCertificate(cert) \
   CERT_DestroyCertificate(*cert)
 
+#elif XP_MACOSX
+
+#define CryptoX_InvalidHandleValue NULL
+#define CryptoX_ProviderHandle void*
+#define CryptoX_SignatureHandle void*
+#define CryptoX_PublicKey void*
+#define CryptoX_Certificate void*
+
+// Forward-declare Objective-C functions implemented in MacVerifyCrypto.mm.
+#ifdef __cplusplus
+extern "C" {
 #endif
+CryptoX_Result CryptoMac_InitCryptoProvider();
+CryptoX_Result CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData);
+CryptoX_Result CryptoMac_VerifyUpdate(CryptoX_SignatureHandle* aInputData,
+                                      void* aBuf, unsigned int aLen);
+CryptoX_Result CryptoMac_LoadPublicKey(const unsigned char* aCertData,
+                                       CryptoX_PublicKey* aPublicKey);
+CryptoX_Result CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData,
+                                         CryptoX_PublicKey* aPublicKey,
+                                         const unsigned char* aSignature,
+                                         unsigned int aSignatureLen);
+void CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData);
+void CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#define CryptoX_InitCryptoProvider(aProviderHandle) \
+  CryptoMac_InitCryptoProvider()
+#define CryptoX_VerifyBegin(aCryptoHandle, aInputData, aPublicKey) \
+  CryptoMac_VerifyBegin(aInputData)
+#define CryptoX_VerifyUpdate(aInputData, aBuf, aLen) \
+  CryptoMac_VerifyUpdate(aInputData, aBuf, aLen)
+#define CryptoX_LoadPublicKey(aProviderHandle, aCertData, aDataSize, \
+                              aPublicKey, aCertName, aCert) \
+  CryptoMac_LoadPublicKey(aCertData, aPublicKey)
+#define CryptoX_VerifySignature(aInputData, aPublicKey, aSignature, \
+                                aSignatureLen) \
+  CryptoMac_VerifySignature(aInputData, aPublicKey, aSignature, aSignatureLen)
+#define CryptoX_FreeSignatureHandle(aInputData) \
+  CryptoMac_FreeSignatureHandle(aInputData)
+#define CryptoX_FreePublicKey(aPublicKey) \
+  CryptoMac_FreePublicKey(aPublicKey)
+#define CryptoX_FreeCertificate(aCertificate)
 
 #elif defined(XP_WIN) 
 
 #include <windows.h>
 #include <wincrypt.h>
 
 CryptoX_Result CryptoAPI_InitCryptoContext(HCRYPTPROV *provider);
 CryptoX_Result CryptoAPI_LoadPublicKey(HCRYPTPROV hProv, 
--- a/modules/libmar/verify/mar_verify.c
+++ b/modules/libmar/verify/mar_verify.c
@@ -503,13 +503,13 @@ mar_verify_signatures_for_fp(FILE *fp,
       goto failure;
     }
     ++*numVerified;
   }
 
   rv = CryptoX_Success;
 failure:
   for (i = 0; i < signatureCount; i++) {
-    CryptoX_FreeSignatureHandle(signatureHandles[i]);
+    CryptoX_FreeSignatureHandle(&signatureHandles[i]);
   }
 
   return rv;
 }
--- a/modules/libmar/verify/moz.build
+++ b/modules/libmar/verify/moz.build
@@ -10,21 +10,23 @@ UNIFIED_SOURCES += [
     'cryptox.c',
     'mar_verify.c',
 ]
 
 FORCE_STATIC_LIB = True
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     USE_STATIC_LIBS = True
+elif CONFIG['OS_ARCH'] == 'Darwin':
+    UNIFIED_SOURCES += [
+      'MacVerifyCrypto.cpp',
+    ]
+    LDFLAGS += [
+      '-framework Security',
+    ]
 else:
     DEFINES['MAR_NSS'] = True
     LOCAL_INCLUDES += ['../sign']
 
-if CONFIG['OS_ARCH'] == 'Darwin':
-    UNIFIED_SOURCES += [
-      'MacVerifyCrypto.cpp',
-    ]
-
 LOCAL_INCLUDES += [
     '../src',
 ]