WinVerifyTrust pour vérifier une signature spécifique?

J’implémente un assistant d’élévation de processus pour Windows. C’est un programme qui s’exécutera en mode élevé et lancera d’autres programmes avec des privilèges d’administrateur sans afficher d’autres invites UAC. Pour des raisons de sécurité, je veux m’assurer que seuls les fichiers binarys signés numériquement avec la clé Authenticode de mon entreprise peuvent être exécutés.

La fonction WinVerifyTrust me permet d’y parvenir à mi-chemin, mais elle garantit uniquement qu’un fichier binary est signé par une clé faisant partie de la chaîne de confiance de Microsoft. Existe-t-il un moyen relativement simple d’effectuer la vérification Authenticode ET de s’assurer qu’il est signé par notre clé privée?

Pour obtenir les informations de certificate à partir du code signé, utilisez ceci:

 using System.Security.Cryptography.X509Certificates; X509Certificate basicSigner = X509Certificate.CreateFromSignedFile(filename); X509Certificate2 cert = new X509Certificate2(basicSigner); 

Ensuite, vous pouvez obtenir les détails du certificate comme ceci:

 Console.WriteLine(cert.IssuerName.Name); Console.WriteLine(cert.SubjectName.Name); // etc 

ce sont certaines des API les plus méchantes avec lesquelles j’ai jamais travaillé

Un mot d’avertissement: c’est pire que ce que vous avez déjà pensé.

Au moins depuis l’introduction de la signature SHA-256 (cela a-t-il toujours été le cas?), Il est possible que Authenticode ait plusieurs signatures. Ils ne sont pas codés en tant que signatures multiples dans le message de signature PKCS-7; à la place, ils sont des atsortingbuts de message non authentifiés de type OID_NESTED_SIGNATURE, chacun contenant un autre message de signature PKCS-7 complet.

WinVerifyTrust vous indiquera que le fichier est valide si l’une des signatures est valide et provient d’une chaîne de certificates de confiance. Cependant, il ne vous dira pas laquelle des signatures était valide. Si vous utilisez ensuite CryptQueryObject pour lire le message PKCS-7 complet et ne regardez que le certificate de la signature principale (comme dans les exemples de code ici et sur MSDN), vous ne consultez pas nécessairement un certificate vérifié. La signature associée peut ne pas correspondre à l’exécutable et / ou le certificate peut ne pas avoir une chaîne d’autorité de certificateion approuvée.

Si vous utilisez les détails de la signature principale pour valider que le certificate est l’un de vos logiciels, vous êtes vulnérable à une situation où WinVerifyTrust fait confiance à une signature secondaire, mais votre code vérifie que le certificate de signature primaire correspond à ce que vous attendiez , et vous n’avez pas remarqué que la signature du certificate principal est un non-sens. Un attaquant pourrait utiliser votre certificate public sans posséder sa clé privée, associé à un autre certificate de signature de code émis par une autre personne, afin de contourner une vérification par un éditeur de cette manière.

À partir de Win8, WinVerifyTrust peut éventuellement valider des signatures spécifiques. Vous devriez donc pouvoir itérer les signatures pour en trouver une qui soit valide et une autre qui réponde à vos besoins.

Si vous devez être compatible avec Win7, pour autant que je sache, le mieux que vous puissiez gérer est MsiGetFileSignatureInformation. De l’expérimentation (comme pour tout le rest ici, la documentation réelle est frustrante), elle semble renvoyer le certificate de confiance lorsque WinVerifyTrust en fait confiance. Mais s’il n’y a pas de signature sécurisée, elle renvoie quand même le certificate de la signature principale. Vous devez donc toujours utiliser WinVerifyTrust pour vérifier cela.

Bien sûr, il y a aussi beaucoup de problèmes de temps de contrôle / d’heure d’utilisation.

trouvé la solution ici:

http://www.ucosoft.com/how-to-program-to-resortingeve-the-authenticode-information.html

la voici avec indentation:

 #define _UNICODE 1 #define UNICODE 1 #include  #include  #include  #include  #include  #include  #pragma comment (lib, "Crypt32") // the Authenticode Signature is encode in PKCS7 #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING) // Information structure of authenticode sign typedef struct { LPWSTR lpszProgramName; LPWSTR lpszPublisherLink; LPWSTR lpszMoreInfoLink; DWORD cbSerialSize; LPBYTE lpSerialNumber; LPTSTR lpszIssuerName; LPTSTR lpszSubjectName; } SPROG_SIGNATUREINFO, *PSPROG_SIGNATUREINFO; VOID GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo); VOID GetCertificateInfo(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo); BOOL GetAuthenticodeInformation(LPCTSTR lpszFileName, PSPROG_SIGNATUREINFO pInfo) { HCERTSTORE hStore = NULL; HCRYPTMSG hMsg = NULL; PCMSG_SIGNER_INFO pSignerInfo = NULL; DWORD dwSignerInfo; BOOL bRet = FALSE; __try { // as CryptQueryObject() only accept WCHAR file name, convert first WCHAR wszFileName[MAX_PATH]; #ifdef UNICODE if ( !lstrcpynW( wszFileName, lpszFileName, MAX_PATH)) __leave; #else if ( mbstowcs( wszFileName, lpszFileName, MAX_PATH) == -1) __leave; #endif //Resortingeve the Message Handle and Store Handle DWORD dwEncoding, dwContentType, dwFormatType; if ( !CryptQueryObject( CERT_QUERY_OBJECT_FILE, wszFileName, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, NULL)) __leave; //Get the length of SignerInfo if ( !CryptMsgGetParam( hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo)) __leave; // allocate the memory for SignerInfo if ( !(pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc( LPTR, dwSignerInfo))) __leave; // get the SignerInfo if ( !CryptMsgGetParam( hMsg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)pSignerInfo, &dwSignerInfo)) __leave; //get the Publisher from SignerInfo GetProgAndPublisherInfo( pSignerInfo, pInfo); //get the Certificate from SignerInfo GetCertificateInfo( hStore, pSignerInfo, pInfo); bRet = TRUE; } __finally { // release the memory if (pSignerInfo != NULL) LocalFree(pSignerInfo); if (hStore != NULL) CertCloseStore(hStore, 0); if (hMsg != NULL) CryptMsgClose(hMsg); } return bRet; } LPWSTR AllocateAndCopyWideSsortingng(LPCWSTR inputSsortingng) { LPWSTR outputSsortingng = NULL; // allocate the memory outputSsortingng = (LPWSTR)VirtualAlloc(NULL, (wcslen(inputSsortingng) + 1) * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE); // copy if (outputSsortingng != NULL) { lstrcpyW(outputSsortingng, inputSsortingng); } return outputSsortingng; } VOID GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo) { PSPC_SP_OPUS_INFO OpusInfo = NULL; DWORD dwData; __try { // query SPC_SP_OPUS_INFO_OBJID OID in Authenticated Atsortingbutes for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++) { if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID, pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0) { // get the length of SPC_SP_OPUS_INFO if ( !CryptDecodeObject(ENCODING, SPC_SP_OPUS_INFO_OBJID, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData, 0, NULL, &dwData)) __leave; // allocate the memory for SPC_SP_OPUS_INFO if ( !(OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData))) __leave; // get SPC_SP_OPUS_INFO structure if ( !CryptDecodeObject(ENCODING, SPC_SP_OPUS_INFO_OBJID, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData, 0, OpusInfo, &dwData)) __leave; // copy the Program Name of SPC_SP_OPUS_INFO to the return variable if (OpusInfo->pwszProgramName) { pInfo->lpszProgramName = AllocateAndCopyWideSsortingng(OpusInfo->pwszProgramName); } else pInfo->lpszProgramName = NULL; // copy the Publisher Info of SPC_SP_OPUS_INFO to the return variable if (OpusInfo->pPublisherInfo) { switch (OpusInfo->pPublisherInfo->dwLinkChoice) { case SPC_URL_LINK_CHOICE: pInfo->lpszPublisherLink = AllocateAndCopyWideSsortingng(OpusInfo->pPublisherInfo->pwszUrl); break; case SPC_FILE_LINK_CHOICE: pInfo->lpszPublisherLink = AllocateAndCopyWideSsortingng(OpusInfo->pPublisherInfo->pwszFile); break; default: pInfo->lpszPublisherLink = NULL; break; } } else { pInfo->lpszPublisherLink = NULL; } // copy the More Info of SPC_SP_OPUS_INFO to the return variable if (OpusInfo->pMoreInfo) { switch (OpusInfo->pMoreInfo->dwLinkChoice) { case SPC_URL_LINK_CHOICE: pInfo->lpszMoreInfoLink = AllocateAndCopyWideSsortingng(OpusInfo->pMoreInfo->pwszUrl); break; case SPC_FILE_LINK_CHOICE: pInfo->lpszMoreInfoLink = AllocateAndCopyWideSsortingng(OpusInfo->pMoreInfo->pwszFile); break; default: pInfo->lpszMoreInfoLink = NULL; break; } } else { pInfo->lpszMoreInfoLink = NULL; } break; // we have got the information, break } } } __finally { if (OpusInfo != NULL) LocalFree(OpusInfo); } } VOID GetCertificateInfo(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo) { PCCERT_CONTEXT pCertContext = NULL; __try { CERT_INFO CertInfo; DWORD dwData; // query Signer Certificate in Certificate Store CertInfo.Issuer = pSignerInfo->Issuer; CertInfo.SerialNumber = pSignerInfo->SerialNumber; if ( !(pCertContext = CertFindCertificateInStore( hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&CertInfo, NULL))) __leave; dwData = pCertContext->pCertInfo->SerialNumber.cbData; // SPROG_SIGNATUREINFO.cbSerialSize pInfo->cbSerialSize = dwData; // SPROG_SIGNATUREINFO.lpSerialNumber pInfo->lpSerialNumber = (LPBYTE)VirtualAlloc(NULL, dwData, MEM_COMMIT, PAGE_READWRITE); memcpy( pInfo->lpSerialNumber, pCertContext->pCertInfo->SerialNumber.pbData, dwData); // SPROG_SIGNATUREINFO.lpszIssuerName __try { // get the length of Issuer Name if (!(dwData = CertGetNameSsortingng( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, NULL, 0))) __leave; // allocate the memory if ( !(pInfo->lpszIssuerName = (LPTSTR)VirtualAlloc(NULL, dwData * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE))) __leave; // get Issuer Name if (!(CertGetNameSsortingng(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, pInfo-> lpszIssuerName, dwData))) __leave; } __finally { } // SPROG_SIGNATUREINFO.lpszSubjectName __try { //get the length of Subject Name if (!(dwData = CertGetNameSsortingng( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0))) __leave; // allocate the memory if ( !(pInfo->lpszSubjectName = (LPTSTR)VirtualAlloc(NULL, dwData * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE))) __leave; // get Subject Name if (!(CertGetNameSsortingng( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pInfo->lpszSubjectName, dwData))) __leave; } __finally { } } __finally { if (pCertContext != NULL) CertFreeCertificateContext(pCertContext); } } int _tmain(int argc, TCHAR *argv[]) { if (argc != 2) { _tprintf(_T("Usage: SignedFileInfo \n")); return 0; } else { SPROG_SIGNATUREINFO SignInfo; ZeroMemory(&SignInfo, sizeof(SignInfo)); GetAuthenticodeInformation( argv[1], &SignInfo); wprintf(L"Program Name: %s\n", SignInfo.lpszProgramName); wprintf(L"Publisher Link: %s\n", SignInfo.lpszPublisherLink); wprintf(L"More Info Link: %s\n", SignInfo.lpszMoreInfoLink); { _tprintf(_T("Serial Number: ")); DWORD dwData = SignInfo.cbSerialSize; for (DWORD n = 0; n < dwData; n++) { _tprintf(_T("%02x "), SignInfo.lpSerialNumber[dwData - (n + 1)]); } _tprintf(_T("\n")); } _tprintf(_T("Issuer Name: %s\n"), SignInfo.lpszIssuerName); _tprintf(_T("Subject Name: %s\n"), SignInfo.lpszSubjectName); if ( SignInfo.lpszProgramName) VirtualFree(SignInfo.lpszProgramName, 0, MEM_RELEASE); if ( SignInfo.lpszPublisherLink) VirtualFree(SignInfo.lpszPublisherLink, 0, MEM_RELEASE); if ( SignInfo.lpszMoreInfoLink) VirtualFree(SignInfo.lpszMoreInfoLink, 0, MEM_RELEASE); if ( SignInfo.lpSerialNumber) VirtualFree(SignInfo.lpSerialNumber, 0, MEM_RELEASE); if ( SignInfo.lpszIssuerName) VirtualFree(SignInfo.lpszIssuerName, 0, MEM_RELEASE); if ( SignInfo.lpszSubjectName) VirtualFree(SignInfo.lpszSubjectName, 0, MEM_RELEASE); return 0; } }