2015-08-25 15 views
1

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

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

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

ответ

0

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