2010-01-05 4 views
9

question 1072540, 'WinVerifyTrust to check for a specific signature?'에 대한 후속 질문입니다.내 orgainization이 신뢰할 수있는 Windows 바이너리에 서명했는지 확인하는 방법은 무엇입니까?

bool TrustedByUs(std::string pathToBinary, std::string pathToPublicKey) 

아이디어는 우리가이 기능을하고있다 바이너리 된 .dll 또는 .exe 파일의 경로를 제공한다는 것입니다 : 나는 C를 작성하려는

는 ++ 기능은 형태의 'TrustedByUs'를 호출 할 수 있습니다 디지털 서명으로 서명 됨. 'pathToPublicKey'문자열은 특정 서명 인증서의 공개 키에 대한 경로입니다.

http://support.microsoft.com/kb/323809의 코드를 사용하면 운영 체제에서 'pathToBinary'파일을 실제로 신뢰할 수 있는지 쉽게 확인할 수 있습니다.

질문 1072540의 작가와 같은 곳에서 OS가이 바이너리의 서명자를 신뢰한다는 것을 알고 있지만 조직의 RSA 키가 바이너리에 서명했는지 알고 싶습니다.

KB323809는 이진 파일에 포함 된 인증서에서 문자열을 추출하는 방법을 보여줍니다. 이 예제는 GetProgAndPublisherInfo 함수에서 서명 인증서에서 문자열을 추출하는 방법을 보여줍니다. 그러나 문자열 일치를 사용하여 인증서를 확인하는 것은 불편합니다.

내가하고 싶은 것은 삽입 된 서명에서 공개 키를 추출하여 처음에 이진 파일에 서명 한 개인 키와 일치하는 공개 키와 비교하는 것입니다.

CryptMsgGetParam에 대한 설명서에 CMSG_SIGNER_CERT_ID_PARAM 매개 변수 '서명자의 공개 키를 식별하는 데 필요한 메시지 서명자에 대한 정보를 반환합니다.'라는 메시지가 표시됩니다. 나는이 열쇠로 인증서의 일련 번호를 얻는데 성공한다. 내 코드는 다음과 같습니다

// Get message handle and store handle from the signed file. 
fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE, 
    L"C:\\Program Files\\MySignedProgram.exe", 
    CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, 
    CERT_QUERY_FORMAT_FLAG_BINARY, 
    0, &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, NULL); 

// Get the public key information about the signer 
// First get the size 
DWORD dwCertIdSize(0); 
fResult = CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_ID_PARAM, 
    0, NULL, &dwCertIdSize); 
BYTE* pCertId = new BYTE(dwCertIdSize); 
::ZeroMemory(pCertId,dwCertIdSize); 

// Now get the cert info 
fResult = CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_ID_PARAM, 
    0, (PVOID)pCertId, &dwCertIdSize); 

if(fResult) 
{  
    CERT_ID* pId = (CERT_ID*)pCertId; 
    pId->HashId; 
    pId->dwIdChoice; 
    pId->IssuerSerialNumber; // Valid serial number (reversed) 
    pId->KeyId; 
    _tprintf("pid\n"); 
} 

이것은 내가 원하는 가깝지만 정말 대상 서명 이진 파일이 실제로 내 특정 대중 작성되었는지 확인하기 위해 서명 인증서의 공개 키를 사용하고 싶습니다/개인 키 쌍.

는 CMSG_ENCRYPTED_DIGEST 플래그를 사용하여이 코드는 성공 :

// Get digest which was encrypted with the private key 
DWORD digestSize(0); 
fResult = CryptMsgGetParam(hMsg, CMSG_ENCRYPTED_DIGEST, 0, NULL, &digestSize); 

BYTE* pDigest = new BYTE[digestSize]; 

// Next CryptMsgGetParam call succeds, 
// pDigest looks valid, can I use this to confirm my public key 
// was used to sign MySignedProgram.exe ? 
fResult = CryptMsgGetParam(hMsg, CMSG_ENCRYPTED_DIGEST, 0, pDigest, &digestSize); 

결론 질문 : 나는 사실이를 사용하여 서명에 대상 파일이되었는지 확인하는 데 사용해야하는지 기술 CryptQueryObject에 의해 발견 된 인증서 정보, 주어 위의 코드가 실행될 때 사용할 수있는 공개 키에 해당하는 개인 키?

답변

7

대신 CMSG_SIGNER_INFO_PARAM이 필요합니다.

CryptMsgGetParam(hMsg, 
       CMSG_SIGNER_INFO_PARAM, 
       0, 
       NULL, 
       &dwSignerInfo); 
PCMSG_SIGNER_INFO pSignerInfo = (PCMSG_SIGNER_INFO) malloc(dwSignerInfo); 
CryptMsgGetParam(hMsg, 
       CMSG_SIGNER_INFO_PARAM, 
       0, 
       pSignerInfo, 
       &dwSignerInfo); 

PCCERT_CONTEXT pCertContext = CertFindCertificateInStore(hStore, 
              ENCODING, 
              0, 
              CERT_FIND_SUBJECT_CERT, 
              (PVOID)pSignerInfo, 
              NULL); 
// Compare with your certificate: 
// - check pCertContext->pbCertEncoded (length is pCertContext->cbCertEncoded) 

// *OR* 
// Compare with your public-key: 
// - check pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm and 
// pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey 
+0

감사 라스무스을하지만, 난 여전히 조금 혼란 스러워요 :

당신은 CryptQueryObject에 의해 반환 된 인증서 저장소에 인증서를 보면 전체 인증서를 얻기 위해 이것을 사용할 수 있습니다. CMSG_SIGNER_INFO stuct에는 SubjectPublicKeyInfol 멤버가 포함되어 있지 않습니다. –

+0

죄송합니다. CMSG_SIGNER_INFO와 CERT_INFO 구조체가 섞였습니다. 답은 지금 바로 정답이어야합니다. –

+0

Rasmus에게 감사드립니다. CERT_NAME_SIMPLE_DISPLAY_TYPE 플래그가있는 CertGetNameString API도이 프로젝트에서 유용합니다. –

관련 문제