SUPPORT-8592. Проверка подписи маркера доступа

This commit is contained in:
Наиля Алашкова 2024-11-14 12:16:55 +03:00
parent 9e85e4e8de
commit 4fa45a1f5e
46 changed files with 1970 additions and 250 deletions

View file

@ -16,7 +16,7 @@ static HCERTSTORE cert_open_store();
static PCCERT_CONTEXT get_signer_cert(const cryptopro_context_t *ctx, HCERTSTORE hStoreHandle);
static int set_pin(PCCERT_CONTEXT pSignerCert, const str_t *pin);
static int set_password(PCCERT_CONTEXT cert_ctx, const str_t *password);
bool
cryptopro_init(const char* cp_file)
@ -44,8 +44,8 @@ cryptopro_sign(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t
LOG_TRACE("cryptopro_sign enter");
assert(ctx != NULL);
assert(ctx->signer != NULL);
assert(ctx->pin != NULL);
assert(!str_t_is_null(*ctx->cert_thumbprint));
assert(ctx->password != NULL);
assert(data != NULL && !str_t_is_null(*data));
assert(sign != NULL);
@ -209,47 +209,78 @@ cert_open_store()
}
static PCCERT_CONTEXT
get_signer_cert(const cryptopro_context_t *ctx, HCERTSTORE hStoreHandle)
get_cert_by_thumbprint(HCERTSTORE hStoreHandle, const str_t* thumbprint)
{
PCCERT_CONTEXT pSignerCert;
str_t thumbprint_bin = str_t_null;
pSignerCert = cp_function_list.CertFindCertificateInStore(hStoreHandle,
LOG_TRACE("get_cert_by_thumbprint enter");
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_SUBJECT_STR,
ctx->signer,
CERT_FIND_HASH,
&hash,
NULL);
if (pSignerCert == NULL) {
if (cert == NULL) {
LOG_ERROR("Could not find certificate in store");
goto error;
}
if (set_pin(pSignerCert, ctx->pin)) {
str_t_clear(&thumbprint_bin);
LOG_TRACE("get_cert_by_thumbprint exit");
return cert;
error:
str_t_clear(&thumbprint_bin);
LOG_ERROR("get_cert_by_thumbprint exit with error");
return NULL;
}
static PCCERT_CONTEXT
get_signer_cert(const cryptopro_context_t *ctx, HCERTSTORE hStoreHandle)
{
PCCERT_CONTEXT cert_ctx = get_cert_by_thumbprint(hStoreHandle, ctx->cert_thumbprint);
if (cert_ctx == NULL) {
goto error;
}
if (set_password(cert_ctx, ctx->password)) {
goto error;
}
LOG_DEBUG("The signer's certificate was found");
return pSignerCert;
return cert_ctx;
error:
if (pSignerCert) {
cp_function_list.CertFreeCertificateContext(pSignerCert);
if (cert_ctx) {
cp_function_list.CertFreeCertificateContext(cert_ctx);
}
LOG_ERROR("get_signer_cert exit with error");
return NULL;
}
static int
set_pin(PCCERT_CONTEXT pSignerCert, const str_t *pin)
set_password(PCCERT_CONTEXT cert_ctx, const str_t *password)
{
DWORD dwSize;
if (!cp_function_list.CertGetCertificateContextProperty(
pSignerCert,
cert_ctx,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&dwSize)) {
LOG_ERROR("Error getting key property");
LOG_ERROR("set_pin exit with error. Last error code: 0x%08x", cp_function_list.GetLastError());
LOG_ERROR("set_password exit with error. Last error code: 0x%08x", cp_function_list.GetLastError());
return -1;
}
@ -257,7 +288,7 @@ set_pin(PCCERT_CONTEXT pSignerCert, const str_t *pin)
CRYPT_KEY_PROV_INFO* pKeyInfo = (CRYPT_KEY_PROV_INFO*) pKeyInfoBuffer;
if (!cp_function_list.CertGetCertificateContextProperty(
pSignerCert,
cert_ctx,
CERT_KEY_PROV_INFO_PROP_ID,
pKeyInfo,
&dwSize)){
@ -272,14 +303,14 @@ set_pin(PCCERT_CONTEXT pSignerCert, const str_t *pin)
memset(&keyProvParam, 0, sizeof(CRYPT_KEY_PROV_PARAM));
keyProvParam.dwFlags = 0;
keyProvParam.dwParam = keyType;
keyProvParam.cbData = (DWORD)(pin->len + 1);
keyProvParam.pbData = (BYTE*) pin->data;
keyProvParam.cbData = (DWORD)(password->len + 1);
keyProvParam.pbData = (BYTE*) password->data;
pKeyInfo->cProvParam = 1;
pKeyInfo->rgProvParam = &keyProvParam;
if (!cp_function_list.CertSetCertificateContextProperty(
pSignerCert,
cert_ctx,
CERT_KEY_PROV_INFO_PROP_ID,
0,
pKeyInfo)) {
@ -290,6 +321,182 @@ set_pin(PCCERT_CONTEXT pSignerCert, const str_t *pin)
return 0;
error:
LOG_ERROR("set_pin exit with error. Last error code: 0x%08x", cp_function_list.GetLastError());
LOG_ERROR("set_password exit with error. Last error code: 0x%08x", cp_function_list.GetLastError());
return -1;
}
}
static int
alg_id_from_str(const str_t* alg, /*out*/ ALG_ID* alg_id)
{
LOG_TRACE("alg_id_from_str enter");
if (strncmp(alg->data, "GOST3410_2012_256", alg->len) == 0) {
*alg_id = CALG_GR3411_2012_256;
} else if (strncmp(alg->data, "GOST3410_2012_512", alg->len) == 0) {
*alg_id = CALG_GR3411_2012_512;
} else if (strncmp(alg->data, "RS256", alg->len) == 0) {
*alg_id = CALG_SHA_256;
} else {
LOG_ERROR("Unknown alg: '%.*s'", (int) alg->len, alg->data);
LOG_ERROR("alg_id_from_str exit with error");
return -1;
}
LOG_TRACE("alg_id_from_str exit");
return 0;
}
static void
get_verify_error(char** verify_error)
{
LOG_TRACE("get_verify_error enter");
DWORD err = cp_function_list.GetLastError();
const char* err_string;
switch (err) {
case NTE_BAD_SIGNATURE:
err_string = "sign is invalid: bad signature (0x%08x)";
break;
case NTE_BAD_ALGID:
err_string = "sign is invalid: bad alg id (0x%08x)";
break;
default:
err_string = "sign is invalid. Last error code: 0x%08x";
break;
}
size_t size = strlen(err_string) + 4 /*error code*/ + 1 /*terminating null*/;
*verify_error = malloc(size);
if (*verify_error == NULL) {
LOG_ERROR("get_verify_error failed. Could not allocate memory for error string "
"(%zd bytes)", size);
return;
}
int n = snprintf(*verify_error, size, err_string, err);
if (n < 0 || (size_t)n >= size) {
LOG_ERROR("get_verify_error failed. Error occurred in concatenation err_string");
free(*verify_error);
*verify_error = NULL;
return;
}
LOG_TRACE("get_verify_error exit");
}
int
cryptopro_verify(const str_t* cert_thumbprint, const str_t* alg, const str_t* data,
const str_t* sign, bool* is_verified, char** verify_error)
{
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 {
get_verify_error(verify_error);
if (*verify_error == NULL) {
goto exit;
}
LOG_WARN("%s", *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;
}