Как подписать EXE с дополнительными сертификатами, используя CryptoAPI и SignerSign

Я пытаюсь создать инструмент, который будет массово подписывать несколько файлов на основе требований подписи кода в режиме ядра. Я знаю, что signtool может получить дополнительный сертификат для доверия между подписями через аргумент / ac, но я не смог выяснить, как сделать то же самое с помощью SignerSign или SignerSignEx. Я даже шпионил за вызовами API signtool, и их зеркалирование, похоже, не дает такого же эффекта.

Помните, что signtool или другие утилиты командной строки нельзя использовать для этой цели из-за ограничений проекта.

Есть ли документация или примеры того, как это сделать?

2

Решение

Хорошо, поработав над этим некоторое время, я наконец-то понял, как мы можем подписать с помощью перекрестного сертификата. Во-первых, вам понадобится четыре или пять сертификатов, встроенных в ресурсы EXE-файла signtool в зависимости от вашей версии signtool. 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);
1

Другие решения


По вопросам рекламы [email protected]