SUPPORT-8592. Добавлен cryptopro_verify()

This commit is contained in:
alashkova 2024-10-15 15:46:30 +03:00
parent 17aec4de8b
commit 503287af7f
4 changed files with 255 additions and 1 deletions

View file

@ -26,11 +26,17 @@ capi_function_list_init(library_t *lib, capi_function_list_t *fl)
LIBRARY_RESOLVE(fl->CryptReleaseContext, lib, "CryptReleaseContext");
LIBRARY_RESOLVE(fl->CryptSignMessage, lib, "CryptSignMessage");
LIBRARY_RESOLVE(fl->GetLastError, lib, "GetLastError");
LIBRARY_RESOLVE(fl->CryptImportPublicKeyInfo, lib, "CryptImportPublicKeyInfo");
LIBRARY_RESOLVE(fl->CryptDestroyKey, lib, "CryptDestroyKey");
#ifdef UNICODE
LIBRARY_RESOLVE(fl->CryptSignHash, lib, "CryptSignHashW");
LIBRARY_RESOLVE(fl->CryptVerifySignature, lib, "CryptVerifySignatureW");
LIBRARY_RESOLVE(fl->CryptAcquireContext, lib, "CryptAcquireContextW");
#else
LIBRARY_RESOLVE(fl->CryptSignHash, lib, "CryptSignHashA");
LIBRARY_RESOLVE(fl->CryptVerifySignature, lib, "CryptVerifySignatureA");
LIBRARY_RESOLVE(fl->CryptAcquireContext, lib, "CryptAcquireContextA");
#endif // !UNICODE
return true;

View file

@ -124,10 +124,65 @@ DECLARE_FN(WINADVAPI,
BYTE *pbSignature,
DWORD *pdwSigLen));
DECLARE_FN(WINADVAPI,
BOOL,
CRYPT_VERIFY_SIGNATURE_A,
(HCRYPTHASH hHash,
CONST BYTE *pbSignature,
DWORD dwSigLen,
HCRYPTKEY hPubKey,
LPCSTR szDescription,
DWORD dwFlags));
DECLARE_FN(WINADVAPI,
BOOL,
CRYPT_VERIFY_SIGNATURE_W,
(HCRYPTHASH hHash,
CONST BYTE *pbSignature,
DWORD dwSigLen,
HCRYPTKEY hPubKey,
LPCWSTR szDescription,
DWORD dwFlags));
DECLARE_FN(WINADVAPI,
BOOL,
CRYPT_ACQUIRE_CONTEXT_A,
(HCRYPTPROV *phProv,
LPCSTR pszContainer,
LPCSTR pszProvider,
DWORD dwProvType,
DWORD dwFlags));
DECLARE_FN(WINADVAPI,
BOOL,
CRYPT_ACQUIRE_CONTEXT_W,
(HCRYPTPROV *phProv,
LPCSTR pszContainer,
LPCSTR pszProvider,
DWORD dwProvType,
DWORD dwFlags));
DECLARE_FN(WINADVAPI,
BOOL,
CRYPT_IMPORT_PUBLIC_KEY_INFO,
(HCRYPTPROV hCryptProv,
DWORD dwCertEncodingType,
PCERT_PUBLIC_KEY_INFO pInfo,
HCRYPTKEY *phKey));
DECLARE_FN(WINADVAPI,
BOOL,
CRYPT_DESTROY_KEY,
(HCRYPTKEY hKey));
#ifdef UNICODE
#define CRYPT_SIGN_HASH_FN CRYPT_SIGN_HASH_W_FN
#define CRYPT_VERIFY_SIGNATURE_FN CRYPT_VERIFY_SIGNATURE_W_FN
#define CRYPT_ACQUIRE_CONTEXT_FN CRYPT_ACQUIRE_CONTEXT_W_FN
#else
#define CRYPT_SIGN_HASH_FN CRYPT_SIGN_HASH_A_FN
#define CRYPT_VERIFY_SIGNATURE_FN CRYPT_VERIFY_SIGNATURE_A_FN
#define CRYPT_ACQUIRE_CONTEXT_FN CRYPT_ACQUIRE_CONTEXT_A_FN
#endif // !UNICODE
@ -146,6 +201,11 @@ typedef struct {
CERT_FIND_CERTIFICATE_IN_STORE_FN CertFindCertificateInStore;
CERT_GET_CERTIFICATE_CONTEXT_PROPERTY_FN CertGetCertificateContextProperty;
CERT_SET_CERTIFICATE_CONTEXT_PROPERTY_FN CertSetCertificateContextProperty;
CRYPT_VERIFY_SIGNATURE_FN CryptVerifySignature;
CRYPT_ACQUIRE_CONTEXT_FN CryptAcquireContext;
CRYPT_IMPORT_PUBLIC_KEY_INFO_FN CryptImportPublicKeyInfo;
CRYPT_DESTROY_KEY_FN CryptDestroyKey;
} capi_function_list_t;

View file

@ -292,4 +292,189 @@ set_pin(PCCERT_CONTEXT pSignerCert, const str_t *pin)
error:
LOG_ERROR("set_pin exit with error. Last error code: 0x%08x", cp_function_list.GetLastError());
return -1;
}
}
static PCCERT_CONTEXT
get_cert_by_thumbprint(HCERTSTORE hStoreHandle, const str_t* thumbprint)
{
str_t thumbprint_bin = str_t_null;
if (hex_to_bin(thumbprint, &thumbprint_bin)) {
goto error;
}
CRYPT_HASH_BLOB hash = {
.pbData = (BYTE*)thumbprint_bin.data,
.cbData = thumbprint_bin.len
};
PCCERT_CONTEXT cert = cp_function_list.CertFindCertificateInStore(hStoreHandle,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CERT_FIND_HASH,
&hash,
NULL);
if (cert == NULL) {
LOG_ERROR("Could not find certificate in store");
goto error;
}
str_t_clear(&thumbprint_bin);
return cert;
error:
str_t_clear(&thumbprint_bin);
LOG_ERROR("get_cert_by_thumbprint exit with error");
return NULL;
}
static int
alg_id_from_str(const str_t* alg, /*out*/ ALG_ID* alg_id)
{
LOG_TRACE("alg_id_from_str");
if (strncmp(alg->data, "GOST3410_2012_256", alg->len) == 0) {
*alg_id = CALG_GR3411_2012_256;
return 0;
}
if (strncmp(alg->data, "GOST3410_2012_512", alg->len) == 0) {
*alg_id = CALG_GR3411_2012_512;
return 0;
}
if (strncmp(alg->data, "RS256", alg->len) == 0) {
*alg_id = CALG_SHA_256;
return 0;
}
LOG_ERROR("Unknown alg: '%.*s'", (int) alg->len, alg->data);
LOG_ERROR("alg_id_from_str exit with error");
return -1;
}
static void
log_verify_error()
{
DWORD err = cp_function_list.GetLastError();
switch (err) {
case NTE_BAD_SIGNATURE:
LOG_WARN("sign is invalid: bad signature (0x%08x)", err);
break;
case NTE_BAD_ALGID:
LOG_WARN("sign is invalid: bad alg id (0x%08x)", err);
break;
default:
LOG_WARN("sign is invalid. Last error code: 0x%08x", err);
break;
}
}
int
cryptopro_verify(const str_t* cert_thumbprint, const str_t* alg, const str_t *data,
const str_t *sign, bool* is_verified)
{
int rc = -1;
HCERTSTORE hStoreHandle = NULL;
PCCERT_CONTEXT certificate = NULL;
HCRYPTPROV hCryptProv = 0;
HCRYPTHASH hash = 0;
HCRYPTKEY hPubKey = 0;
str_t sign_reversed = str_t_null;
ALG_ID alg_id;
LOG_TRACE("cryptopro_verify enter");
*is_verified = false;
if (alg_id_from_str(alg, &alg_id)) {
goto exit;
}
if (reverse_sign(sign, &sign_reversed)) {
goto exit;
}
hStoreHandle = cert_open_store();
if (hStoreHandle == NULL) {
goto exit;
}
certificate = get_cert_by_thumbprint(hStoreHandle, cert_thumbprint);
if (certificate == NULL) {
goto exit;
}
if (!cp_function_list.CryptAcquireContext(&hCryptProv, NULL, CP_KC1_GR3410_2001_PROV,
PROV_GOST_2001_DH, CRYPT_VERIFYCONTEXT)) {
LOG_ERROR("CryptAcquireContext() failed");
goto exit;
}
if (!cp_function_list.CryptImportPublicKeyInfo(hCryptProv, X509_ASN_ENCODING,
&certificate->pCertInfo->SubjectPublicKeyInfo,
&hPubKey)) {
LOG_ERROR("CryptImportPublicKeyInfo() failed");
goto exit;
}
if (!cp_function_list.CryptCreateHash(hCryptProv, alg_id, 0, 0, &hash)) {
LOG_ERROR("CryptCreateHash() failed");
goto exit;
}
if (!cp_function_list.CryptHashData(hash, (CONST BYTE *) data->data, data->len, 0)) {
LOG_ERROR("CryptHashData() failed");
goto exit;
}
if (cp_function_list.CryptVerifySignature(hash,
(CONST BYTE *) sign_reversed.data,
sign_reversed.len,
hPubKey,
NULL,
0)) {
LOG_DEBUG("sign is valid");
*is_verified = true;
} else {
log_verify_error();
}
rc = 0;
exit:
str_t_clear(&sign_reversed);
if (hash) {
cp_function_list.CryptDestroyHash(hash);
}
if (hPubKey) {
cp_function_list.CryptDestroyKey(hPubKey);
}
if (hCryptProv) {
cp_function_list.CryptReleaseContext(hCryptProv, 0);
}
if (certificate) {
cp_function_list.CertFreeCertificateContext(certificate);
}
if (hStoreHandle) {
if (!cp_function_list.CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_CHECK_FLAG)) {
LOG_ERROR("CertCloseStore() failed");
}
}
if (rc == 0) {
LOG_TRACE("cryptopro_verify exit");
} else {
LOG_ERROR("cryptopro_verify exit with error. Last error code: 0x%08x",
cp_function_list.GetLastError());
}
return rc;
}

View file

@ -26,4 +26,7 @@ bool cryptopro_init(const char* cp_file);
int cryptopro_sign(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t *sign);
int cryptopro_verify(const str_t* cert_thumbprint, const str_t* alg, const str_t *data,
const str_t *sign, bool* is_verified);
#endif // CRYPTOPRO_H_INCLUDED