changeset 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 bf54c9fc0d63
children cf7e82e91875
files common/CMakeLists.txt common/binverify.c common/binverify.h
diffstat 3 files changed, 193 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/common/CMakeLists.txt	Tue May 27 10:27:35 2014 +0000
+++ b/common/CMakeLists.txt	Tue May 27 10:28:36 2014 +0000
@@ -12,6 +12,7 @@
    portpath.c
    strhelp.c
    util.c
+   binverify.c
 )
 
 add_library(trustbridge_common STATIC ${trustbridge_common_src})
--- /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 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/binverify.h	Tue May 27 10:28:36 2014 +0000
@@ -0,0 +1,58 @@
+/* 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.
+ */
+
+#ifndef BINVERIFY_H
+#define BINVERIFY_H
+/* @file binverify.h
+ * @brief Verification of binary files
+ */
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @enum bin_verify_result
+ * @brief Result of a verification
+ */
+typedef enum {
+    Valid = 100, /*! Could be read and signature matched */
+    UnknownError = 1, /*! The expected unexpected */
+    InvalidSignature = 4, /*! Signature was invalid */
+    ReadFailed = 6, /*! File exists but could not read the file */
+} bin_verify_result;
+
+#ifdef WIN32
+/**
+ * @brief verify a binary
+ *
+ * This function checks that a binary is signed by a built
+ * in certificate.
+ *
+ * Caution: This function works on file names only which could
+ * be modified after this check.
+ *
+ * The verification is done using Windows crypto API based on
+ * embedded PKCS 7 "authenticode" signatures embedded into the
+ * file.
+ *
+ * @param[in] filename absolute null terminated UTF-8 encoded path to the file.
+ * @param[in] name_len length of the filename.
+ *
+ * @returns the verification result.
+ */
+bin_verify_result verify_binary_win(const char *filename, size_t name_len);
+#endif /* WIN32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BINVERIFY_H */

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