From f66a6b6b4c5f48e99be92500eab1f3a0255a956a Mon Sep 17 00:00:00 2001
From: Gilles Khouzam <gillesk@microsoft.com>
Date: Fri, 21 Aug 2015 14:15:38 -0700
Subject: [PATCH] Add the package certificate thumbprint property when there is
 a certificate on a WindowsStore or Phone app.

---
 Source/CMakeLists.txt                      |  4 +-
 Source/cmSystemTools.cxx                   | 88 ++++++++++++++++++++++++++++++
 Source/cmSystemTools.h                     |  3 +
 Source/cmVisualStudio10TargetGenerator.cxx | 16 +++++-
 4 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 428b364..56cf1aa 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -558,7 +558,9 @@ endif()
 
 if(CMAKE_BUILD_ON_VISUAL_STUDIO OR MINGW)
   # We need the rpcrt4 library for at least the VS7-VC10 generators.
-  target_link_libraries(CMakeLib rpcrt4)
+  # We need the crypt32 library for generating the thumbprint for
+  # Windows Store projects
+  target_link_libraries(CMakeLib rpcrt4 crypt32)
 endif()
 
 #
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index a117238..3780ec0 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1013,6 +1013,94 @@ std::string cmSystemTools::ComputeStringMD5(const std::string& input)
 #endif
 }
 
+//----------------------------------------------------------------------------
+std::string cmSystemTools::ComputeCertificateThumbprint(
+  const std::string& source)
+{
+  std::string thumbprint;
+
+#ifdef _WIN32
+  BYTE* certData = NULL;
+  CRYPT_INTEGER_BLOB cryptBlob;
+  HCERTSTORE certStore = NULL;
+  PCCERT_CONTEXT certContext = NULL;
+
+  HANDLE certFile = CreateFile(cmsys::Encoding::ToWide(source.c_str()).c_str(),
+    GENERIC_READ,
+    FILE_SHARE_READ,
+    NULL,
+    OPEN_EXISTING,
+    FILE_ATTRIBUTE_NORMAL,
+    NULL);
+
+  if (certFile != INVALID_HANDLE_VALUE && certFile != NULL)
+    {
+    DWORD fileSize = GetFileSize(certFile, NULL);
+    if (fileSize != INVALID_FILE_SIZE)
+      {
+      certData = new BYTE[fileSize];
+      if (certData != NULL)
+        {
+        DWORD dwRead = NULL;
+        if (ReadFile(certFile, certData, fileSize, &dwRead, NULL))
+          {
+          cryptBlob.cbData = fileSize;
+          cryptBlob.pbData = certData;
+
+          // Verify that this is a valid cert
+          if (PFXIsPFXBlob(&cryptBlob))
+            {
+            // Open the certificate as a store
+            certStore = PFXImportCertStore(
+              &cryptBlob, NULL, CRYPT_EXPORTABLE);
+            if (certStore != NULL)
+              {
+              // There should only be 1 cert.
+              certContext = CertEnumCertificatesInStore(certStore,
+                certContext);
+              if (certContext != NULL)
+                {
+                // The hash is 20 bytes
+                BYTE hashData[20];
+                DWORD hashLength = 20;
+
+                // Buffer to print the hash. Each byte takes 2 chars +
+                // terminating character
+                char hashPrint[41];
+                char *pHashPrint = hashPrint;
+                // Get the hash property from the certificate
+                if (CertGetCertificateContextProperty(certContext,
+                  CERT_HASH_PROP_ID, hashData, &hashLength))
+                  {
+                  for (DWORD i = 0; i < hashLength; i++)
+                    {
+                    // Convert each byte to hexadecimal
+                    sprintf(pHashPrint, "%02X", hashData[i]);
+                    pHashPrint += 2;
+                    }
+                  *pHashPrint = '\0';
+                  thumbprint = hashPrint;
+                  }
+                CertFreeCertificateContext(certContext);
+                }
+              CertCloseStore(certStore, 0);
+              }
+            }
+          }
+        delete[] certData;
+        }
+      }
+    CloseHandle(certFile);
+    }
+#else
+  (void)source;
+  cmSystemTools::Message("ComputeCertificateThumbprint is not implemented",
+    "Error");
+#endif
+
+  return thumbprint;
+}
+
 void cmSystemTools::Glob(const std::string& directory,
                          const std::string& regexp,
                          std::vector<std::string>& files)
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index fb58307..c12a1db 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -194,6 +194,9 @@ public:
   /** Compute the md5sum of a string.  */
   static std::string ComputeStringMD5(const std::string& input);
 
+  ///! Get the SHA thumbprint for a certificate file
+  static std::string ComputeCertificateThumbprint(const std::string& source);
+
   /**
    * Run a single executable command
    *
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 80b8591..4d0a4f4 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -2893,7 +2893,7 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile()
       (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) <<
         "\\</AppxPackageArtifactsDir>\n";
       this->WriteString("<ProjectPriFullPath>"
-        "$(TargetDir)resources.pri</ProjectPriFullPath>", 2);
+        "$(TargetDir)resources.pri</ProjectPriFullPath>\n", 2);
 
       // If we are missing files and we don't have a certificate and
       // aren't targeting WP8.0, add a default certificate
@@ -2911,6 +2911,13 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile()
       this->WriteString("<", 2);
       (*this->BuildFileStream) << "PackageCertificateKeyFile>"
         << pfxFile << "</PackageCertificateKeyFile>\n";
+      std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile);
+      if(!thumb.empty())
+        {
+        this->WriteString("<PackageCertificateThumbprint>", 2);
+        (*this->BuildFileStream) << thumb
+          << "</PackageCertificateThumbprint>\n";
+        }
       this->WriteString("</PropertyGroup>\n", 1);
       }
     else if(!pfxFile.empty())
@@ -2919,6 +2926,13 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile()
       this->WriteString("<", 2);
       (*this->BuildFileStream) << "PackageCertificateKeyFile>"
         << pfxFile << "</PackageCertificateKeyFile>\n";
+      std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile);
+      if(!thumb.empty())
+      {
+        this->WriteString("<PackageCertificateThumbprint>", 2);
+        (*this->BuildFileStream) << thumb
+          << "</PackageCertificateThumbprint>\n";
+      }
       this->WriteString("</PropertyGroup>\n", 1);
       }
     }
-- 
1.9.5.msysgit.1

