问题描述
我正在尝试构建一个工具,该工具将根据内核模式代码签名要求对一堆文件进行大规模签名.我知道signtool可以通过/ac参数获取跨证书信任的附加证书,但是还无法弄清楚如何使用SignerSign或SignerSignEx进行相同的操作.我什至监视了signtool的API调用,并且镜像它们似乎并不会产生相同的影响.
I'm trying to build a tool that will mass sign a bunch of files based on Kernel-Mode Code Signing requirements. I know that signtool can take an additional certificate for cross-signatures trust via the /ac argument, but have not been able to figure out how to do the same using SignerSign or SignerSignEx. I've even spied on signtool's API calls, and mirroring them does not seems to produce the same affect.
请注意,由于项目限制,signtool或其他命令行实用程序不能用于此目的.
Be aware, signtool or other command-line utilities cannot be used for this purpose due to project constraints.
是否有任何文档或示例说明如何完成此操作?
Is there any documentation or examples on how to accomplish this?
推荐答案
好的,经过一段时间的研究,我终于弄清楚了如何使用交叉证书进行签名.首先,根据signtool的版本,您将需要四个或五个证书,这些证书嵌入在CERTIFICATE
资源类型下的signtool EXE资源中,它们都以MS
开头.现在,我使版本从文件中提取所有证书,因此以下示例伪代码将说明如何执行此操作.它不仅是CryptoAPI调用,而且确实解释了signtool使用的基本过程.为了简化起见,所有证书使用情况的验证也被忽略了.
Okay, after working on this for awhile, I've finally figured our how to do signing with a cross certificate. First, you will need four, or five depending on your version of signtool, certificates that are embedded in the signtool EXE's resources under the CERTIFICATE
resource type, they all start with MS
. Now I made my version pull all certificates from files so the following example pseudo code will explain how to do this. It's not purely the CryptoAPI calls, but does explain the basic process used by signtool. All certificate usage validation has also been left out for simplicity.
// 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);
这篇关于如何使用CryptoAPI和SignerSign使用附加证书对EXE进行签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!