#include "test_common.h"

CK_RV test_crypto();
CK_RV test_gost28147_pkcs8_key_wrap(CK_SESSION_HANDLE sess);

int main(int argc, char *argv[])
{
    CK_RV rc = CKR_OK;

    rc = test_main(argc, argv);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "test_main failed: 0x%lx\n", rc);
        return rc;
    }
    rc = test_crypto();
    if (rc != CKR_OK)
    {
        fprintf(stderr, "test_crypto failed: 0x%lx\n", rc);
        return rc;
    }
    return CKR_OK;
}

CK_RV test_crypto()
{
    CK_RV             rc;
    CK_SESSION_HANDLE hSession;
    CK_MECHANISM_INFO minfo;

    printf(
        "CKM_GOST28147_PKCS8_KEY_WRAP "
        "and CKM_GOSTR3410_PUBLIC_KEY_DERIVE test\n");

    rc = funcs->C_GetMechanismInfo(SlotId,
                                   CKM_GOSTR3410_KEY_PAIR_GEN, &minfo);
    if (rc != CKR_OK)
    {
        fprintf(stderr,
                "Mechanism CKM_GOSTR3410_KEY_PAIR_GEN not supported\n");
        return rc;
    }
    rc = funcs->C_GetMechanismInfo(SlotId,
                                   CKM_GOST28147_PKCS8_KEY_WRAP, &minfo);
    if (rc != CKR_OK)
    {
        fprintf(stderr,
                "Mechanism CKM_GOST28147_PKCS8_KEY_WRAP not supported\n");
        return rc;
    }
    rc = funcs->C_GetMechanismInfo(SlotId,
                                   CKM_GOSTR3410_PUBLIC_KEY_DERIVE, &minfo);
    if (rc != CKR_OK)
    {
        fprintf(stderr,
                "Mechanism CKM_GOSTR3410_PUBLIC_KEY_DERIVE not supported\n");
        return rc;
    }

    rc = funcs->C_OpenSession(SlotId,
                              CKF_RW_SESSION | CKF_SERIAL_SESSION,
                              NULL_PTR, NULL_PTR, &hSession);
    if (rc != CKR_OK)
    {
        fprintf(stderr,
                "ERROR call to C_OpenSession failed, rc = 0x%lx\n", rc);
        goto out;
    }

    rc = funcs->C_Login(hSession, CKU_USER, user_pin, (CK_ULONG)strlen(user_pin));
    if (rc != CKR_OK) {
        fprintf(stderr, "ERROR call to C_Login failed, rc = 0x%lx\n", rc);
        goto out;
    }
 
    rc = test_gost28147_pkcs8_key_wrap(hSession);

    if (rc != CKR_OK)
    {
        fprintf(stderr,
                "CKM_GOST28147_PKCS8_KEY_WRAP and CKM_GOSTR3410_PUBLIC_KEY_DERIVE "
                "test failed, rc = 0x%lx\n",
                rc);
    }
    else
    {
        printf(
            "CKM_GOST28147_PKCS8_KEY_WRAP and CKM_GOSTR3410_PUBLIC_KEY_DERIVE "
            "test SUCCESS\n");
    }

 out:
    funcs->C_CloseSession(hSession);
    return rc;
}

CK_RV test_gost28147_pkcs8_key_wrap(CK_SESSION_HANDLE sess)
{
    CK_RV                        rc = CKR_OK;
    char                         str[4096];
    CK_BYTE                      *value;
    CK_ULONG                     len;
    CK_OBJECT_HANDLE             pub_key        = CK_INVALID_HANDLE;
    CK_OBJECT_HANDLE             priv_key       = CK_INVALID_HANDLE;
    CK_OBJECT_HANDLE             unw_priv_key   = CK_INVALID_HANDLE;
    CK_OBJECT_HANDLE             der_pub_key    = CK_INVALID_HANDLE;
//    CK_OBJECT_HANDLE             cipher_key     = CK_INVALID_HANDLE;
    CK_MECHANISM                 mechanism_desc =
    { CKM_GOST28147_PKCS8_KEY_WRAP, NULL, 0 };
    CK_MECHANISM_PTR             mechanism          = &mechanism_desc;
    CK_MECHANISM                 mechanism_der_desc =
    { CKM_GOSTR3410_PUBLIC_KEY_DERIVE, NULL, 0 };
    CK_MECHANISM_PTR             mechanism_der          = &mechanism_der_desc;
    CK_MECHANISM                 mechanism_gen_256_desc =
    { CKM_GOSTR3410_KEY_PAIR_GEN, NULL, 0 };
    CK_MECHANISM_PTR             mechanism_gen_256      = &mechanism_gen_256_desc;
    CK_MECHANISM                 mechanism_gen_512_desc =
    { CKM_GOSTR3410_512_KEY_PAIR_GEN, NULL, 0 };
    CK_MECHANISM_PTR             mechanism_gen_512 = &mechanism_gen_512_desc;

    static CK_BBOOL              ltrue        = CK_TRUE;
    static CK_BBOOL              lfalse       = CK_FALSE;
    static const CK_OBJECT_CLASS oclass_pub   = CKO_PUBLIC_KEY;
    static const CK_OBJECT_CLASS oclass_priv  = CKO_PRIVATE_KEY;
    static CK_KEY_TYPE           key_type_256 = CKK_GOSTR3410;
    static CK_KEY_TYPE           key_type_512 = CKK_GOSTR3410_512;
    // PAR 256 A OID
    static CK_BYTE               gostR3410_256_params_A[] = {
        0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01
    };
    // PAR 512 A OID
    static CK_BYTE                      gostR3410_512_params_A[] = {
        0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x2, 0x01, 0x02, 0x01
    };
    // PAR HASH 1 OID
    static CK_BYTE               gostR3411_94_params[] = {
        0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01
    };
    // PAR 3411-2012-256 OID
    static CK_BYTE                      gostR3411_2012_256_params[] = {
        0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x02
    };
    // PAR 3411-2012-512 OID
    static CK_BYTE                      gostR3411_2012_512_params[] = {
        0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x03
    };
    // PAR CIPHER A OID
    static CK_BYTE               gost28147params_A[] = {
        0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01
    };
/*
   typedef struct CK_GOST28147_PKCS8_KEY_WRAP_PARAMS {
    CK_CHAR_PTR      pPassword;
    CK_ULONG         ulPasswordLen;
        CK_BYTE_PTR      pHashParOID;
        CK_ULONG         ulHashParOIDLen;
        CK_BYTE_PTR      pSalt;
        CK_ULONG         ulSaltLen;
    CK_ULONG         ulIterCount;
        CK_BYTE_PTR      pCipherParOID;
        CK_ULONG         ulCipherParOIDLen;
        CK_BYTE_PTR      pIV;
        CK_ULONG         ulIVLen;
   } CK_GOST28147_PKCS8_KEY_WRAP_PARAMS;
 */
    CK_GOST28147_PKCS8_KEY_WRAP_PARAMS params;

    static CK_BYTE                     salt[] = {
        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x26
    };
    static CK_BYTE                     salt32[] = {
        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x26,
        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0xab,
        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0xab,
        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0xab,
    };
    static CK_ULONG                    iter     = 2048;
    static CK_ULONG                    iter2000 = 2000;
    static CK_BYTE                     iv[]     = {
        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0xab
    };
    // Use UTF-8 password
    static CK_UTF8CHAR_PTR             password                = (CK_UTF8CHAR_PTR)"4444";
//    static CK_ULONG                    password_len            = 4;
    CK_ATTRIBUTE                       pub_2001_256_template[] = {
        { CKA_GOSTR3410PARAMS,
          gostR3410_256_params_A, sizeof(gostR3410_256_params_A) },
        { CKA_GOSTR3411PARAMS,
          gostR3411_94_params, sizeof(gostR3411_94_params) },
		{ CKA_TOKEN, &ltrue, sizeof(ltrue) }, 
    };
    CK_ATTRIBUTE                       pub_2012_256_template[] = {
        { CKA_GOSTR3410PARAMS,
          gostR3410_256_params_A, sizeof(gostR3410_256_params_A) },
        { CKA_GOSTR3411PARAMS,
          gostR3411_2012_256_params, sizeof(gostR3411_2012_256_params) },
		{ CKA_TOKEN, &ltrue, sizeof(ltrue) }, 
    };
    CK_ATTRIBUTE                       pub_2012_512_template[] = {
        { CKA_GOSTR3410PARAMS,
          gostR3410_512_params_A, sizeof(gostR3410_512_params_A) },
        { CKA_GOSTR3411PARAMS,
          gostR3411_2012_512_params, sizeof(gostR3411_2012_512_params) },
		{ CKA_TOKEN, &ltrue, sizeof(ltrue) }, 
    };
    // Template for token private key generation.
    CK_ATTRIBUTE                       priv_template[] = {
        { CKA_EXTRACTABLE, &ltrue, sizeof(ltrue) },
        { CKA_SENSITIVE,   &ltrue, sizeof(ltrue) },
		{ CKA_TOKEN, &ltrue, sizeof(ltrue) }, 
		{ CKA_PRIVATE, &ltrue, sizeof(ltrue) }, 
    };
    // Additional attributes for token unwrapped private key generation.
    CK_ATTRIBUTE                       unw_256_template[] = {
        { CKA_CLASS,    (CK_VOID_PTR) &oclass_priv, sizeof(oclass_priv)  },
        { CKA_KEY_TYPE, &key_type_256,              sizeof(key_type_256) },
        { CKA_EXTRACTABLE, &ltrue, sizeof(ltrue) },
        { CKA_SENSITIVE,   &lfalse, sizeof(ltrue) },
		{ CKA_TOKEN, &ltrue, sizeof(ltrue) }, 
		{ CKA_PRIVATE, &ltrue, sizeof(ltrue) }, 
    };
    CK_ATTRIBUTE                       unw_512_template[] = {
        { CKA_CLASS,    (CK_VOID_PTR) &oclass_priv, sizeof(oclass_priv)  },
        { CKA_KEY_TYPE, &key_type_512,              sizeof(key_type_512) },
        { CKA_EXTRACTABLE, &ltrue, sizeof(ltrue) },
        { CKA_SENSITIVE,   &ltrue, sizeof(ltrue) },
		{ CKA_TOKEN, &ltrue, sizeof(ltrue) }, 
		{ CKA_PRIVATE, &ltrue, sizeof(ltrue) }, 
    };
	CK_BYTE pub_key_value[128];
	CK_BYTE der_pub_key_value[128];
	CK_ULONG pub_key_len = 128;
	CK_ATTRIBUTE cka_value_template[] = {
		{ CKA_VALUE, NULL, 0 },
	};
	// Поскольку параметры ключевой сохраняются в объекте закрытого ключа
	// при его генерации, то при получении открытого ключа по закрытому
	// их лучше вообще не задавать, чтобы не нарваться на конфликт атрибутов.
	// Задавать следует другие атрибуты, например CKA_TOKEN, CKA_LABEL и т.д.,
	// только если они необходимы для дальнейшей работы с объектом открытого ключа.
/*
    CK_ATTRIBUTE                       pub_2001_256_der_template[] = {
        { CKA_CLASS,           (CK_VOID_PTR) &oclass_pub, sizeof(oclass_pub)   },
        { CKA_KEY_TYPE,        &key_type_256,             sizeof(key_type_256) },
        { CKA_GOSTR3410PARAMS,
          gostR3410_256_params_A, sizeof(gostR3410_256_params_A) },
        { CKA_GOSTR3411PARAMS,
          gostR3411_94_params, sizeof(gostR3411_94_params) },
    };
    CK_ATTRIBUTE                       pub_2012_256_der_template[] = {
        { CKA_CLASS,           (CK_VOID_PTR) &oclass_pub, sizeof(oclass_pub)   },
        { CKA_KEY_TYPE,        &key_type_256,             sizeof(key_type_256) },
        { CKA_GOSTR3410PARAMS,
          gostR3410_256_params_A, sizeof(gostR3410_256_params_A) },
        { CKA_GOSTR3411PARAMS,
          gostR3411_2012_256_params, sizeof(gostR3411_2012_256_params) },
    };
    CK_ATTRIBUTE                       pub_2012_512_der_template[] = {
        { CKA_CLASS,           (CK_VOID_PTR) &oclass_pub, sizeof(oclass_pub)   },
        { CKA_KEY_TYPE,        &key_type_512,             sizeof(key_type_512) },
        { CKA_GOSTR3410PARAMS,
          gostR3410_512_params_A, sizeof(gostR3410_512_params_A) },
        { CKA_GOSTR3411PARAMS,
          gostR3411_2012_512_params, sizeof(gostR3411_2012_512_params) },
    };
*/

    // Тест распаковки PKCS#8 от Криптокома
    printf("Unpacking external PKCS#8 256 bit...\n");
    {
        CK_BYTE     wrapped_256[] = {
            0x30, 0x81, 0xA7, 0x30, 0x59, 0x06, 0x09, 0x2A,
            0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0D,
            0x30, 0x4C, 0x30, 0x29, 0x06, 0x09, 0x2A, 0x86,
            0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C, 0x30,
            0x1C, 0x04, 0x08, 0x4D, 0x43, 0xAD, 0x1D, 0x35,
            0x8F, 0x95, 0xCC, 0x02, 0x02, 0x08, 0x00, 0x30,
            0x0C, 0x06, 0x08, 0x2A, 0x85, 0x03, 0x07, 0x01,
            0x01, 0x04, 0x02, 0x05, 0x00, 0x30, 0x1F, 0x06,
            0x06, 0x2A, 0x85, 0x03, 0x02, 0x02, 0x15, 0x30,
            0x15, 0x04, 0x08, 0x4B, 0x7D, 0x83, 0x08, 0xD5,
            0x5A, 0x60, 0x5E, 0x06, 0x09, 0x2A, 0x85, 0x03,
            0x07, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x4A,
            0x1E, 0xA2, 0x47, 0x3F, 0x3C, 0x31, 0x60, 0xFB,
            0xDB, 0xBA, 0x6E, 0xDC, 0x4A, 0xC6, 0x17, 0xD2,
            0x06, 0xC7, 0xDD, 0xE3, 0xF0, 0xD0, 0x37, 0xAA,
            0x98, 0x2E, 0xC9, 0x35, 0x14, 0xDD, 0x77, 0x5A,
            0xE8, 0x2D, 0x24, 0x2E, 0xDF, 0xCF, 0xBD, 0xB3,
            0xFB, 0x03, 0xD7, 0x68, 0xF5, 0x4B, 0x66, 0x7A,
            0x94, 0xDB, 0x9A, 0xEE, 0x55, 0x86, 0x29, 0x0C,
            0xDC, 0x3E, 0x63, 0x2B, 0xFD, 0xA7, 0x15, 0xE6,
            0x63, 0x10, 0x3E, 0xD3, 0x2D, 0x8C, 0xDB, 0xF4,
            0xF0, 0xA1
        };
        CK_UTF8CHAR *password_01234567 = (CK_UTF8CHAR *)"01234567";

        len = sizeof(wrapped_256);
        mechanism->pParameter     = password_01234567;
        mechanism->ulParameterLen = (CK_ULONG)strlen((char *)password_01234567);
        rc                        = funcs->C_UnwrapKey(sess, mechanism, CK_INVALID_HANDLE,
                                                       wrapped_256, len,
                                                       unw_256_template, sizeof(unw_256_template) / sizeof(CK_ATTRIBUTE),
                                                       &unw_priv_key);

        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_UnwrapKey failed, rc = 0x%lx\n", rc);
            goto end;
        }
        funcs->C_DestroyObject(sess, unw_priv_key);
        printf("OK\n");
    }

    printf("Unpacking external PKCS#8 512 bit...\n");
    {
		// LCSSL encrypted PKCS#8 private key DER data:
		CK_BYTE wrapped_512[] = {
			0x30, 0x81, 0xC9, 0x30, 0x59, 0x06, 0x09, 0x2A, 
			0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0D,
			0x30, 0x4C, 0x30, 0x29, 0x06, 0x09, 0x2A, 0x86, 
			0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C, 0x30,
			0x1C, 0x04, 0x08, 0xF4, 0xEC, 0x5C, 0x0E, 0x7D, 
			0xE6, 0xF1, 0x40, 0x02, 0x02, 0x08, 0x00, 0x30,
			0x0C, 0x06, 0x08, 0x2A, 0x85, 0x03, 0x07, 0x01, 
			0x01, 0x04, 0x02, 0x05, 0x00, 0x30, 0x1F, 0x06,
			0x06, 0x2A, 0x85, 0x03, 0x02, 0x02, 0x15, 0x30, 
			0x15, 0x04, 0x08, 0x72, 0x4E, 0xD1, 0xDA, 0xAE,
			0x9F, 0xAA, 0x01, 0x06, 0x09, 0x2A, 0x85, 0x03, 
			0x07, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x6C,
			0xC2, 0x34, 0xDB, 0x46, 0x04, 0x2B, 0xF1, 0xEF, 
			0x12, 0xCB, 0x10, 0xAA, 0x1E, 0x2B, 0xEA, 0x1A,
			0xC4, 0xBE, 0xCD, 0x7C, 0x08, 0xCB, 0xA1, 0x6B, 
			0xB3, 0x43, 0x4E, 0xB4, 0x9B, 0x99, 0xB1, 0x05,
			0xB6, 0xF7, 0x2B, 0xBB, 0xE3, 0xD1, 0x39, 0x2B, 
			0x1C, 0x8D, 0xB3, 0xD7, 0xF0, 0x62, 0x58, 0x0A,
			0x14, 0x5B, 0x9E, 0x57, 0xBF, 0xBA, 0x5B, 0x18, 
			0x35, 0xBE, 0xBB, 0x84, 0x13, 0x38, 0xE3, 0x6A,
			0xA0, 0xC4, 0x53, 0x11, 0xD1, 0x52, 0x1B, 0xD9, 
			0xB0, 0x0B, 0xC4, 0x2D, 0x06, 0x6B, 0xC9, 0x47,
			0xDC, 0x6B, 0x94, 0x68, 0xDE, 0x0E, 0x0F, 0xB6, 
			0xE2, 0xB0, 0x34, 0xD4, 0xFC, 0x45, 0xBA, 0xE7,
			0x3E, 0x56, 0x22, 0x60, 0xBA, 0xD7, 0x9B, 0x6F, 
			0xD8, 0xC3, 0x49, 0x48,		
		};
        CK_UTF8CHAR *password_1111 = (CK_UTF8CHAR *)"1111";

        len = sizeof(wrapped_512);
        mechanism->pParameter     = password_1111;
        mechanism->ulParameterLen = (CK_ULONG)strlen((char *)password_1111);
        rc                        = funcs->C_UnwrapKey(sess, mechanism, CK_INVALID_HANDLE,
                                                       wrapped_512, len,
                                                       unw_512_template, sizeof(unw_512_template) / sizeof(CK_ATTRIBUTE),
                                                       &unw_priv_key);

        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_UnwrapKey failed, rc = 0x%lx\n", rc);
            goto end;
        }
        funcs->C_DestroyObject(sess, unw_priv_key);
        printf("OK\n");
    }

    // При упаковке на выходе должна получиться структура такого вида:
/*
    static CK_BYTE                     pr_key_bag[] = {
// 0
        0x30, 0x81, 0xa7,
// 3
        0x30, 0x5c,
// 5
        0x06, 0x09,
        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0d,
// 16
        0x30, 0x4f,
// 18
        0x30, 0x2e,
// 20
        0x06, 0x09,
        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c,
// 31
        0x30, 0x21,
// 33
        0x04, 0x08,
// 35 - salt
        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x26,
// 43
        0x02, 0x02,
// 45 - iter (2048)
        0x08, 0x00,
// 47
        0x30, 0x11,
// 49 - oid_hmac_3411_94
        0x06, 0x06,
        0x2a, 0x85, 0x03, 0x02, 0x02, 0x0a,
// 57 - oid_3411_par (may be 0x05, 0x00)
        0x06, 0x07,
        0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01,
// 66
        0x30, 0x1d,
// 68
        0x06, 0x06,
        0x2a, 0x85, 0x03, 0x02, 0x02, 0x15,
// 76
        0x30, 0x13,
// 78
        0x04, 0x08,
// 80 - iv
        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0xab,
// 88 - oid_28147_par
        0x06, 0x07,
        0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01,
// 97
        0x04, 0x47,
// 99 - encr_pr_key
        0x46, 0x5c, 0xc8, 0x21, 0xcd, 0xcc, 0xb8, 0x99,
        0x53, 0xa7, 0x72, 0xda, 0x20, 0x0f, 0x3d, 0xd5,
        0xab, 0x59, 0x11, 0x6f, 0x4f, 0x8a, 0x75, 0x9b,
        0xf4, 0xd1, 0x91, 0x7e, 0x9d, 0x2f, 0x79, 0xab,
        0x95, 0xb8, 0x54, 0xe2, 0x5b, 0x21, 0x61, 0xa8,
        0xe7, 0x2b, 0x58, 0x5b, 0xe2, 0x10, 0xd0, 0xd8,
        0xbb, 0xd4, 0x04, 0xdc, 0x06, 0x4c, 0x60, 0x14,
        0x60, 0x12, 0xd1, 0xf1, 0xb2, 0xbf, 0x39, 0xf7,
        0xc8, 0x35, 0x16, 0xc4, 0xea, 0xe9, 0xb6
// 170
    };
*/
    // Заметим, что при распаковке во входной структуре допускается
    // использование 0x05, 0x00 вместо oid_3411_par. Соответственно,
    // длина такой укороченной структуры будет меньше на 7 байтов.

    // GOSTR3410-2001
	printf("GOSTR3410-2001\n");
    rc = funcs->C_GenerateKeyPair(sess, mechanism_gen_256,
                                  pub_2001_256_template,
                                  sizeof(pub_2001_256_template) / sizeof(CK_ATTRIBUTE),
                                  priv_template, sizeof(priv_template) / sizeof(CK_ATTRIBUTE),
                                  &pub_key, &priv_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GenerateKeyPair failed, rc = 0x%lx\n", rc);
        goto end;
    }

	cka_value_template[0].pValue = pub_key_value;
	cka_value_template[0].ulValueLen = 64;
	rc = funcs->C_GetAttributeValue(sess, pub_key, cka_value_template, sizeof(cka_value_template) / sizeof(CK_ATTRIBUTE));
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GetAttributeValue failed, rc = 0x%lx\n", rc);
        goto end;
    }

    params.pPassword         = password;
    params.ulPasswordLen     = (CK_ULONG)strlen((char *)password);
    params.pHashParOID       = gostR3411_94_params;
    params.ulHashParOIDLen   = sizeof(gostR3411_94_params);
    params.pSalt             = salt;
    params.ulSaltLen         = sizeof(salt);
    params.ulIterCount       = iter;
    params.pCipherParOID     = gost28147params_A;
    params.ulCipherParOIDLen = sizeof(gost28147params_A);
    params.pIV               = iv;
    params.ulIVLen           = sizeof(iv);

    mechanism->pParameter     = &params;
    mechanism->ulParameterLen = sizeof(params);

    rc                        = funcs->C_WrapKey(sess, mechanism,
                                                 CK_INVALID_HANDLE, priv_key, NULL, &len);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_WrapKey failed, rc = 0x%lx\n", rc);
        goto end;
    }

	value = malloc(len);
    rc                        = funcs->C_WrapKey(sess, mechanism,
                                                 CK_INVALID_HANDLE, priv_key, value, &len);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_WrapKey failed, rc = 0x%lx\n", rc);
        goto end;
    }

    print_bytes_str(value, len, str);
    printf("PKCS#8:\n%s\n", str);

/*
        0x30, 0x81, 0xa7,
                0x30, 0x5c,
                        0x06, 0x09,
                                0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0d,
                        0x30, 0x4f,
                                0x30, 0x2e,
                                        0x06, 0x09,
                                                0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c,
                                        0x30, 0x21,
                                                0x04, 0x08,
                                                        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x26,
                                                0x02, 0x02,
                                                        0x08, 0x00,
                                                0x30, 0x11,
                                                        0x06, 0x06,
                                                                0x2a, 0x85, 0x03, 0x02, 0x02, 0x0a,
                                                        0x06, 0x07,
                                                                0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01,
                                0x30, 0x1d,
                                        0x06, 0x06,
                                                0x2a, 0x85, 0x03, 0x02, 0x02, 0x15,
                                        0x30, 0x13,
                                                0x04, 0x08,
                                                        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0xab,
                                                0x06, 0x07,
                                                        0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01,
                0x04, 0x47,
                        0x95, 0x44, 0x39, 0xe9, 0xce, 0xb5, 0x56, 0x29,
                        0xfa, 0x08, 0xf2, 0xab, 0x09, 0x81, 0x44, 0xca,
                        0xe0, 0x56, 0xc7, 0x60, 0xe2, 0x5c, 0xbd, 0x3c,
                        0xdd, 0x1c, 0x13, 0xf8, 0xf1, 0xe8, 0xd3, 0xf4,
                        0x98, 0xf0, 0x2e, 0x3c, 0xa0, 0x7d, 0xfe, 0x35,
                        0xee, 0xcf, 0xc4, 0xaf, 0xad, 0x93, 0x89, 0x48,
                        0xe5, 0xf2, 0x25, 0xbf, 0xe7, 0x61, 0x01, 0x8f,
                        0x50, 0x62, 0x08, 0x9b, 0xad, 0x9e, 0xcb, 0x42,
                        0xce, 0x17, 0x81, 0xc4, 0xea, 0xe9, 0xb6,
 */

    mechanism->pParameter     = password;
    mechanism->ulParameterLen = (CK_ULONG)strlen((char *)password);
    rc                        = funcs->C_UnwrapKey(sess, mechanism, CK_INVALID_HANDLE,
                                                   value, len,
                                                   unw_256_template, sizeof(unw_256_template) / sizeof(CK_ATTRIBUTE),
                                                   &unw_priv_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_UnwrapKey failed, rc = 0x%lx\n", rc);
        goto end;
    }

    // Получаем открытый ключ по закрытому
    rc = funcs->C_DeriveKey(sess, mechanism_der, unw_priv_key,
		// Шаблон открытого ключа задавать не обязательно,
		// если генерируется сессионный ключ.
/*
        pub_2001_256_der_template,
        sizeof(pub_2001_256_der_template) / sizeof(CK_ATTRIBUTE),
*/
		NULL, 0,
        &der_pub_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_DeriveKey failed, rc = 0x%lx\n", rc);
        goto end;
    }

	cka_value_template[0].pValue = der_pub_key_value;
	cka_value_template[0].ulValueLen = 64;
	rc = funcs->C_GetAttributeValue(sess, der_pub_key, cka_value_template, sizeof(cka_value_template) / sizeof(CK_ATTRIBUTE));
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GetAttributeValue failed, rc = 0x%lx\n", rc);
        goto end;
    }
    print_bytes_str(der_pub_key_value, cka_value_template[0].ulValueLen, str);
    printf("Public key value:\n%s\n", str);
	if (memcmp(pub_key_value, der_pub_key_value, 64) != 0){
        fprintf(stderr, "Invalid derived public key\n");
		rc = CKR_FUNCTION_FAILED;
        goto end;
	}
	printf("GOST R 3410-2001: CKM_GOSTR3410_PUBLIC_KEY_DERIVE OK\n");
    // Для проверки распакованного ключа нужно что-нибудь им подписать
    // и проверить подпись открытым ключом.
    {
        CK_MECHANISM mechanism_sign = { CKM_GOSTR3410, NULL, 0 };
        // Подписываемый дайджест (32 байта)
        CK_BYTE      pData[32] = {
            0x4D, 0x89, 0x9E, 0x48, 0xC5, 0x39, 0x64, 0xD1,
            0x78, 0xB4, 0x6D, 0x58, 0x40, 0x5F, 0x62, 0x8F,
            0xA4, 0x46, 0x4C, 0xDC, 0x73, 0x75, 0xB0, 0xE5,
            0x2E, 0x91, 0xFB, 0x64, 0x9C, 0x06, 0xAB, 0x75
        };
        CK_ULONG     ulDataLen = 32;
        CK_BYTE      pSignatureData[64];
        CK_ULONG     signatureDataLen = 64;

        rc = funcs->C_SignInit(sess, &mechanism_sign, unw_priv_key);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_SignInit failed, rc = 0x%lx\n", rc);
            goto end;
        }
        rc = funcs->C_Sign(sess,
                           pData, ulDataLen, pSignatureData, &signatureDataLen);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_Sign failed, rc = 0x%lx\n", rc);
            goto end;
        }

        rc = funcs->C_VerifyInit(sess, &mechanism_sign, pub_key);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_VerifyInit failed, rc = 0x%lx\n", rc);
            goto end;
        }
        rc = funcs->C_Verify(sess,
                             pData, ulDataLen, pSignatureData, signatureDataLen);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_Verify failed, rc = 0x%lx\n", rc);
            goto end;
        }

        rc = funcs->C_VerifyInit(sess, &mechanism_sign, der_pub_key);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_VerifyInit failed, rc = 0x%lx\n", rc);
            goto end;
        }
        rc = funcs->C_Verify(sess,
                             pData, ulDataLen, pSignatureData, signatureDataLen);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_Verify failed, rc = 0x%lx\n", rc);
            goto end;
        }
    }
    funcs->C_DestroyObject(sess, der_pub_key);
    funcs->C_DestroyObject(sess, unw_priv_key);
    funcs->C_DestroyObject(sess, pub_key);
    funcs->C_DestroyObject(sess, priv_key);
	if (value) {
		free(value);
		value = NULL;
	}

    // GOSTR3410-2012-256
	printf("GOSTR3410-2012-256\n");
    rc = funcs->C_GenerateKeyPair(sess, mechanism_gen_256,
                                  pub_2012_256_template,
                                  sizeof(pub_2012_256_template) / sizeof(CK_ATTRIBUTE),
                                  priv_template, sizeof(priv_template) / sizeof(CK_ATTRIBUTE),
                                  &pub_key, &priv_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GenerateKeyPair failed, rc = 0x%lx\n", rc);
        goto end;
    }
	cka_value_template[0].pValue = pub_key_value;
	cka_value_template[0].ulValueLen = 64;
	rc = funcs->C_GetAttributeValue(sess, pub_key, cka_value_template, sizeof(cka_value_template) / sizeof(CK_ATTRIBUTE));
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GetAttributeValue failed, rc = 0x%lx\n", rc);
        goto end;
    }
    // Упаковка ключей 2012-256 должна производиться на gostR3411_2012_512_params!
    params.pPassword         = password;
    params.ulPasswordLen     = (CK_ULONG)strlen((char *)password);
    params.pHashParOID       = gostR3411_2012_512_params;
    params.ulHashParOIDLen   = sizeof(gostR3411_2012_512_params);
    params.pSalt             = salt32;
    params.ulSaltLen         = sizeof(salt32);
    params.ulIterCount       = iter2000;
    params.pCipherParOID     = gost28147params_A;
    params.ulCipherParOIDLen = sizeof(gost28147params_A);
    params.pIV               = iv;
    params.ulIVLen           = sizeof(iv);

    mechanism->pParameter     = &params;
    mechanism->ulParameterLen = sizeof(params);
    rc                        = funcs->C_WrapKey(sess, mechanism,
                                                 CK_INVALID_HANDLE, priv_key, NULL, &len);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_WrapKey failed, rc = 0x%lx\n", rc);
        goto end;
    }
	value = malloc(len);
    rc                        = funcs->C_WrapKey(sess, mechanism,
                                                 CK_INVALID_HANDLE, priv_key, value, &len);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_WrapKey failed, rc = 0x%lx\n", rc);
        goto end;
    }

    print_bytes_str(value, len, str);
    printf("PKCS#8:\n%s\n", str);

/*
        0x30, 0x81, 0xab,
                0x30, 0x5d,
                        0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0d,
                        0x30, 0x50,
                                0x30, 0x2f,
                                        0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c,
                                        0x30, 0x22,
                                                0x04, 0x08,
                                                        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x26,
                                                0x02, 0x02,
                                                        0x08, 0x00,
                                                0x30, 0x12,
                                                        0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x0a,
                                                        0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x02,
                                0x30, 0x1d,
                                        0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x15,
                                        0x30, 0x13,
                                                0x04, 0x08,
                                                        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0xab,
                                                0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01,
                0x04, 0x4a,
                        0x68, 0x7f, 0x0d, 0x40, 0xbc, 0x97, 0xe6, 0x83,
                        0x83, 0xdf, 0x4b, 0x9e, 0xff, 0x60, 0x64, 0xbd,
                        0xb3, 0xea, 0xfe, 0x6b, 0xb2, 0x00, 0xc7, 0x78,
                        0x80, 0x13, 0xc7, 0x61, 0x45, 0x76, 0x30, 0x53,
                        0x5d, 0xf1, 0xcf, 0xdc, 0xf3, 0xd9, 0xdd, 0x50,
                        0x7d, 0x7a, 0x2c, 0x87, 0x06, 0x2f, 0x28, 0xdb,
                        0x1e, 0x94, 0xe3, 0xab, 0x9f, 0x0a, 0x75, 0x09,
                        0xd3, 0xf9, 0x2e, 0xbe, 0xc6, 0xb1, 0xf4, 0x9c,
                        0x92, 0xc9, 0xa4, 0x35, 0xd6, 0x6c, 0x25, 0xc7,
                        0xbc, 0xcf,
 */

    mechanism->pParameter     = password;
    mechanism->ulParameterLen = (CK_ULONG)strlen((char *)password);
    rc                        = funcs->C_UnwrapKey(sess, mechanism, CK_INVALID_HANDLE,
                                                   value, len,
                                                   unw_256_template,
                                                   sizeof(unw_256_template) / sizeof(CK_ATTRIBUTE),
                                                   &unw_priv_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_UnwrapKey failed, rc = 0x%lx\n", rc);
        goto end;
    }
    // Получаем открытый ключ по закрытому
    rc = funcs->C_DeriveKey(sess, mechanism_der, unw_priv_key,
		// Шаблон открытого ключа задавать не обязательно,
		// если генерируется сессионный ключ.
/*
        pub_2012_256_der_template,
        sizeof(pub_2012_256_der_template) / sizeof(CK_ATTRIBUTE),
*/
		NULL, 0,
        &der_pub_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_DeriveKey failed, rc = 0x%lx\n", rc);
        goto end;
    }
	cka_value_template[0].pValue = der_pub_key_value;
	cka_value_template[0].ulValueLen = 64;
	rc = funcs->C_GetAttributeValue(sess, der_pub_key, cka_value_template, sizeof(cka_value_template) / sizeof(CK_ATTRIBUTE));
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GetAttributeValue failed, rc = 0x%lx\n", rc);
        goto end;
    }
    print_bytes_str(der_pub_key_value, cka_value_template[0].ulValueLen, str);
    printf("Public key value:\n%s\n", str);
	if (memcmp(pub_key_value, der_pub_key_value, 64) != 0){
        fprintf(stderr, "Invalid derived public key\n");
		rc = CKR_FUNCTION_FAILED;
        goto end;
	}
	printf("GOST R 3410-2012-256: CKM_GOSTR3410_PUBLIC_KEY_DERIVE OK\n");
    // Для проверки распакованного ключа нужно что-нибудь им подписать
    // и проверить подпись открытым ключом.
    {
        CK_MECHANISM mechanism_sign = { CKM_GOSTR3410, NULL, 0 };
        // Подписываемый дайджест (32 байта)
        CK_BYTE      pData[32] = {
            0x4D, 0x89, 0x9E, 0x48, 0xC5, 0x39, 0x64, 0xD1,
            0x78, 0xB4, 0x6D, 0x58, 0x40, 0x5F, 0x62, 0x8F,
            0xA4, 0x46, 0x4C, 0xDC, 0x73, 0x75, 0xB0, 0xE5,
            0x2E, 0x91, 0xFB, 0x64, 0x9C, 0x06, 0xAB, 0x75
        };
        CK_ULONG     ulDataLen = 32;
        CK_BYTE      pSignatureData[64];
        CK_ULONG     signatureDataLen = 64;

        rc = funcs->C_SignInit(sess, &mechanism_sign, unw_priv_key);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_SignInit failed, rc = 0x%lx\n", rc);
            goto end;
        }
        rc = funcs->C_Sign(sess,
                           pData, ulDataLen, pSignatureData, &signatureDataLen);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_Sign failed, rc = 0x%lx\n", rc);
            goto end;
        }

        rc = funcs->C_VerifyInit(sess, &mechanism_sign, pub_key);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_VerifyInit failed, rc = 0x%lx\n", rc);
            goto end;
        }
        rc = funcs->C_Verify(sess,
                             pData, ulDataLen, pSignatureData, signatureDataLen);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_Verify failed, rc = 0x%lx\n", rc);
            goto end;
        }

        rc = funcs->C_VerifyInit(sess, &mechanism_sign, der_pub_key);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_VerifyInit failed, rc = 0x%lx\n", rc);
            goto end;
        }
        rc = funcs->C_Verify(sess,
                             pData, ulDataLen, pSignatureData, signatureDataLen);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_Verify failed, rc = 0x%lx\n", rc);
            goto end;
        }
    }
    funcs->C_DestroyObject(sess, der_pub_key);
    funcs->C_DestroyObject(sess, unw_priv_key);
    funcs->C_DestroyObject(sess, pub_key);
    funcs->C_DestroyObject(sess, priv_key);
	if (value){
		free(value);
		value = NULL;
	}


    // GOSTR3410-2012-512
	printf("GOSTR3410-2012-512\n");
    rc = funcs->C_GenerateKeyPair(sess, mechanism_gen_512,
                                  pub_2012_512_template,
                                  sizeof(pub_2012_512_template) / sizeof(CK_ATTRIBUTE),
                                  priv_template, sizeof(priv_template) / sizeof(CK_ATTRIBUTE),
                                  &pub_key, &priv_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GenerateKeyPair failed, rc = 0x%lx\n", rc);
        goto end;
    }
	cka_value_template[0].pValue = pub_key_value;
	cka_value_template[0].ulValueLen = 128;
	rc = funcs->C_GetAttributeValue(sess, pub_key, cka_value_template, sizeof(cka_value_template) / sizeof(CK_ATTRIBUTE));
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GetAttributeValue failed, rc = 0x%lx\n", rc);
        goto end;
    }

    params.pPassword         = password;
    params.ulPasswordLen     = (CK_ULONG)strlen((char *)password);
    params.pHashParOID       = gostR3411_2012_512_params;
    params.ulHashParOIDLen   = sizeof(gostR3411_2012_512_params);
    params.pSalt             = salt32;
    params.ulSaltLen         = sizeof(salt32);
    params.ulIterCount       = iter2000;
    params.pCipherParOID     = gost28147params_A;
    params.ulCipherParOIDLen = sizeof(gost28147params_A);
    params.pIV               = iv;
    params.ulIVLen           = sizeof(iv);

    mechanism->pParameter     = &params;
    mechanism->ulParameterLen = sizeof(params);
    rc                        = funcs->C_WrapKey(sess, mechanism,
                                                 CK_INVALID_HANDLE, priv_key, NULL, &len);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_WrapKey failed, rc = 0x%lx\n", rc);
        goto end;
    }
	value = malloc(len);
    rc                        = funcs->C_WrapKey(sess, mechanism,
                                                 CK_INVALID_HANDLE, priv_key, value, &len);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_WrapKey failed, rc = 0x%lx\n", rc);
        goto end;
    }

    print_bytes_str(value, len, str);
    printf("PKCS#8:\n%s\n", str);

/*
        0x30, 0x81, 0xcd,
                0x30, 0x5d,
                        0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0d,
                        0x30, 0x50,
                                0x30, 0x2f,
                                        0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c,
                                        0x30, 0x22,
                                                0x04, 0x08,
                                                        0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x26,
                                                0x02, 0x02,
                                                        0x08, 0x00,
                                0x30, 0x12,
                                        0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x0a,
                                        0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x03,
                        0x30, 0x1d,
                                0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x15,
                                0x30, 0x13,
                                        0x04, 0x08,
                                                0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0xab,
                                        0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01,
                0x04, 0x6c,
                        0x68, 0x5d, 0x0d, 0x40, 0xbc, 0x97, 0xd8, 0x83,
                        0x73, 0x78, 0x9a, 0x75, 0x9a, 0xa1, 0x44, 0xf1,
                        0x80, 0x83, 0x05, 0x32, 0x1a, 0x83, 0x36, 0x03,
                        0x9e, 0x76, 0x41, 0xb8, 0x56, 0x10, 0x25, 0x6c,
                        0x65, 0x83, 0xa8, 0x46, 0xd5, 0x1b, 0xb0, 0x04,
                        0x41, 0x5c, 0x13, 0x91, 0x76, 0x1c, 0x85, 0x59,
                        0x6b, 0x1d, 0x8d, 0xc8, 0xde, 0x93, 0x2e, 0x22,
                        0x1c, 0x5c, 0xec, 0xaf, 0x1f, 0xb7, 0x7b, 0x63,
                        0xa5, 0x72, 0x1f, 0x29, 0xd6, 0x07, 0xf6, 0xdf,
                        0x8d, 0x69, 0xe4, 0x49, 0x35, 0xfb, 0x71, 0xda,
                        0xb7, 0x4b, 0x17, 0x8c, 0xae, 0xbd, 0xcf, 0x62,
                        0xd2, 0xe6, 0xdb, 0x4d, 0x7c, 0x47, 0x46, 0x82,
                        0xdb, 0x0c, 0xcd, 0x5b, 0x0a, 0xc0, 0xd8, 0x42,
                        0x58, 0x77, 0xe7, 0x7e,
 */

    mechanism->pParameter     = password;
    mechanism->ulParameterLen = (CK_ULONG)strlen((char *)password);
    rc                        = funcs->C_UnwrapKey(sess, mechanism, CK_INVALID_HANDLE,
                                                   value, len,
                                                   unw_512_template, sizeof(unw_512_template) / sizeof(CK_ATTRIBUTE),
                                                   &unw_priv_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_UnwrapKey failed, rc = 0x%lx\n", rc);
        goto end;
    }
    // Получаем открытый ключ по закрытому
    rc = funcs->C_DeriveKey(sess, mechanism_der, unw_priv_key,
		// Шаблон открытого ключа задавать не обязательно,
		// если генерируется сессионный ключ.
/*
        pub_2012_512_der_template,
        sizeof(pub_2012_512_der_template) / sizeof(CK_ATTRIBUTE),
*/
		NULL, 0,
        &der_pub_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_DeriveKey failed, rc = 0x%lx\n", rc);
        goto end;
    }
	cka_value_template[0].pValue = der_pub_key_value;
	cka_value_template[0].ulValueLen = 128;
	rc = funcs->C_GetAttributeValue(sess, der_pub_key, cka_value_template, sizeof(cka_value_template) / sizeof(CK_ATTRIBUTE));
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GetAttributeValue failed, rc = 0x%lx\n", rc);
        goto end;
    }
    print_bytes_str(der_pub_key_value, cka_value_template[0].ulValueLen, str);
    printf("Public key value:\n%s\n", str);
	if (memcmp(pub_key_value, der_pub_key_value, 128) != 0){
        fprintf(stderr, "Invalid derived public key\n");
		rc = CKR_FUNCTION_FAILED;
        goto end;
	}
	printf("GOST R 3410-2012-512: CKM_GOSTR3410_PUBLIC_KEY_DERIVE OK\n");
    // Для проверки распакованного ключа нужно что-нибудь им подписать
    // и проверить подпись открытым ключом.
    {
        CK_MECHANISM mechanism_sign = { CKM_GOSTR3410_512, NULL, 0 };
        // Подписываемый дайджест (64 байта)
        CK_BYTE      pData[] = {
            0x4D, 0x89, 0x9E, 0x48, 0xC5, 0x39, 0x64, 0xD1,
            0x78, 0xB4, 0x6D, 0x58, 0x40, 0x5F, 0x62, 0x8F,
            0xA4, 0x46, 0x4C, 0xDC, 0x73, 0x75, 0xB0, 0xE5,
            0x2E, 0x91, 0xFB, 0x64, 0x9C, 0x06, 0xAB, 0x75,
            0x4D, 0x89, 0x9E, 0x48, 0xC5, 0x39, 0x64, 0xD1,
            0x78, 0xB4, 0x6D, 0x58, 0x40, 0x5F, 0x62, 0x8F,
            0xA4, 0x46, 0x4C, 0xDC, 0x73, 0x75, 0xB0, 0xE5,
            0x2E, 0x91, 0xFB, 0x64, 0x9C, 0x06, 0xAB, 0x75,
        };
        CK_ULONG     ulDataLen = 64;
        CK_BYTE      pSignatureData[128];
        CK_ULONG     signatureDataLen = 128;

        rc = funcs->C_SignInit(sess, &mechanism_sign, unw_priv_key);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_SignInit failed, rc = 0x%lx\n", rc);
            goto end;
        }
        rc = funcs->C_Sign(sess,
                           pData, ulDataLen, pSignatureData, &signatureDataLen);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_Sign failed, rc = 0x%lx\n", rc);
            goto end;
        }

        rc = funcs->C_VerifyInit(sess, &mechanism_sign, pub_key);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_VerifyInit failed, rc = 0x%lx\n", rc);
            goto end;
        }
        rc = funcs->C_Verify(sess,
                             pData, ulDataLen, pSignatureData, signatureDataLen);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_Verify failed, rc = 0x%lx\n", rc);
            goto end;
        }

        rc = funcs->C_VerifyInit(sess, &mechanism_sign, der_pub_key);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_VerifyInit failed, rc = 0x%lx\n", rc);
            goto end;
        }
        rc = funcs->C_Verify(sess,
                             pData, ulDataLen, pSignatureData, signatureDataLen);
        if (rc != CKR_OK)
        {
            fprintf(stderr, "C_Verify failed, rc = 0x%lx\n", rc);
            goto end;
        }
    }
    funcs->C_DestroyObject(sess, der_pub_key);
    funcs->C_DestroyObject(sess, unw_priv_key);
    funcs->C_DestroyObject(sess, pub_key);
    funcs->C_DestroyObject(sess, priv_key);
	if (value){
		free(value);
		value = NULL;
	}


    printf("SUCCESS\n");
 end:

    return rc;
}
