SUPPORT-8592. Проверка подписи маркера доступа
This commit is contained in:
parent
9e85e4e8de
commit
4fa45a1f5e
46 changed files with 1970 additions and 250 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue