// // prov.cpp // // NT Trust Provider implementation for software publishing trust // #include "stdpch.h" #include "common.h" /////////////////////////////////////////////////////////////////////// // // First, some supporting routines. Note especially the first of these, // which remains incomplete. // /////////////////////////////////////////////////////////////////////// LPWINTRUST_CLIENT_TP_DISPATCH_TABLE GetSip(LPWIN_TRUST_SIP_SUBJECT pSubjectForm); HRESULT GetSignedDataFromSip // // Load the appropriate SignedData from the SIP. We just take the // first #7 that we see. Use the TASK allocator. // ( LPWINTRUST_CLIENT_TP_DISPATCH_TABLE psip, LPWIN_TRUST_SIP_SUBJECT pSubject, LPWIN_CERTIFICATE* ppCert ) { HRESULT hr = S_OK; *ppCert = NULL; // // Look for pkcs#7 embedded in SIP // ULONG iCert; for (iCert = 0; ; iCert++) { WIN_CERTIFICATE hdr; if ((psip->GetSubjectCertHeader)(pSubject, iCert, &hdr)) { if (hdr.wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) { // found one break; } } else { // // Didn't find usable trust material // hr = TRUST_E_NOSIGNATURE; break; } } if (hr==S_OK) { // // Get pkcs#7 WINCERT from SIP // // REVIEW: Is the error code convention that we use here the correct // one? It does indeed work for ImageHlp. If this is correct, then // it needs to be documented. // ULONG cbNeeded = 0; if ((psip->GetSubjectCertificate)(pSubject, iCert, NULL, &cbNeeded) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) { *ppCert = (LPWIN_CERTIFICATE)CoTaskMemAlloc(cbNeeded); if (*ppCert) { if ((psip->GetSubjectCertificate)(pSubject, iCert, *ppCert, &cbNeeded)) { // all is well } else hr = HError(); } else hr = E_OUTOFMEMORY; } else hr = HError(); } return hr; } LPWSTR GetDisplayNameOfSubject( // // Return the display name of the given subject. Use the Task allocator // LPWINTRUST_CLIENT_TP_DISPATCH_TABLE psip, LPWIN_TRUST_SIP_SUBJECT pSubject, LPWIN_CERTIFICATE pCertSeven ) { ULONG cbNeeded = 0; LPWSTR wsz = NULL; if ((psip->GetSubjectName)(pSubject, pCertSeven, NULL, &cbNeeded) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) { wsz = (LPWSTR)CoTaskMemAlloc(cbNeeded); if (wsz) { if ((psip->GetSubjectName)(pSubject, pCertSeven, wsz, &cbNeeded)) { // all is well } else { CoTaskMemFree(wsz); wsz = NULL; } } } return wsz; } /////////////////////////////////////////////////////////////////////// // // Carry out the indicated trust verification action // /////////////////////////////////////////////////////////////////////// HRESULT VerifyTrust( HWND hwnd, GUID * pGuidActionId, LPVOID lpActionData ) { HRESULT hr = S_OK; GUID guidActionPublishedSoftware = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE; LPWIN_TRUST_ACTDATA_CONTEXT_WITH_SUBJECT lpActionDataSubjectOnly = (LPWIN_TRUST_ACTDATA_CONTEXT_WITH_SUBJECT)lpActionData; // // Make sure we were called with an action id we support // if ( !(*pGuidActionId == guidActionPublishedSoftware) ) { return TRUST_E_ACTION_UNKNOWN; } // // Unpack the subject information. // WIN_TRUST_SIP_SUBJECT subject; subject.SubjectType = lpActionDataSubjectOnly->SubjectType; subject.Subject = lpActionDataSubjectOnly->Subject; LPWINTRUST_CLIENT_TP_DISPATCH_TABLE psip = GetSip(&subject); // // Extract the relavent PKCS #7 SignedData from the subject // WIN_CERTIFICATE* pCertSeven = NULL; hr = GetSignedDataFromSip(psip, &subject, &pCertSeven); // // Next, ask that SIP to verify the content information therein // if (hr==S_OK) { if (psip->CheckSubjectContentInfo(&subject, pCertSeven)) { // all is well } else hr = HError(); } // // Having passed the test, load the #7 ourselves so we can check // other things. // // Note: the SIP undoubtedly just loaded and tossed the #7, so this // is a repeat load here. Sure would be nice to have a way to avoid the // redundant decodings of the ANS.1. // if (hr==S_OK) { IPkcs7SignedData* pkcs7 = NULL; if ((pdigsig->CreatePkcs7SignedData)(NULL, IID_IPkcs7SignedData, (LPVOID*)&pkcs7)) { ICertificateStore* store = NULL; ISignerInfo* signer = NULL; HCRYPTPROV hprov = NULL; IX509* parent = NULL; BOOL fCommercial = FALSE; IX509* p509Publisher = NULL; IX509* p509Agency = NULL; BOOL fTestingOnly = FALSE; BOOL fTrustTesting = FALSE; BOOL fTestCanBeValid = FALSE; ////////////////////////////////////////////////////////////////////////// // // Allow the user to override a few things // hr = GetRegistryState(fTrustTesting, fTestCanBeValid); ////////////////////////////////////////////////////////////////////////// // // Verify and fetch the signer info from the #7 // if (hr==S_OK) hr = VerifySeven(pkcs7, store, fCommercial, signer, hprov, parent); ////////////////////////////////////////////////////////////////////////// // // verify the chain of x509 certificates // if (hr==S_OK) hr = VerifyChain ( parent, // in,out store, // in hprov, // in fCommercial, // in p509Publisher, // out p509Agency, // out fTestingOnly // out ); ////////////////////////////////////////////////////////////////////////// // // Put up the appropriate UI // if (hr==S_OK) { LPWSTR wszDisplayName = GetDisplayNameOfSubject(psip, &subject, pCertSeven); hr = VerifyFinish( hr, hwnd, wszDisplayName, fTestingOnly, fTrustTesting, fTestCanBeValid, fCommercial, p509Publisher, p509Agency, signer, store ); CoTaskMemFree(wszDisplayName); } ////////////////////////////////////////////////////////////////////////// // // Clean up // if (store) store->Release(); if (signer) signer->Release(); if (parent) parent->Release(); if (p509Publisher) p509Publisher->Release(); if (p509Agency) p509Agency->Release(); if (hprov) CryptReleaseContext(hprov, 0); } else hr = HError(); if (pkcs7) pkcs7->Release(); } // // Clean up // if (pCertSeven) CoTaskMemFree(pCertSeven); return hr; } /////////////////////////////////////////////////////////////////////// // // Add a certificate so that it will be useful in subsequent // verification requests. // // REVIEW: How is this correlated with actionid? // ANSWER: It's not! // /////////////////////////////////////////////////////////////////////// VOID SubmitCertificate ( IN LPWIN_CERTIFICATE pCert ) { HRESULT hr = S_OK; BLOB b; b.cbSize = pCert->dwLength - OFFSETOF(WIN_CERTIFICATE, bCertificate); b.pBlobData = &pCert->bCertificate[0]; // // Open the certificate store that we use for software publishing trust // verification // ICertificateStore* pStore; if ((pdigsig->OpenCertificateStore)(NULL, IID_ICertificateStore, (LPVOID*)&pStore)) { switch (pCert->wCertificateType) { case WIN_CERT_TYPE_X509: // // Import just the one certificate // hr = pStore->ImportCertificate(&b, NULL); break; case WIN_CERT_TYPE_PKCS_SIGNED_DATA: { // // Import all the certificates in the SignedData // IPersistMemBlob* pPerMem; if ((pdigsig->CreatePkcs7SignedData)(NULL, IID_IPersistMemBlob, (LPVOID*)&pPerMem)) { hr = pPerMem->Load(&b); if (hr==S_OK) { ICertificateStore* pStoreSeven; hr = pPerMem->QueryInterface(IID_ICertificateStore, (LPVOID*)&pStoreSeven); if (hr==S_OK) { hr = pStoreSeven->CopyTo(pStore); pStoreSeven->Release(); } } pPerMem->Release(); } else hr = HError(); } break; default: hr = E_INVALIDARG; } pStore->Release(); } else hr = HError(); SetLastError(hr); } /////////////////////////////////////////////////////////////////////// // // // /////////////////////////////////////////////////////////////////////// VOID ClientUnload ( IN LPVOID lpTrustProviderInfo ) { // // Do nothing // return; } /////////////////////////////////////////////////////////////////// // / // Interface Tables / // / /////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // // // WinTrustClientTPDispatchTable - Table of function pointers passed // // to trust providers during their initialization routines. // // // // // WINTRUST_PROVIDER_CLIENT_SERVICES WinTrustProviderClientServices = { ClientUnload, // VerifyTrust, // SubmitCertificate // }; // //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // // // Table of services provided by WinTrust that are available // // to trust providers. // // // // This table is defined as follows: // // // // typedef struct _WINTRUST_CLIENT_TP_DISPATCH_TABLE // // { // // LPWINTRUST_PROVIDER_PING ServerPing; // // LPWINTRUST_SUBJECT_CHECK_CONTENT_INFO CheckSubjectContentInfo; // // LPWINTRUST_SUBJECT_ENUM_CERTIFICATES EnumSubjectCertificates; // // LPWINTRUST_SUBJECT_GET_CERTIFICATE GetSubjectCertificate; // // LPWINTRUST_SUBJECT_GET_CERT_HEADER GetSubjectCertHeader; // // LPWINTRUST_SUBJECT_GET_NAME GetSubjectName; // // // // } WINTRUST_CLIENT_TP_DISPATCH_TABLE, *LPWINTRUST_CLIENT_TP_DISPATCH_TABLE; // // // // LPWINTRUST_CLIENT_TP_DISPATCH_TABLE WinTrustServices; // // //////////////////////////////////////////////////////////////////////////////////////// const GUID rgguidActions[] = { WIN_SPUB_ACTION_PUBLISHED_SOFTWARE }; const WINTRUST_PROVIDER_CLIENT_INFO provInfo = { 1, &WinTrustProviderClientServices, 1, (GUID*)&rgguidActions[0] }; BOOL WINAPI WinTrustProviderClientInitialize( IN DWORD dwWinTrustRevision, IN LPWINTRUST_CLIENT_TP_INFO lpWinTrustInfo, IN LPWSTR lpProviderName, OUT LPWINTRUST_PROVIDER_CLIENT_INFO *lpTrustProviderInfo ) /*++ Routine Description: Client initialization routine. Called by Wintrust when the dll is loaded. Arguments: dwWinTrustRevision - Provides revision information. lpWinTrustInfo - Provides list of services available to the trust provider from the wintrust layer. lpProviderName - Supplies a null terminated string representing the provider name. Should be passed back to wintrust when required without modification. lpTrustProviderInfo - Used to return trust provider information, e.g. entry points. Return Value: TRUE on success, FALSE on failure, callers may call GetLastError() for more information. --*/ { *lpTrustProviderInfo = (LPWINTRUST_PROVIDER_CLIENT_INFO)&provInfo; WinTrustServices = lpWinTrustInfo->lpServices; return TRUE; } LPWINTRUST_CLIENT_TP_DISPATCH_TABLE GetSip(LPWIN_TRUST_SIP_SUBJECT pSubjectForm) // // Return the access to the appropriate dispatch table for // the indicated subject type. // { return WinTrustServices; }