如何使用CryptoAPI和SignerSign签名带有其他证书的EXE

How to Sign an EXE with Additional Certificates using CryptoAPI and SignerSign

本文关键字:其他 证书 EXE CryptoAPI 何使用 SignerSign      更新时间:2023-10-16

我正在尝试构建一个工具,将基于内核模式代码签名要求对一堆文件进行大规模签名。我知道signtool可以通过/ac参数为交叉签名信任采取额外的证书,但无法弄清楚如何使用SignerSign或SignerSignEx做同样的事情。我甚至监视了signtool的API调用,并且镜像它们似乎不会产生相同的效果。

请注意,由于项目限制,signtool或其他命令行实用程序不能用于此目的。

有关于如何完成这个的文档或示例吗?

好了,经过一段时间的工作,我终于弄清楚了如何使用交叉证书进行签名。首先,根据signtool的版本,您将需要四个或五个证书,这些证书嵌入在signtool EXE的资源CERTIFICATE资源类型下,它们都以MS开头。现在我让我的版本从文件中提取所有证书,下面的示例伪代码将解释如何做到这一点。它不是纯粹的CryptoAPI调用,但确实解释了signtool使用的基本过程。为了简单起见,还省略了所有证书使用验证。


// inputs: string pfx_file_path, string cross_cert_file_path, string password, string file_to_sign
Certificate_Store signer_collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, CERT_STORE_CREATE_NEW_FLAG, NULL);
Certificate_Store signer_store = CertOpenStore(CERT_STORE_PROV_MEMORY, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL,
    CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG | CERT_STORE_READONLY_FLAG, NULL);
File pfx_file = File::open(pifx_file_path, GENERIC_READ, OPEN_EXISTING);
File_Mapping<BYTE> pfx_mapping = File_Mapping<BYTE>::map(pfx_file);
CRYPT_DATA_BLOB pfx_blob = { pfx_mapping.size(), pfx_mapping.data() };
Certificate_Store signer_pfx = PFXImportCertStore(&pfx_blob, password, CRYPT_USER_KEYSET);
// CertEnumCertificatesInStore
for (Certificate certificate: signer_pfx) {
    signer_store.add(certificate); // CertAddCertificateContextToStore
}
signer_collection.add(signer_store); // CertAddStoreToCollection
Certificate signer;
for (Certificate certificate: signer_collection) {
    // Assumes first certificate is the signer, need better validation.
    signer = CertDuplicateCertificateContext(certificate);
    break;
}
if (signer != NULL) {
    throw NoSginerException();
}
Certificate_Store additional_collection;
if (cross_cert_file_path != NULL) {
    Certificate_Store cross_collection;
    Certificate_Store cross_store;
    Certificate cross_certificate = Certificate::load(cross_cert_file_path);
    // CryptQueryObject(CERT_QUERY_OBJECT_FILE, cross_cert_file_path, 
    //  CERT_QUERY_CONTENT_FLAG_CERT, CERT_QUERY_FORMAT_FLAG_ALL,
    //  0, NULL, NULL, NULL, NULL, NULL, &cross_certificate);
    cross_collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, CERT_STORE_CREATE_NEW_FLAG, NULL);
    cross_collection.add(signer_collection);
    cross_store = CertOpenStore(CERT_STORE_PROV_MEMORY, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL,
        CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG | CERT_STORE_READONLY_FLAG, NULL);
    cross_store.add(cross_certificate);
    cross_collection.add(cross_store);
    Certificate_Store ms_root_store = CertOpenStore(sz_CERT_STORE_PROV_MEMORY, 0, NULL,
        CERT_STORE_CREATE_NEW_FLAG | CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL);
    // This is where the embedded certificates from the MS Code Validation roots are collectioned.
    for (Resource resource: Program_Resources::resources_under("CERTIFICATE")) { // EnumResourceNames, Find/Load/Lock|Resource
        Certificate certificate = Certificate::from_blob(resource.size(), resource.data());
        // CERT_BLOB blob = { resource.size(), resources.data() };
        // CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, 
        //  CERT_QUERY_CONTENT_FLAG_CERT | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT,
        //  CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, NULL, NULL, NULL,
        //  &certificate);
        ms_root_store.add(certificate);
    }
    cross_collection.add(certificate);
    static const DWORD CHAIN_FLAGS = CERT_CHAIN_DISABLE_PASS1_QUALITY_FILTERING |
        CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS |
        CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
    static const CERT_CHAIN_PARA CHAIN_PARAMS = { sizeof(CERT_CHAIN_PARA) };
    Certificate_Chain chain = Certificate_Chain::get(HCCE_LOCAL_MACHINE, signer, NULL,
        cross_collection, &CHAIN_PARAMS, CHAIN_FLAGS, NULL);
    // CertGetCertificateChain(HCCE_LOCAL_MACHINE, signer, NULL,
    //  cross_collection, &CHAIN_PARAMS, CHAIN_FLAGS, NULL, &chain);
    Certificate_Store additional_store = CertOpenStore(CERT_STORE_PROV_MEMORY,
        PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL, CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG |
        CERT_STORE_READONLY_FLAG, NULL);
    for (DWORD l = 0; l != chain->cLowerQualityChainContext; ++l) {
        PCCERT_CHAIN_CONTEXT low_chain = pChain->rgpLowerQualityChainContext[l];
        for (DWORD c = 0; c != low_chain->cChain; ++c) {
            PCERT_SIMPLE_CHAIN simple_chain = low_chain->rgpChain[c];
            for (DWORD e = 0; e != simple_chain->cElement; ++e) {
                PCERT_CHAIN_ELEMENT element = simple_chain->rgpElement[e];
                additional_store.add(element->pCertContext);
            }
        }
    }
    additional_collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, CERT_STORE_CREATE_NEW_FLAG, NULL);
    additional_collection.add(additional_store);
}
SIGNER_FILE_INFO file_info = { sizeof(SIGNER_FILE_INFO) };
file_info.pwszFileName = file_to_sign;
DWORD index = 0;
SIGNER_SUBJECT_INFO subject_info = { sizeof(SIGNER_SUBJECT_INFO) };
subject_info.pdwIndex = &index;
subject_info.dwSubjectChoice = SIGNER_SUBJECT_FILE;
subject_info.pSignerFileInfo = &file_info;
SIGNER_CERT_STORE_INFO store_info = { sizeof(SIGNER_CERT_STORE_INFO) };
store_info.dwCertPolicy = SIGNER_CERT_POLICY_STORE;
store_info.pSigningCert = signer;
store_info.hCertStore = additional_collection;
SIGNER_CERT cert_info = { sizeof(SIGNER_CERT) };
cert_info.dwCertChoice = SIGNER_CERT_STORE;
cert_info.pCertStoreInfo = &store_info;
SIGNER_ATTR_AUTHCODE authcode_attr = { sizeof(SIGNER_ATTR_AUTHCODE) };
SIGNER_SIGNATURE_INFO signature_info = { sizeof(SIGNER_SIGNATURE_INFO) };
signature_info.algidHash = CALG_SHA;
signature_info.dwAttrChoice = SIGNER_AUTHCODE_ATTR;
signature_info.pAttrAuthcode = &authcode_attr;
SIGNER_PROVIDER_INFO provider_info = { sizeof(SIGNER_PROVIDER_INFO) };
provider_info.pwszProviderName = L"";
provider_info.dwPvkChoice = PVK_TYPE_KEYCONTAINER;
provider_info.pwszKeyContainer = L"";
HRESULT hr = SignerSign(&subject_info, &cert_info, &signature_info, &provider_info, NULL, NULL, NULL);
相关文章: