SUPPORT-8455. Реализован модуль подписания
This commit is contained in:
commit
4243ebae5e
42 changed files with 4889 additions and 0 deletions
295
src/utils/cryptopro.c
Normal file
295
src/utils/cryptopro.c
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
#include "cryptopro.h"
|
||||
|
||||
#include "base64.h"
|
||||
#include "capi.h"
|
||||
#include "library.h"
|
||||
#include "logger.h"
|
||||
|
||||
static capi_function_list_t cp_function_list;
|
||||
static library_t libcapi;
|
||||
|
||||
static int sign_hash_data(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t *sign);
|
||||
|
||||
static int reverse_sign(const str_t *sign, /*out*/ str_t *sign_reversed);
|
||||
|
||||
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);
|
||||
|
||||
bool
|
||||
cryptopro_init(const char* cp_file)
|
||||
{
|
||||
static bool is_initialized = false;
|
||||
|
||||
if (!is_initialized) {
|
||||
library_init(&libcapi, cp_file);
|
||||
if (!capi_function_list_init(&libcapi, &cp_function_list)) {
|
||||
LOG_ERROR("capi_function_list_init failed");
|
||||
return false;
|
||||
}
|
||||
is_initialized = true;
|
||||
LOG_INFO("Cryptographic Provider initialized");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
cryptopro_sign(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t *sign)
|
||||
{
|
||||
str_t signed_data = str_t_null;
|
||||
str_t sign_reversed = str_t_null;
|
||||
|
||||
LOG_TRACE("cryptopro_sign enter");
|
||||
|
||||
assert(ctx != NULL);
|
||||
assert(ctx->signer != NULL);
|
||||
assert(ctx->pin != NULL);
|
||||
assert(data != NULL && !str_t_is_null(*data));
|
||||
assert(sign != NULL);
|
||||
|
||||
if (sign_hash_data(ctx, data, &signed_data)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (reverse_sign(&signed_data, &sign_reversed)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
sign->len = base64_encoded_length(sign_reversed.len);
|
||||
sign->data = calloc(1, sign->len + 1);
|
||||
if (sign->data == NULL) {
|
||||
LOG_ERROR("Could not allocate memory for sign (%zu bytes)", sign->len + 1);
|
||||
goto error;
|
||||
}
|
||||
|
||||
encode_base64_url(sign, &sign_reversed);
|
||||
|
||||
str_t_clear(&signed_data);
|
||||
str_t_clear(&sign_reversed);
|
||||
|
||||
LOG_TRACE("cryptopro_sign exit");
|
||||
return 0;
|
||||
|
||||
error:
|
||||
str_t_clear(&signed_data);
|
||||
str_t_clear(&sign_reversed);
|
||||
LOG_ERROR("cryptopro_sign exit with error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
sign_hash_data(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t *sign)
|
||||
{
|
||||
int rc = -1;
|
||||
HCERTSTORE hStoreHandle;
|
||||
PCCERT_CONTEXT pSignerCert = NULL;
|
||||
BOOL bReleaseContext = FALSE;
|
||||
HCRYPTPROV hCryptProv;
|
||||
HCRYPTHASH hash = 0;
|
||||
BYTE *pbSignedMessageBlob;
|
||||
DWORD cbSignedMessageBlob;
|
||||
|
||||
hStoreHandle = cert_open_store();
|
||||
if (hStoreHandle == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
pSignerCert = get_signer_cert(ctx, hStoreHandle);
|
||||
if (pSignerCert == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!cp_function_list.CryptAcquireCertificatePrivateKey(
|
||||
pSignerCert,
|
||||
CRYPT_ACQUIRE_SILENT_FLAG,
|
||||
NULL,
|
||||
&hCryptProv,
|
||||
NULL,
|
||||
&bReleaseContext)) {
|
||||
LOG_ERROR("Cannot acquire the certificate private key");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!cp_function_list.CryptCreateHash(hCryptProv, CALG_GR3411_2012_256, 0, 0, &hash)) {
|
||||
LOG_ERROR("CryptCreateHash() failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!cp_function_list.CryptHashData(hash, (BYTE *)data->data, data->len, 0)) {
|
||||
LOG_ERROR("CryptHashData() failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!cp_function_list.CryptSignHash(hash, AT_KEYEXCHANGE, NULL, 0, NULL, &cbSignedMessageBlob)) {
|
||||
LOG_ERROR("CryptSignHash() failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
pbSignedMessageBlob = malloc(cbSignedMessageBlob * sizeof(BYTE));
|
||||
|
||||
if (!cp_function_list.CryptSignHash(hash, AT_KEYEXCHANGE, NULL, 0, pbSignedMessageBlob, &cbSignedMessageBlob)) {
|
||||
LOG_ERROR("CryptSignHash() failed");
|
||||
free(pbSignedMessageBlob);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sign->data = (char*)pbSignedMessageBlob;
|
||||
sign->len = (size_t)cbSignedMessageBlob;
|
||||
|
||||
rc = 0;
|
||||
|
||||
exit:
|
||||
if (hash) {
|
||||
cp_function_list.CryptDestroyHash(hash);
|
||||
}
|
||||
|
||||
if (bReleaseContext) {
|
||||
cp_function_list.CryptReleaseContext(hCryptProv, 0);
|
||||
}
|
||||
|
||||
if (pSignerCert) {
|
||||
cp_function_list.CertFreeCertificateContext(pSignerCert);
|
||||
}
|
||||
|
||||
if (hStoreHandle) {
|
||||
if (!cp_function_list.CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_CHECK_FLAG)) {
|
||||
LOG_ERROR("CertCloseStore() failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
LOG_ERROR("sign_hash_data exit with error. Last error code: 0x%08x", cp_function_list.GetLastError());
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
reverse_sign(const str_t *sign, /*out*/ str_t *sign_reversed)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
sign_reversed->data = malloc(sign->len);
|
||||
if (sign_reversed->data == NULL) {
|
||||
LOG_ERROR("Could not allocate memory for reversed sign (%zd bytes)", sign->len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < sign->len; i++) {
|
||||
sign_reversed->data[i] = sign->data[sign->len - i - 1];
|
||||
}
|
||||
|
||||
sign_reversed->len = sign->len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HCERTSTORE
|
||||
cert_open_store()
|
||||
{
|
||||
HCERTSTORE hStoreHandle;
|
||||
|
||||
LOG_TRACE("cert_open_store enter");
|
||||
|
||||
hStoreHandle = cp_function_list.CertOpenStore(CERT_STORE_PROV_SYSTEM,
|
||||
0,
|
||||
0,
|
||||
CERT_SYSTEM_STORE_CURRENT_USER,
|
||||
L"MY");
|
||||
|
||||
if (hStoreHandle == NULL) {
|
||||
LOG_ERROR("The store could not be opened");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_DEBUG("The MY store is open");
|
||||
|
||||
return hStoreHandle;
|
||||
}
|
||||
|
||||
static PCCERT_CONTEXT
|
||||
get_signer_cert(const cryptopro_context_t *ctx, HCERTSTORE hStoreHandle)
|
||||
{
|
||||
PCCERT_CONTEXT pSignerCert;
|
||||
|
||||
pSignerCert = cp_function_list.CertFindCertificateInStore(hStoreHandle,
|
||||
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
0,
|
||||
CERT_FIND_SUBJECT_STR,
|
||||
ctx->signer,
|
||||
NULL);
|
||||
if (pSignerCert == NULL) {
|
||||
LOG_ERROR("Could not find certificate in store");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (set_pin(pSignerCert, ctx->pin)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
LOG_DEBUG("The signer's certificate was found");
|
||||
return pSignerCert;
|
||||
|
||||
error:
|
||||
if (pSignerCert) {
|
||||
cp_function_list.CertFreeCertificateContext(pSignerCert);
|
||||
}
|
||||
LOG_ERROR("get_signer_cert exit with error");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
set_pin(PCCERT_CONTEXT pSignerCert, const str_t *pin)
|
||||
{
|
||||
DWORD dwSize;
|
||||
if (!cp_function_list.CertGetCertificateContextProperty(
|
||||
pSignerCert,
|
||||
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());
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char pKeyInfoBuffer[dwSize];
|
||||
CRYPT_KEY_PROV_INFO* pKeyInfo = (CRYPT_KEY_PROV_INFO*) pKeyInfoBuffer;
|
||||
|
||||
if (!cp_function_list.CertGetCertificateContextProperty(
|
||||
pSignerCert,
|
||||
CERT_KEY_PROV_INFO_PROP_ID,
|
||||
pKeyInfo,
|
||||
&dwSize)){
|
||||
LOG_ERROR("The second call to the function failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
DWORD keyType = (pKeyInfo->dwKeySpec == AT_SIGNATURE) ? PP_SIGNATURE_PIN
|
||||
: PP_KEYEXCHANGE_PIN;
|
||||
|
||||
CRYPT_KEY_PROV_PARAM keyProvParam;
|
||||
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;
|
||||
|
||||
pKeyInfo->cProvParam = 1;
|
||||
pKeyInfo->rgProvParam = &keyProvParam;
|
||||
|
||||
if (!cp_function_list.CertSetCertificateContextProperty(
|
||||
pSignerCert,
|
||||
CERT_KEY_PROV_INFO_PROP_ID,
|
||||
0,
|
||||
pKeyInfo)) {
|
||||
LOG_ERROR("Error setting key property");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
LOG_ERROR("set_pin exit with error. Last error code: 0x%08x", cp_function_list.GetLastError());
|
||||
return -1;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue