diff --git a/CTestCustom.cmake.in b/CTestCustom.cmake.in index f29ac70ae..d3cff518c 100644 --- a/CTestCustom.cmake.in +++ b/CTestCustom.cmake.in @@ -32,6 +32,7 @@ set(CTEST_CUSTOM_WARNING_EXCEPTION "remark: .*LOOP WAS VECTORIZED" "warning .980: wrong number of actual arguments to intrinsic function .std::basic_" "LINK : warning LNK4089: all references to.*ADVAPI32.dll.*discarded by /OPT:REF" + "LINK : warning LNK4089: all references to.*CRYPT32.dll.*discarded by /OPT:REF" "LINK : warning LNK4089: all references to.*PSAPI.DLL.*discarded by /OPT:REF" "LINK : warning LNK4089: all references to.*RPCRT4.dll.*discarded by /OPT:REF" "LINK : warning LNK4089: all references to.*SHELL32.dll.*discarded by /OPT:REF" diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 1886519cf..16b9ea10b 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -558,7 +558,8 @@ endif() if(WIN32 AND NOT UNIX) # We need the rpcrt4 library on Windows. - target_link_libraries(CMakeLib rpcrt4) + # We need the crypt32 library on Windows for crypto/cert APIs. + target_link_libraries(CMakeLib rpcrt4 crypt32) endif() # diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index a117238b1..583e1d0ee 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 = 0; + 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& files) diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index fb58307d0..c12a1db96 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 80b8591e8..28a0425bd 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2893,7 +2893,7 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) << "\\\n"; this->WriteString("" - "$(TargetDir)resources.pri", 2); + "$(TargetDir)resources.pri\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 << "\n"; + std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile); + if (!thumb.empty()) + { + this->WriteString("", 2); + (*this->BuildFileStream) << thumb + << "\n"; + } this->WriteString("\n", 1); } else if(!pfxFile.empty()) @@ -2919,6 +2926,13 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() this->WriteString("<", 2); (*this->BuildFileStream) << "PackageCertificateKeyFile>" << pfxFile << "\n"; + std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile); + if (!thumb.empty()) + { + this->WriteString("", 2); + (*this->BuildFileStream) << thumb + << "\n"; + } this->WriteString("\n", 1); } }