# HG changeset patch # User Andre Heinecke # Date 1401186516 0 # Node ID f4ce4eef3b389e77a0e419a40baa3e768612494f # Parent bf54c9fc0d630aa9bcf1051cd059dbdfbe0433d9 Implement PKCS#7 embedded signature verfification for windows diff -r bf54c9fc0d63 -r f4ce4eef3b38 common/CMakeLists.txt --- 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}) diff -r bf54c9fc0d63 -r f4ce4eef3b38 common/binverify.c --- /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 +#include +#include +#include + +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 */ diff -r bf54c9fc0d63 -r f4ce4eef3b38 common/binverify.h --- /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 +#include + +#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 */