SUPPORT-9333. Проверка подписанного сообщения, содержащего отсоединённую подпись
This commit is contained in:
parent
9d2f2be25a
commit
ac08303c90
34 changed files with 2403 additions and 114 deletions
|
|
@ -100,13 +100,75 @@ free_cert_chain(PCCERT_CHAIN_CONTEXT chain_ctx)
|
|||
}
|
||||
|
||||
static void
|
||||
process_trust_status_error(DWORD status, /*out*/ const char **error_code)
|
||||
print_crl_urls_from_certificate(PCCERT_CONTEXT cert)
|
||||
{
|
||||
LOG_TRACE("print_crl_urls_from_certificate enter");
|
||||
|
||||
PCERT_EXTENSION extension = cp_function_list.CertFindExtension(
|
||||
szOID_CRL_DIST_POINTS,
|
||||
cert->pCertInfo->cExtension,
|
||||
cert->pCertInfo->rgExtension
|
||||
);
|
||||
|
||||
if (!extension) {
|
||||
LOG_WARN("CRL Distribution Points extension not found");
|
||||
goto error;
|
||||
}
|
||||
|
||||
DWORD info_size = 0;
|
||||
CRL_DIST_POINTS_INFO *crl_dist_points = NULL;
|
||||
|
||||
if (!cp_function_list.CryptDecodeObjectEx(
|
||||
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
X509_CRL_DIST_POINTS,
|
||||
extension->Value.pbData,
|
||||
extension->Value.cbData,
|
||||
CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
|
||||
NULL,
|
||||
&crl_dist_points,
|
||||
&info_size
|
||||
)) {
|
||||
LOG_ERROR("CryptDecodeObjectEx failed. Desc: 0x%x", cp_function_list.GetLastError());
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (crl_dist_points && crl_dist_points->cDistPoint > 0) {
|
||||
for (DWORD i = 0; i < crl_dist_points->cDistPoint; i++) {
|
||||
PCRL_DIST_POINT pDistPoint = &crl_dist_points->rgDistPoint[i];
|
||||
|
||||
if (pDistPoint->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_FULL_NAME) {
|
||||
PCERT_ALT_NAME_ENTRY pAltNameEntry = pDistPoint->DistPointName._empty_union_.FullName.rgAltEntry;
|
||||
|
||||
for (DWORD j = 0; j < pDistPoint->DistPointName._empty_union_.FullName.cAltEntry; j++) {
|
||||
if (pAltNameEntry[j].dwAltNameChoice == CERT_ALT_NAME_URL) {
|
||||
LOG_INFO("CRL URL: %ls", pAltNameEntry[j]._empty_union_.pwszURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (crl_dist_points) {
|
||||
cp_function_list.LocalFree(crl_dist_points);
|
||||
}
|
||||
|
||||
LOG_TRACE("print_crl_urls_from_certificate exit");
|
||||
return;
|
||||
|
||||
error:
|
||||
LOG_ERROR("print_crl_urls_from_certificate exit with error");
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
process_trust_status_error(PCCERT_CONTEXT cert, DWORD status, /*out*/ const char **error_code)
|
||||
{
|
||||
LOG_TRACE("process_trust_status_error enter");
|
||||
|
||||
switch (status) {
|
||||
case CERT_TRUST_REVOCATION_STATUS_UNKNOWN:
|
||||
*error_code = CERT_TRUST_REVOCATION_STATUS_UNKNOWN_ERR_CODE;
|
||||
print_crl_urls_from_certificate(cert);
|
||||
break;
|
||||
case CERT_TRUST_IS_UNTRUSTED_ROOT:
|
||||
*error_code = CERT_TRUST_IS_UNTRUSTED_ROOT_ERR_CODE;
|
||||
|
|
@ -153,7 +215,7 @@ get_cert_chain(PCCERT_CONTEXT certificate, /*out*/ const char **error_code)
|
|||
}
|
||||
|
||||
if (chain_ctx->TrustStatus.dwErrorStatus) {
|
||||
process_trust_status_error(chain_ctx->TrustStatus.dwErrorStatus, error_code);
|
||||
process_trust_status_error(certificate, chain_ctx->TrustStatus.dwErrorStatus, error_code);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
@ -220,6 +282,8 @@ verify_cert_chain(PCCERT_CONTEXT certificate, timer_context_t *timer_ctx, /*out*
|
|||
|
||||
LOG_TRACE("verify_cert_chain enter");
|
||||
|
||||
timer_on_verify_cert_chain_enter(timer_ctx);
|
||||
|
||||
timer_on_get_cert_chain_enter(timer_ctx);
|
||||
|
||||
PCCERT_CHAIN_CONTEXT chain_ctx = get_cert_chain(certificate, error_code);
|
||||
|
|
@ -240,6 +304,8 @@ exit:
|
|||
|
||||
LOG_DEBUG("cert_chain: %s", is_verified ? "verified" : "failed");
|
||||
|
||||
timer_on_verify_cert_chain_exit(timer_ctx);
|
||||
|
||||
LOG_DEBUG("verify_cert_chain exit");
|
||||
return is_verified;
|
||||
}
|
||||
|
|
@ -293,7 +359,6 @@ open_signer_cert(cryptopro_context_t *ctx)
|
|||
goto error;
|
||||
}
|
||||
|
||||
|
||||
LOG_TRACE("open_signer_cert exit");
|
||||
|
||||
return 0;
|
||||
|
|
@ -353,14 +418,10 @@ sign_hash_data(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t
|
|||
BYTE *pbSignedMessageBlob;
|
||||
DWORD cbSignedMessageBlob;
|
||||
|
||||
timer_on_verify_cert_chain_enter(ctx->timer_ctx);
|
||||
|
||||
if (!verify_cert_chain(ctx->signer_cert, ctx->timer_ctx, error_code)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
timer_on_verify_cert_chain_exit(ctx->timer_ctx);
|
||||
|
||||
timer_on_acquire_private_key_enter(ctx->timer_ctx);
|
||||
|
||||
if (!cp_function_list.CryptAcquireCertificatePrivateKey(
|
||||
|
|
@ -394,6 +455,10 @@ sign_hash_data(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t
|
|||
}
|
||||
|
||||
pbSignedMessageBlob = malloc(cbSignedMessageBlob * sizeof(BYTE));
|
||||
if (pbSignedMessageBlob == NULL) {
|
||||
LOG_ERROR("Could not allocate memory for pbSignedMessageBlob (%zd bytes)", cbSignedMessageBlob * sizeof(BYTE));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!cp_function_list.CryptSignHash(hash, AT_KEYEXCHANGE, NULL, 0, pbSignedMessageBlob, &cbSignedMessageBlob)) {
|
||||
LOG_ERROR("CryptSignHash() failed");
|
||||
|
|
@ -703,6 +768,8 @@ get_verify_error(char** verify_error)
|
|||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("verify error: %s", *verify_error);
|
||||
|
||||
LOG_TRACE("get_verify_error exit");
|
||||
}
|
||||
|
||||
|
|
@ -743,14 +810,10 @@ cryptopro_verify(cryptopro_context_t* ctx, const str_t* alg, const str_t* data,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
timer_on_verify_cert_chain_enter(ctx->timer_ctx);
|
||||
|
||||
if (!verify_cert_chain(certificate, ctx->timer_ctx, error_code)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
timer_on_verify_cert_chain_exit(ctx->timer_ctx);
|
||||
|
||||
LOG_DEBUG("provider: '%s', prov_type: %u", ctx->provider, ctx->prov_type);
|
||||
|
||||
if (!cp_function_list.CryptAcquireContext(&hCryptProv, NULL, ctx->provider, ctx->prov_type,
|
||||
|
|
@ -842,6 +905,224 @@ exit:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static bool
|
||||
get_subject_name(PCCERT_CONTEXT cert, /*out*/ char **subject_name)
|
||||
{
|
||||
LOG_TRACE("get_subject_name enter");
|
||||
|
||||
DWORD len = cp_function_list.CertNameToStr(
|
||||
cert->dwCertEncodingType,
|
||||
&cert->pCertInfo->Subject,
|
||||
CERT_X500_NAME_STR,
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
|
||||
*subject_name = malloc(len);
|
||||
if (*subject_name == NULL) {
|
||||
LOG_ERROR("Could not allocate memory for Subject Name str (%d bytes)", len);
|
||||
goto error;
|
||||
}
|
||||
|
||||
cp_function_list.CertNameToStr(
|
||||
cert->dwCertEncodingType,
|
||||
&cert->pCertInfo->Subject,
|
||||
CERT_X500_NAME_STR,
|
||||
*subject_name,
|
||||
len
|
||||
);
|
||||
|
||||
LOG_DEBUG("Subject Name: %s", *subject_name);
|
||||
|
||||
LOG_TRACE("get_subject_name exit");
|
||||
return true;
|
||||
|
||||
error:
|
||||
free(*subject_name);
|
||||
LOG_ERROR("get_subject_name exit with error");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
get_issuer_name(PCCERT_CONTEXT cert, /*out*/ char **issuer_name)
|
||||
{
|
||||
LOG_TRACE("get_issuer_name enter");
|
||||
|
||||
DWORD len = cp_function_list.CertNameToStr(
|
||||
cert->dwCertEncodingType,
|
||||
&cert->pCertInfo->Issuer,
|
||||
CERT_X500_NAME_STR,
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
|
||||
*issuer_name = malloc(len);
|
||||
if (*issuer_name == NULL) {
|
||||
LOG_ERROR("Could not allocate memory for Issuer Name str (%d bytes)", len);
|
||||
goto error;
|
||||
}
|
||||
|
||||
cp_function_list.CertNameToStr(
|
||||
cert->dwCertEncodingType,
|
||||
&cert->pCertInfo->Issuer,
|
||||
CERT_X500_NAME_STR,
|
||||
*issuer_name,
|
||||
len
|
||||
);
|
||||
|
||||
LOG_DEBUG("Issuer Name: %s", *issuer_name);
|
||||
|
||||
LOG_TRACE("get_issuer_name exit");
|
||||
return true;
|
||||
|
||||
error:
|
||||
free(*issuer_name);
|
||||
LOG_ERROR("get_issuer_name exit with error");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
get_signer_cert_info(PCCERT_CONTEXT signer_cert, cert_info_t *signer_cert_info)
|
||||
{
|
||||
LOG_TRACE("get_signer_cert_info enter");
|
||||
|
||||
if (!get_subject_name(signer_cert, &signer_cert_info->subject)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!get_issuer_name(signer_cert, &signer_cert_info->issuer)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
LOG_TRACE("get_signer_cert_info exit");
|
||||
return true;
|
||||
|
||||
error:
|
||||
LOG_ERROR("get_signer_cert_info exit with error");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Проверка количества подписантов сообщения
|
||||
* Предполагается, что количество подписантов должно быть равно 1
|
||||
*/
|
||||
static bool
|
||||
check_message_signer_count(const str_t *sign)
|
||||
{
|
||||
int signer_count = cp_function_list.CryptGetMessageSignerCount(
|
||||
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
|
||||
(const BYTE *) sign->data,
|
||||
(DWORD) sign->len);
|
||||
|
||||
LOG_DEBUG("signer count = %d", signer_count);
|
||||
|
||||
if (signer_count == 1) {
|
||||
LOG_DEBUG("signer count is ok");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (signer_count < 0) {
|
||||
LOG_ERROR("Could not get signer count. Last error code: 0x%08x",
|
||||
cp_function_list.GetLastError());
|
||||
} else {
|
||||
LOG_ERROR("Invalid signer count: %d", signer_count);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Проверка подписи и извлечение сертификата подписанта
|
||||
* Предполагается, что количество подписантов проверено и равно 1
|
||||
*/
|
||||
static bool
|
||||
verify_detached_message_signature(const str_t *data, const str_t *sign,
|
||||
timer_context_t *timer_ctx,
|
||||
/*out*/ PCCERT_CONTEXT *signer_cert)
|
||||
{
|
||||
LOG_TRACE("verify_detached_message_signature enter");
|
||||
|
||||
timer_on_verify_detached_message_signature_enter(timer_ctx);
|
||||
|
||||
CRYPT_VERIFY_MESSAGE_PARA verifyParams = {
|
||||
.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA),
|
||||
.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING
|
||||
};
|
||||
|
||||
BOOL r = cp_function_list.CryptVerifyDetachedMessageSignature(
|
||||
&verifyParams,
|
||||
0, // индекс проверяемой подписи
|
||||
(CONST BYTE *) sign->data,
|
||||
sign->len,
|
||||
1, // количество подписанных сообщений
|
||||
(const BYTE **) &(data->data),
|
||||
(DWORD*) &(data->len),
|
||||
signer_cert
|
||||
);
|
||||
|
||||
timer_on_verify_detached_message_signature_exit(timer_ctx);
|
||||
|
||||
LOG_TRACE("verify_detached_message_signature exit");
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
cryptopro_verify_detached(cryptopro_context_t *ctx, const str_t *data, const str_t *sign,
|
||||
bool *is_verified, /*out*/ cert_info_t *signer_cert_info,
|
||||
/*out*/ char **verify_error, /*out*/ const char **error_code)
|
||||
{
|
||||
LOG_TRACE("cryptopro_verify_detached enter");
|
||||
|
||||
timer_on_cryptopro_verify_detached_enter(ctx->timer_ctx);
|
||||
|
||||
*is_verified = false;
|
||||
PCCERT_CONTEXT signer_cert = NULL;
|
||||
|
||||
if (!check_message_signer_count(sign)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (verify_detached_message_signature(data, sign, ctx->timer_ctx, &signer_cert)) {
|
||||
LOG_DEBUG("sign is valid");
|
||||
|
||||
if (!check_cert_key_usage(signer_cert)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!verify_cert_chain(signer_cert, ctx->timer_ctx, error_code)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!get_signer_cert_info(signer_cert, signer_cert_info)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
*is_verified = true;
|
||||
|
||||
} else {
|
||||
LOG_DEBUG("sign is invalid");
|
||||
get_verify_error(verify_error);
|
||||
}
|
||||
|
||||
if (signer_cert != NULL) {
|
||||
cp_function_list.CertFreeCertificateContext(signer_cert);
|
||||
}
|
||||
|
||||
timer_on_cryptopro_verify_detached_exit(ctx->timer_ctx);
|
||||
|
||||
LOG_TRACE("cryptopro_verify_detached exit");
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (signer_cert != NULL) {
|
||||
cp_function_list.CertFreeCertificateContext(signer_cert);
|
||||
}
|
||||
|
||||
LOG_ERROR("cryptopro_verify_detached exit with error. Last error code: 0x%08x",
|
||||
cp_function_list.GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
cryptopro_gen_random(const cryptopro_context_t *ctx, unsigned char* data, size_t len)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue