diff common/binverify.c @ 579:f4ce4eef3b38

Implement PKCS#7 embedded signature verfification for windows
author Andre Heinecke <aheinecke@intevation.de>
date Tue, 27 May 2014 10:28:36 +0000
parents
children ecfd77751daf
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/binverify.c	Tue May 27 10:28:36 2014 +0000
@@ -0,0 +1,134 @@
+/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU GPL (v>=2)
+ * and comes with ABSOLUTELY NO WARRANTY!
+ * See LICENSE.txt for details.
+ */
+
+#include "binverify.h"
+
+#include "strhelp.h"
+#include "logging.h"
+
+#ifdef WIN32
+
+#include <windows.h>
+#include <wincrypt.h>
+#include <wintrust.h>
+#include <stdio.h>
+
+bin_verify_result
+verify_binary_win(const char *filename, size_t name_len) {
+  bin_verify_result retval = UnknownError;
+  WCHAR *filenameW = NULL;
+  BOOL result = FALSE;
+  DWORD dwEncoding = 0,
+        dwContentType = 0,
+        dwFormatType = 0,
+        dwSignerInfoSize = 0;
+  HCERTSTORE hStore = NULL;
+  HCRYPTMSG hMsg = NULL;
+  PCERT_INFO pSignerCert = NULL;
+  PCCERT_CONTEXT pSignerCertContext = NULL;
+
+  if (!filename || name_len > MAX_PATH || strlen(filename) != name_len)
+    {
+      ERRORPRINTF ("Invalid parameters\n");
+      return UnknownError;
+    }
+
+  filenameW = utf8_to_wchar(filename, strnlen(filename, MAX_PATH));
+
+  result = CryptQueryObject (CERT_QUERY_OBJECT_FILE,
+                             filenameW,
+                             CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+                             CERT_QUERY_FORMAT_FLAG_BINARY,
+                             0,
+                             &dwEncoding,
+                             &dwContentType,
+                             &dwFormatType,
+                             &hStore,
+                             &hMsg,
+                             NULL);
+
+  if (!result || !hMsg)
+    {
+      PRINTLASTERROR ("Failed to query crypto object");
+      retval = ReadFailed;
+      goto done;
+    }
+
+  /* Get the cert info so that we can look up the signer in the store later */
+  if (CryptMsgGetParam(hMsg,
+                       CMSG_SIGNER_CERT_INFO_PARAM,
+                       0,
+                       NULL,
+                       &dwSignerInfoSize) && dwSignerInfoSize > 0)
+    {
+      pSignerCert = xmalloc (dwSignerInfoSize);
+    }
+  else
+    {
+      ERRORPRINTF ("Failed to get signer cert size.");
+      retval = UnknownError;
+      goto done;
+    }
+
+  if (!(CryptMsgGetParam(hMsg,
+                         CMSG_SIGNER_CERT_INFO_PARAM,
+                         0,
+                         pSignerCert,
+                         &dwSignerInfoSize)))
+    {
+      ERRORPRINTF ("Failed to get signer cert.");
+      retval = UnknownError;
+      goto done;
+    }
+
+  pSignerCertContext = CertGetSubjectCertificateFromStore(
+          hStore,
+          PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+          pSignerCert);
+
+  if (!pSignerCertContext)
+    {
+      ERRORPRINTF ("Failed to find signer cert in store.");
+      retval = UnknownError;
+      goto done;
+    }
+
+  /* Verify that the signature is actually valid */
+  if(CryptMsgControl(hMsg,
+                     0,
+                     CMSG_CTRL_VERIFY_SIGNATURE,
+                     pSignerCertContext->pCertInfo))
+    {
+      DEBUGPRINTF ("Verify signature succeeded. \n");
+      /* TODO pinning*/
+      retval = Valid;
+    } else {
+      ERRORPRINTF ("The signature was not verified. \n");
+      retval = InvalidSignature;
+      goto done;
+    }
+
+done:
+  xfree(filenameW);
+  xfree(pSignerCert);
+
+  if(pSignerCertContext)
+    {
+      CertFreeCertificateContext(pSignerCertContext);
+    }
+  if (hStore)
+    {
+      CertCloseStore(hStore, 0);
+    }
+  if (hMsg)
+    {
+      CryptMsgClose(hMsg);
+    }
+  return retval;
+}
+#endif /* WIN32 */

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