diff common/binverify.c @ 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 26a18e3c3db4
children be30d50bc4f0
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;
     }
 

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