diff --git a/src/utils/capi.c b/src/utils/capi.c index 5cc5f8a..4bf63ba 100644 --- a/src/utils/capi.c +++ b/src/utils/capi.c @@ -32,6 +32,7 @@ capi_function_list_init(library_t *lib, capi_function_list_t *fl) LIBRARY_RESOLVE(fl->CertVerifyCertificateChainPolicy, lib, "CertVerifyCertificateChainPolicy"); LIBRARY_RESOLVE(fl->CertFreeCertificateChain, lib, "CertFreeCertificateChain"); LIBRARY_RESOLVE(fl->CryptGenRandom, lib, "CryptGenRandom"); + LIBRARY_RESOLVE(fl->CertGetIntendedKeyUsage, lib, "CertGetIntendedKeyUsage"); #ifdef UNICODE LIBRARY_RESOLVE(fl->CryptSignHash, lib, "CryptSignHashW"); diff --git a/src/utils/capi.h b/src/utils/capi.h index ba5ed09..f19b875 100644 --- a/src/utils/capi.h +++ b/src/utils/capi.h @@ -207,6 +207,14 @@ DECLARE_FN(WINADVAPI, DWORD dwLen, BYTE *pbBuffer)); +DECLARE_FN(WINADVAPI, + BOOL, + CERT_GET_INTENDED_KEY_USAGE, + (DWORD dwCertEncodingType, + PCERT_INFO pCertInfo, + BYTE *pbKeyUsage, + IN DWORD cbKeyUsage)); + #ifdef UNICODE #define CRYPT_SIGN_HASH_FN CRYPT_SIGN_HASH_W_FN #define CRYPT_VERIFY_SIGNATURE_FN CRYPT_VERIFY_SIGNATURE_W_FN @@ -241,6 +249,7 @@ typedef struct { CERT_VERIFY_CERTIFICATE_CHAIN_POLICY_FN CertVerifyCertificateChainPolicy; CERT_FREE_CERTIFICATE_CHAIN_FN CertFreeCertificateChain; CRYPT_GEN_RANDOM_FN CryptGenRandom; + CERT_GET_INTENDED_KEY_USAGE_FN CertGetIntendedKeyUsage; } capi_function_list_t; diff --git a/src/utils/cryptopro.c b/src/utils/cryptopro.c index a6e2833..10422f2 100644 --- a/src/utils/cryptopro.c +++ b/src/utils/cryptopro.c @@ -210,26 +210,34 @@ exit: return is_verified; } -static void -log_sign_hash_data_last_error() +static bool +check_cert_key_usage(PCCERT_CONTEXT certificate) { - DWORD error = cp_function_list.GetLastError(); + bool is_digital_signature_key_usage = false; + BYTE key_usage; - switch (error) { - case ERROR_FUNCTION_FAILED: - LOG_ERROR("sign_hash_data exit with error. Last error code: " - "license is expired or not yet valid (0x%08x)", error); - break; + LOG_TRACE("check_cert_key_usage enter"); - case SCARD_W_WRONG_CHV: - LOG_ERROR("sign_hash_data exit with error. Last error code: " - "the wrong PIN was presented (0x%08x)", error); - break; - - default: - LOG_ERROR("sign_hash_data exit with error. Last error code: 0x%08x", error); - break; + if (cp_function_list.CertGetIntendedKeyUsage( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + certificate->pCertInfo, + &key_usage, + sizeof(key_usage))) { + if (key_usage & CERT_DIGITAL_SIGNATURE_KEY_USAGE) { + is_digital_signature_key_usage = true; + } + } else { + LOG_ERROR("CertGetIntendedKeyUsage failed: 0x%08x", cp_function_list.GetLastError()); } + + if (is_digital_signature_key_usage) { + LOG_DEBUG("Certificate KeyUsage contains digitalSignature"); + } else { + LOG_ERROR("Certificate KeyUsage does not contain digitalSignature"); + } + + LOG_TRACE("check_cert_key_usage exit"); + return is_digital_signature_key_usage; } int @@ -247,6 +255,11 @@ open_signer_cert(cryptopro_context_t *ctx) goto error; } + if (!check_cert_key_usage(ctx->signer_cert)) { + goto error; + } + + LOG_TRACE("open_signer_cert exit"); return 0; @@ -274,6 +287,28 @@ close_signer_cert(cryptopro_context_t *ctx) LOG_TRACE("close_signer_cert exit"); } +static void +log_sign_hash_data_last_error() +{ + DWORD error = cp_function_list.GetLastError(); + + switch (error) { + case ERROR_FUNCTION_FAILED: + LOG_ERROR("sign_hash_data exit with error. Last error code: " + "license is expired or not yet valid (0x%08x)", error); + break; + + case SCARD_W_WRONG_CHV: + LOG_ERROR("sign_hash_data exit with error. Last error code: " + "the wrong PIN was presented (0x%08x)", error); + break; + + default: + LOG_ERROR("sign_hash_data exit with error. Last error code: 0x%08x", error); + break; + } +} + static int sign_hash_data(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t *sign) {