winapi cryptography digital-signature winverifytrust

winapi - ¿Cómo verificar que mi organización firmó un binario confiable de Windows?



cryptography digital-signature (1)

En su lugar, quiere el CMSG_SIGNER_INFO_PARAM .

Puede usar esto para obtener el certificado completo buscando el certificado en el almacén de certificados devuelto por CryptQueryObject :

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

Esta es una pregunta de seguimiento a la pregunta 1072540, ''¿WinVerifyTrust para verificar una firma específica?'' .

Quiero escribir una función de C ++. Vamos a llamarla ''TrustedByUs'' del formulario:

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

La idea es que proporcionemos a esta función una ruta a un archivo binario .dll o .exe que se haya firmado con una firma digital. La cadena ''pathToPublicKey'' es la ruta a una clave pública de nuestro certificado de firma particular.

Usando el código en http://support.microsoft.com/kb/323809 es bastante sencillo verificar que el sistema operativo realmente confíe en el archivo ''pathToBinary''.

Ahora estoy en el mismo lugar que el autor de la pregunta 1072540, sé que el SO confía en el firmante de este binario, pero quiero saber si la clave RSA de mi organización es la que firmó el binario.

El KB323809 muestra cómo extraer las cadenas del certificado incrustado en nuestro archivo binario. Este ejemplo muestra cómo extraer cadenas del certificado de firma en su función GetProgAndPublisherInfo, pero no me siento cómodo usando una coincidencia de cadena para verificar el certificado.

Lo que me gustaría hacer es extraer la clave pública de la firma incrustada y compararla con la clave pública que corresponde con la clave privada que firmó mi archivo binario en primer lugar.

La documentación para CryptMsgGetParam dice que el parámetro CMSG_SIGNER_CERT_ID_PARAM ''Devuelve información sobre un firmante de mensaje necesario para identificar la clave pública del firmante''. Logré obtener el número de serie del certificado con esta clave. Mi código se ve así:

// 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"); }

Esto está cerca de lo que quiero, pero realmente me gustaría utilizar la clave pública del certificado de firma para verificar que el archivo binario firmado por el objetivo se haya creado de hecho con mi par particular de clave pública / privada.

Usando el indicador CMSG_ENCRYPTED_DIGEST, este código tiene éxito:

// 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);

Pregunta de fondo : dada la información del certificado descubierta por CryptQueryObject, ¿qué técnica debo usar para asegurarme de que el archivo de destino se firmó con la clave privada que corresponde a la clave pública que tengo disponible cuando se ejecuta el código anterior?