changeset 629:facb13c578f1

Add certificate pinning to verify_binary_win
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 23 Jun 2014 13:04:34 +0200
parents f595fcbe3e76
children aa48ea7ead1f
files common/binverify.c common/binverify.h common/pubkey-test.h
diffstat 3 files changed, 129 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/common/binverify.c	Fri Jun 20 14:29:05 2014 +0200
+++ b/common/binverify.c	Mon Jun 23 13:04:34 2014 +0200
@@ -11,6 +11,12 @@
 #include "strhelp.h"
 #include "logging.h"
 
+#ifdef RELEASE_BUILD
+#include "pubkey-release.h"
+#else
+#include "pubkey-test.h"
+#endif
+
 bin_verify_result
 verify_binary(const char *filename, size_t name_len) {
 #ifdef WIN32
@@ -25,11 +31,74 @@
 
 #ifdef WIN32
 
+#include <polarssl/x509_crt.h>
+
 #include <windows.h>
 #include <wincrypt.h>
 #include <wintrust.h>
 #include <stdio.h>
 
+
+/** @brief Check if the certificate @a pCCertContext is pinned
+  *
+  * Compares the certificate's binary data (public key and attributes)
+  * with each other to validate that the certificate pCCertContext has
+  * exactly the same data as the builtin public certificate.
+  *
+  * @param[in] pCCertContext pointer to the certificate to check
+  *
+  * @returns true if the certificate matches, false otherwise.
+  */
+static bool
+check_certificate (PCCERT_CONTEXT pCCertContext)
+{
+  x509_crt codesign_cert;
+  int ret = 0;
+  DWORD dwI = 0;
+  bool retval = false;
+
+  if (pCCertContext == NULL)
+    {
+      ERRORPRINTF ("Invalid call to check_certificate");
+      return false;
+    }
+
+  x509_crt_init(&codesign_cert);
+
+  /* Parse the pinned certificate */
+  ret = x509_crt_parse(&codesign_cert,
+                       public_key_codesign_pem,
+                       public_key_codesign_pem_size);
+  if (ret != 0)
+    {
+      ERRORPRINTF ("x509_crt_parse failed with -0x%04x\n\n", -ret);
+      goto done;
+    }
+
+  if (codesign_cert.raw.len != pCCertContext->cbCertEncoded ||
+      codesign_cert.raw.len <= 0)
+    {
+      ERRORPRINTF ("Certificate size mismatch");
+      goto done;
+    }
+
+  /* Check that the certificate is exactly the same as the pinned one */
+  for (dwI = 0; dwI < pCCertContext->cbCertEncoded; dwI++)
+    {
+      if (pCCertContext->pbCertEncoded[dwI] != codesign_cert.raw.p[dwI])
+        {
+          ERRORPRINTF ("Certificate content mismatch");
+          goto done;
+        }
+    }
+
+  retval = true;
+
+done:
+  x509_crt_free(&codesign_cert);
+  return retval;
+}
+
 bin_verify_result
 verify_binary_win(const char *filename, size_t name_len) {
   bin_verify_result retval = VerifyUnknownError;
@@ -111,17 +180,29 @@
     }
 
   /* Verify that the signature is actually valid */
-  if(CryptMsgControl(hMsg,
-                     0,
-                     CMSG_CTRL_VERIFY_SIGNATURE,
-                     pSignerCertContext->pCertInfo))
+  if(!CryptMsgControl(hMsg,
+                      0,
+                      CMSG_CTRL_VERIFY_SIGNATURE,
+                      pSignerCertContext->pCertInfo))
     {
-      DEBUGPRINTF ("Verify signature succeeded. \n");
-      /* TODO pinning*/
+      ERRORPRINTF ("The signature is invalid. \n");
+      retval = VerifyInvalidSignature;
+      syslog_error_printf ("Software update embedded signature is invalid.");
+      goto done;
+    }
+
+  if(check_certificate(pSignerCertContext))
+    {
+      DEBUGPRINTF ("Valid signature with pinned certificate.");
       retval = VerifyValid;
-    } else {
-      ERRORPRINTF ("The signature was not verified. \n");
+      goto done;
+    }
+  else
+    {
+      ERRORPRINTF ("Certificate mismatch. \n");
       retval = VerifyInvalidSignature;
+      syslog_error_printf ("Software update embedded signature "
+                           "created with wrong certificate.");
       goto done;
     }
 
--- a/common/binverify.h	Fri Jun 20 14:29:05 2014 +0200
+++ b/common/binverify.h	Mon Jun 23 13:04:34 2014 +0200
@@ -26,6 +26,7 @@
     VerifyValid = 100, /*! Could be read and signature matched */
     VerifyUnknownError = 1, /*! The expected unexpected */
     VerifyInvalidSignature = 4, /*! Signature was invalid */
+    VerifyInvalidCertificate = 5, /*! Certificate mismatch */
     VerifyReadFailed = 6, /*! File exists but could not read the file */
 } bin_verify_result;
 
--- a/common/pubkey-test.h	Fri Jun 20 14:29:05 2014 +0200
+++ b/common/pubkey-test.h	Mon Jun 23 13:04:34 2014 +0200
@@ -23,4 +23,43 @@
 "-----END PUBLIC KEY-----\n";
 
 static const size_t public_key_pem_size = 625;
+
+/* Key used for codesigning */
+static const unsigned char public_key_codesign_pem[] =
+"-----BEGIN CERTIFICATE-----\n"
+"MIIFqTCCA5GgAwIBAgIBATANBgkqhkiG9w0BAQUFADBZMSAwHgYDVQQDExdQdWJs\n"
+"aWMgVHJ1c3RCcmlkZ2UgVGVzdDEoMCYGA1UEChMfUHVibGljIHNlY3JldCBkbyBu\n"
+"b3QgdHJ1c3QgdGhpczELMAkGA1UEBhMCREUwHhcNMTMwMTAxMDAwMDAwWhcNMTUx\n"
+"MjMxMjM1OTU5WjBlMSwwKgYDVQQDEyNQdWJsaWMgVHJ1c3RCcmlkZ2UgY29kZXNp\n"
+"Z25pbmcgdGVzdDEoMCYGA1UEChMfUHVibGljIHNlY3JldCBkbyBub3QgdHJ1c3Qg\n"
+"dGhpczELMAkGA1UEBhMCREUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\n"
+"AQDIz9IetAtdqJJ7aSfJcLmA9Mb4nxrqEJ5E6PMejDJZmmHNjyhCVp1qsLYmyC60\n"
+"m7qJ4OBENx0v2n5LiCUHJpJ4mzAklkWn1GffUkzWgQ2VHw5Nr44NWEwkUUa5/jT7\n"
+"Sxts2DWuaLz2r7oi6BUQpoRmQRPwwzFPONcCSw9iAvTU6oVI2jW1opEW3t10UwY3\n"
+"5/muryPsUz6y5VkBIc73VC0wByXoAruEPBBpMgOVw1+npOaJ1PL1XXQ/P6xziZo0\n"
+"Ab/tKvN6IpEHrNEGv1gScJt//pKKklvIyXm9UdIY9XpB6aauzthKpTFJXGYySlXx\n"
+"bD1a5sq0i2sAK/p8RvErVWg3EfBlUrQryJxONPVqribczZIWcgKVEFfXjX1tQqiC\n"
+"qRCgO4M6zhNIKLkAicp0DvYs8M4hIoPng98nqK6kSpfXR6Y4b9DU3yEktH7wGrwL\n"
+"jKATVM2l2yTF17Pjxkr2tH0XWrChfS+oV6Qzm9JQ/vmLKz5piLKpt5SXuZny+j0Y\n"
+"68ch709sVTuuPm4RAm5c5t0SCwEippClFpkZynYRsJVrjG9ZTrdvULxZao8GBzJx\n"
+"Lb+tCaKP60BRoUuRfwGMKZbU6j6ujOCy5bZIoJaKgHgyAHXRuS4PIjY9K2BGM5vI\n"
+"seA2GEdAJNmZPAQJE5rxkrsAH9n8QtmHucEqzCZVFcLuCwIDAQABo3AwbjAJBgNV\n"
+"HRMEAjAAMB0GA1UdDgQWBBSMgUaKY3L65wH5M4il/gbHCeVm4TAfBgNVHSMEGDAW\n"
+"gBTl/kZGRoa0cm82zW7CPn3yqk4MeTAOBgNVHQ8BAQEEBAMCAYAwEQYJYIZIAYb4\n"
+"QgEBBAQDAgAQMA0GCSqGSIb3DQEBBQUAA4ICAQAdmpf8k+ZKuhDvNwMCrf1JIZh3\n"
+"uJxlCHFke/ypsMT2E6p/GZpD/lLyRHbk7V5aEYdmBaK6Dem0KYhRuDclWscpQdXl\n"
+"96wx1IDNueMkj5ZDmpBLFl/nqxlM9HfHo8YTE9dRgzJAR8+dFR8HyRSayKo+pz4L\n"
+"FkNFT5Jtm9kKLIN+mSGKMBmpY4owfpeh7K6YyASoOHL9Zk8A0I7iZX8FB5KujrlG\n"
+"WJahjSAyvLvy98XDCf9/SyX73F1ol5ycAb/du+G5VZFDEI8sv/7fIdTx/AUR30Ac\n"
+"f3tqXZ4HwxWc0gofT0J2z/I4FZ/sT/1SNHReGNrG9GNn5bxjwpSXfc5A1bjhRfxd\n"
+"x73xKEInjpgo6AXY7wfNk1V+2z7keVOpaDEZUOsd/x/C+L8FsUh2JJHZp/hKX6Co\n"
+"AD///pxqNfvH5pPLUINC7VRUOTynUas7p9UvkPeJjqnWY6pmjeb4Fs6Z6vn0+Opy\n"
+"HP1MjLL41a+U9VxuNb6SfRDoeT19pqK6ovT2gbc61OvTI0lE97ChC622rjnV0c/N\n"
+"QYqkeTQG/IjPk0QFrYQxMqq6QKgds2nheYd4LyLGhk72pKWr28Hfj1ElcoTFFbWP\n"
+"ndI+uZePkkCsVYNMXbIAIpqLb++1ftl+L+itqxTyq+0tPObIL3WG9rzBGz8X6WT0\n"
+"KIzi4KAn66e5/iWZng==\n"
+"-----END CERTIFICATE-----\n";
+
+static const size_t  public_key_codesign_pem_size = 2025;
+
 #endif

http://wald.intevation.org/projects/trustbridge/