[cpp-sp] 05/05: Start to hack away at cert checking

Rod Widdowson rdw at steadingsoftware.com
Wed May 7 13:14:03 UTC 2025


This is an automated email from the git hooks/post-receive script.

rdw pushed a commit to branch dev/SPPSP-8-playpen
in repository cpp-sp.

View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=29c94863db8b550f2cd4fbd283423351a470c7ec

commit 29c94863db8b550f2cd4fbd283423351a470c7ec
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Wed May 7 14:11:31 2025 +0100

    Start to hack away at cert checking
---
 Projects/WinHttpProject/WinHttpProject.cpp         | 165 +++++++++++++++++++--
 Projects/WinHttpProject/WinHttpProject.vcxproj     |   5 +
 .../WinHttpProject/WinHttpProject.vcxproj.filters  |   5 +
 3 files changed, 160 insertions(+), 15 deletions(-)

diff --git a/Projects/WinHttpProject/WinHttpProject.cpp b/Projects/WinHttpProject/WinHttpProject.cpp
index 63ad25ee..a3cacdd0 100644
--- a/Projects/WinHttpProject/WinHttpProject.cpp
+++ b/Projects/WinHttpProject/WinHttpProject.cpp
@@ -11,6 +11,44 @@ using namespace std;
 
 //static WINHTTP_STATUS_CALLBACK Callback;
 
+HCERTCHAINENGINE engine = NULL;
+HCERTSTORE certStore;
+
+static
+BOOLEAN
+CheckCertCtx(PCCERT_CONTEXT context) {
+
+    PCCERT_CONTEXT outCtx 
+
+    = CertFindCertificateInStore(certStore, X509_ASN_ENCODING, 0, CERT_FIND_EXISTING, context, NULL);
+/*
+//    if (!CertGetCertificateChain(engine, context, NULL, context->hCertStore, &chainPara, 0, // No revocation checking
+//        if (!CertGetCertificateChain(NULL, context, NULL, context->hCertStore, &chainPara, 0, // No revocation checking
+    if (!CertGetCertificateChain(NULL, context, NULL, certStore, &chainPara, 0, // No revocation checking
+        NULL, &chainContext)) {
+        cout << "CertGetCertificateChain failed " << GetLastError() << endl;
+
+        return FALSE;
+     }
+
+    CERT_SIMPLE_CHAIN* pSimpleChain = chainContext->rgpChain[0];
+    DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
+    dwTrustErrorMask = pSimpleChain->TrustStatus.dwErrorStatus;
+    CertFreeCertificateChain(chainContext);
+
+    if (dwTrustErrorMask) {
+
+        cout << "TrustError Mask: 0x" << hex << dwTrustErrorMask << endl;
+
+        return FALSE;
+
+    }
+    */
+    return TRUE;
+}
+
+
+
 static void Callback(
     HINTERNET hInternet,
     DWORD_PTR dwContext,
@@ -18,20 +56,26 @@ static void Callback(
     LPVOID lpvStatusInformation,
     DWORD dwStatusInformationLength)
 {
-    PCCERT_CONTEXT pCert = NULL;
-    DWORD dwSize = sizeof(pCert);
+    PCCERT_CONTEXT pCertCtx = NULL;
+    DWORD dwSize = sizeof(pCertCtx);
     cout << "Handle " << hex << hInternet <<endl;
     cout << "Context " << dec << dwContext << endl;
     switch (dwInternetStatus) {
         case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
             wcout << L"Sending Request (" << dwInternetStatus << L") " << endl;
-            if (!WinHttpQueryOption(hInternet, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &pCert, &dwSize)) {
+            if (!WinHttpQueryOption(hInternet, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &pCertCtx, &dwSize)) {
                 cout << "Gack " << GetLastError() << endl;
             } else {
                 CHAR buffer[1024];
-                CertNameToStrA(X509_ASN_ENCODING, &pCert->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, buffer, sizeof(buffer));
+                CertNameToStrA(X509_ASN_ENCODING, &pCertCtx->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, buffer, sizeof(buffer));
                 cout << "Subject name " << buffer << endl;
-                CertFreeCertificateContext(pCert);
+
+                if (!CheckCertCtx(pCertCtx)) {
+                    cout << "Check Failed" << endl;
+                }
+
+
+                CertFreeCertificateContext(pCertCtx);
             }
         break;
     
@@ -64,9 +108,105 @@ Utf8ToUtf16(string InputString) {
 
     return result;
 }
+//
+// Certificate checking
+// I spelunked the curl code and there are some cute tricks but effectively
+// 
+// Suck the cert file into memory
+// 
+// Create an in Memory Certificate store(HCERTSTORE) using CertOpenStore with a provider CERT_STORE_PROV_MEMORY
+// 
+// This should probably be a private field and be torn down
+// 
+// Suck the cerificate into the cert store(CryptQueryObject then CertAddCertificateContextToStore)
+// 
+// plug the HCERTSTORE into a CERT_CHAIN_ENGINE_CONFIG and plug that into CertCreateCertificateChainEngine to get a HCERTENGINE
+// 
+// Also a private filed, also torn down
+// 
+// Then call CertGetCertificateChain with the PCCERT_CONTEXT we get inside our worker method.
+// 
+// Documentation for the above all starts https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/
+
+static
+void enumerateStore(HCERTSTORE store) {
+    
+    PCCERT_CONTEXT cert = CertEnumCertificatesInStore(store, NULL);
+
+    cout << "CERT STORE\n";
+    while (cert) {
+        CHAR buffer[1024];
+        CertNameToStrA(X509_ASN_ENCODING, &cert->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, buffer, sizeof(buffer));
+        cout << "\t Subject name " << buffer << endl;
+        cert = CertEnumCertificatesInStore(store, cert);
+    }
+}
 
 int main()
 {
+    DWORD msgAndCertEncodingType, contentType, formatType;
+    PCERT_CONTEXT certContext = NULL;
+
+    if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE,
+        L"V:\\perforce\\SP\\cpp-sp\\Projects\\WinHttpProject\\shib.cert",
+       // L"V:\\perforce\\SP\\cpp-sp\\tests\\data\\remoting\\impl\\trustfile.pem",
+        CERT_QUERY_CONTENT_FLAG_CERT,
+        CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED,
+        0,
+        &msgAndCertEncodingType,
+        &contentType,
+        &formatType,
+        NULL,
+        NULL,
+        (void const**) &certContext)) {
+
+        cerr << "CryptQueryObject failed 0x" << hex << GetLastError() << endl ;
+        return 1;
+    }
+{
+        CHAR buffer[1024];
+        CertNameToStrA(X509_ASN_ENCODING, &certContext->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, buffer, sizeof(buffer));
+        cout << "Subject name " << buffer << endl;
+}
+
+    if ((msgAndCertEncodingType != X509_ASN_ENCODING) ||
+        (contentType != CERT_QUERY_CONTENT_CERT) ||
+        (formatType != CERT_QUERY_FORMAT_BASE64_ENCODED)) {
+    
+        cerr << "CryptQueryObject unexpected input. Encoding: 0x" << hex << msgAndCertEncodingType <<
+                                                ", context: 0x" << contentType <<
+                                                ", format: 0x" << formatType << endl;        
+    }
+
+    certStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, CERT_STORE_CREATE_NEW_FLAG, NULL);
+
+    if (certStore == NULL) {
+
+        cerr << "CertOpenStore failed 0x" << hex << GetLastError() << endl;
+        return 1;
+    }
+    enumerateStore(certStore);
+
+    if (!CertAddCertificateContextToStore(certStore, certContext, CERT_STORE_ADD_ALWAYS, NULL)) {
+    
+        cerr << "CertAddCertificateContextToStore failed 0x" << hex << GetLastError() << endl;
+        return 1;
+    }
+    enumerateStore(certStore);
+        CertFreeCertificateContext(certContext);
+        enumerateStore(certStore);
+
+    CERT_CHAIN_ENGINE_CONFIG cfg = {0};
+    cfg.cbSize = sizeof(cfg);
+    cfg.hExclusiveRoot = certStore;
+
+    if (!CertCreateCertificateChainEngine(&cfg, &engine)) {
+
+        cerr << "CertCreateCertificateChainEngine failed 0x" << hex << GetLastError() << endl;
+        return 1;
+    }
+
+
     string url("https://shibboleth.net/downloads/PGP_KEYS");
 
     wstring wUrl(Utf8ToUtf16(url));
@@ -171,15 +311,10 @@ int main()
     if (hRequest) WinHttpCloseHandle(hRequest);
     if (hConnect) WinHttpCloseHandle(hConnect);
     if (hSession) WinHttpCloseHandle(hSession);
-}
+    enumerateStore(certStore);
 
-// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
-// Debug program: F5 or Debug > Start Debugging menu
+    if (certStore) CertCloseStore(certStore, 0);
+    if (engine) CertFreeCertificateChainEngine(engine);
+
+}
 
-// Tips for Getting Started: 
-//   1. Use the Solution Explorer window to add/manage files
-//   2. Use the Team Explorer window to connect to source control
-//   3. Use the Output window to see build output and other messages
-//   4. Use the Error List window to view errors
-//   5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
-//   6. In the future, to open this project again, go to File > Open > Project and select the .sln file
diff --git a/Projects/WinHttpProject/WinHttpProject.vcxproj b/Projects/WinHttpProject/WinHttpProject.vcxproj
index f5c04f71..964559b2 100644
--- a/Projects/WinHttpProject/WinHttpProject.vcxproj
+++ b/Projects/WinHttpProject/WinHttpProject.vcxproj
@@ -131,6 +131,11 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\..\curl\lib\vtls\schannel_verify.c">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">USE_SCHANNEL=1;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FileType>CppCode</FileType>
+    </ClInclude>
     <ClCompile Include="WinHttpProject.cpp" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/Projects/WinHttpProject/WinHttpProject.vcxproj.filters b/Projects/WinHttpProject/WinHttpProject.vcxproj.filters
index aa36c5af..92142e1a 100644
--- a/Projects/WinHttpProject/WinHttpProject.vcxproj.filters
+++ b/Projects/WinHttpProject/WinHttpProject.vcxproj.filters
@@ -19,4 +19,9 @@
       <Filter>Source Files</Filter>
     </ClCompile>
   </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\..\curl\lib\vtls\schannel_verify.c">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+  </ItemGroup>
 </Project>
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list