#include "test_common.h"

CK_RV test_crypto();
CK_RV test_tls_tree_gost3411_2012_256(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;
}

static void Uint64ToUint8BE(unsigned long long input, unsigned char* output)
{
    output[7] = (input & 0xffLL);
    output[6] = ((input >> 8) & 0xffLL);
    output[5] = ((input >> 16) & 0xffLL);
    output[4] = ((input >> 24) & 0xffLL);
    output[3] = ((input >> 32) & 0xffLL);
    output[2] = ((input >> 40) & 0xffLL);
    output[1] = ((input >> 48) & 0xffLL);
    output[0] = ((input >> 56) & 0xffLL);
}

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

    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;
    }
    fprintf(stderr, "C_OpenSession success\n");

    rc = funcs->C_GetMechanismInfo(SlotId,
                                   CKM_TLS_TREE_GOSTR3411_2012_256, &minfo);
    if (rc != CKR_OK)
    {
        fprintf(stderr,
                "\n======== Mechanism CKM_TLS_TREE_GOSTR3411_2012_256 "
                "not supported ===========\n");
    }
    else
    {
        fprintf(stderr,
                "\n==================== CKM_TLS_TREE_GOSTR3411_2012_256 "
                "test ==================\n");
        rc = test_tls_tree_gost3411_2012_256(hSession);
        if (rc != CKR_OK)
        {
            fprintf(stderr,
                    "ERROR CKM_TLS_TREE_GOSTR3411_2012_256 failed, "
                    "rc = 0x%lx\n", rc);
        }
        else
        {
            fprintf(stderr,
                    "CKM_TLS_TREE_GOSTR3411_2012_256 test SUSSESS.\n");
        }
    }

    if ((ret = funcs->C_CloseSession(hSession)) != CKR_OK)
    {
        fprintf(stderr,
                "Error: C_CloseSession failed with 0x%lx\n", ret);
        rc = ret;
    }
    else
    {
        fprintf(stderr, "C_CloseSession success\n");
    }

 out:
    return rc;
}

/*
Из документа ТК 26
TLSTREE(K,i)=Divers1(Divers2(Divers3(K,STR8(i & С1)),STR8(i & С2)),STR8(i & С3)),
где 
число 0 <= i < 2^64,
STR8(k) - массив из 8-ми выгруженных байтов числа k 
в порядке big-endian (старший байт - в начале);
константы C1, C2, C3 определяются конкретным набором шифрования
отдельно для Магмы и для Кузнечика; 
Diversj(K,D), j = 1,2,3 — алгоритм диверсификации ключа D, 
который задается с помощью алгоритма KDF_GOSTR3411_2012_256: 
Divers1(K,D)= KDF256(K,"level1",D); 
Divers2(K,D)= KDF256(K,"level2",D); 
Divers3(K,D)= KDF256(K,"level3",D).

В данной реализации число i задается в параметре механизма в уже выгруженном виде.

*/
/*
A.1 TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC

Значение корневого ключа Kroot: 
*/
unsigned char KrootM[] = {
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};

unsigned long long secnumsM[] = {
  0, 
  4095, 
  4096, 
  33554431, 
  33554432, 
  274877906943, 
  274877906944,
};
/*
Выработка ключа защиты записи с номером 0: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1:
*/
unsigned char K1_M_0[] = {
  0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
  0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
  0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
  0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2: 
*/
unsigned char K2_M_0[] = {
  0xAB, 0x3D, 0xFD, 0x55, 0x68, 0x6D, 0x55, 0x97, 
  0x63, 0x5C, 0xFE, 0x08, 0x6C, 0x12, 0xF0, 0x2D, 
  0x40, 0x72, 0x2B, 0xA4, 0x65, 0x9F, 0x51, 0x77, 
  0x34, 0xF8, 0xC5, 0x84, 0xB8, 0xF9, 0xE9, 0x9B, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3:
*/
unsigned char K3_M_0[] = {
  0x50, 0x76, 0x42, 0xD9, 0x58, 0xC5, 0x20, 0xC6, 
  0xD7, 0xEE, 0xF5, 0xCA, 0x8A, 0x53, 0x16, 0xD4, 
  0xF3, 0x4B, 0x85, 0x5D, 0x2D, 0xD4, 0xBC, 0xBF, 
  0x4E, 0x5B, 0xF0, 0xFF, 0x64, 0x1A, 0x19, 0xFF, 
};
/*
Выработка ключа защиты записи с номером 4095: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1:
*/
unsigned char K1_M_4095[] = {
  0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
  0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
  0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
  0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_M_4095[] = {
  0xAB, 0x3D, 0xFD, 0x55, 0x68, 0x6D, 0x55, 0x97, 
  0x63, 0x5C, 0xFE, 0x08, 0x6C, 0x12, 0xF0, 0x2D, 
  0x40, 0x72, 0x2B, 0xA4, 0x65, 0x9F, 0x51, 0x77, 
  0x34, 0xF8, 0xC5, 0x84, 0xB8, 0xF9, 0xE9, 0x9B, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3: 
*/
unsigned char K3_M_4095[] = {
  0x50, 0x76, 0x42, 0xD9, 0x58, 0xC5, 0x20, 0xC6, 
  0xD7, 0xEE, 0xF5, 0xCA, 0x8A, 0x53, 0x16, 0xD4, 
  0xF3, 0x4B, 0x85, 0x5D, 0x2D, 0xD4, 0xBC, 0xBF, 
  0x4E, 0x5B, 0xF0, 0xFF, 0x64, 0x1A, 0x19, 0xFF,
};
/*
Выработка ключа защиты записи с номером 4096: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1: 
*/
unsigned char K1_M_4096[] = {
  0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
  0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
  0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
  0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_M_4096[] = {
  0xAB, 0x3D, 0xFD, 0x55, 0x68, 0x6D, 0x55, 0x97, 
  0x63, 0x5C, 0xFE, 0x08, 0x6C, 0x12, 0xF0, 0x2D, 
  0x40, 0x72, 0x2B, 0xA4, 0x65, 0x9F, 0x51, 0x77, 
  0x34, 0xF8, 0xC5, 0x84, 0xB8, 0xF9, 0xE9, 0x9B, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3:
*/
unsigned char K3_M_4096[] = {
  0x71, 0x86, 0x93, 0xEC, 0xD3, 0xF1, 0xDC, 0xE2, 
  0x11, 0x93, 0xBD, 0x56, 0x40, 0x6A, 0xA4, 0xE2, 
  0x09, 0x0F, 0xE1, 0xC8, 0x7A, 0x5D, 0x5D, 0x7A, 
  0x8C, 0xE6, 0xE0, 0xD8, 0x28, 0xA4, 0x39, 0x15, 
};
/*
Выработка ключа защиты записи с номером 33554431:
1. Ключ первого уровня, являющийся результатом работы функции Divers1: 
*/
unsigned char K1_M_33554431[] = {
  0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
  0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
  0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
  0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_M_33554431[] = {
  0xAB, 0x3D, 0xFD, 0x55, 0x68, 0x6D, 0x55, 0x97, 
  0x63, 0x5C, 0xFE, 0x08, 0x6C, 0x12, 0xF0, 0x2D, 
  0x40, 0x72, 0x2B, 0xA4, 0x65, 0x9F, 0x51, 0x77, 
  0x34, 0xF8, 0xC5, 0x84, 0xB8, 0xF9, 0xE9, 0x9B, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3:
*/
unsigned char K3_M_33554431[] = {
  0xCD, 0x4E, 0x6F, 0x09, 0x94, 0xC4, 0xCA, 0x17, 
  0xA9, 0xAD, 0xE5, 0x3D, 0x69, 0x20, 0x49, 0x77, 
  0x57, 0x87, 0x3B, 0xC0, 0x8D, 0x4F, 0x98, 0x06, 
  0xE3, 0xC9, 0x99, 0xA7, 0xE4, 0xAE, 0x70, 0xE0, 
};

/*
Выработка ключа защиты записи с номером 33554432: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1:
*/
unsigned char K1_M_33554432[] = {
  0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
  0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
  0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
  0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_M_33554432[] = {
  0xAC, 0x22, 0xFD, 0x64, 0x6B, 0x15, 0x94, 0x8B, 
  0x94, 0x52, 0xEA, 0x19, 0x3F, 0x40, 0x72, 0xC7, 
  0x72, 0xCA, 0x54, 0xDA, 0x8E, 0xA2, 0xF6, 0x96, 
  0x92, 0x98, 0x1F, 0x7C, 0x9E, 0x29, 0xB8, 0xB9, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3: 
*/
unsigned char K3_M_33554432[] = {
  0x4E, 0xAB, 0x0F, 0x8A, 0x28, 0x2D, 0xE5, 0x78, 
  0x85, 0x7B, 0xE0, 0x15, 0xD1, 0x32, 0xCD, 0xFD, 
  0x88, 0xF0, 0xEB, 0xD9, 0x9D, 0x10, 0xCC, 0xA3, 
  0xB6, 0xD9, 0x11, 0x4E, 0x37, 0x56, 0x5D, 0xE7, 
};

/*
Выработка ключа защиты записи с номером 274877906943: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1:
*/
unsigned char K1_M_274877906943[] = {
  0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
  0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
  0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
  0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_M_274877906943[] = {
  0x80, 0xA8, 0x35, 0xD6, 0xA3, 0x8A, 0xCB, 0x77, 
  0xCB, 0xAC, 0xDF, 0xC8, 0xE8, 0xE1, 0x50, 0x97, 
  0xC5, 0x8F, 0x24, 0x08, 0xD6, 0x08, 0xB2, 0x1B, 
  0x39, 0xCC, 0x85, 0xE4, 0x1C, 0x5C, 0xE9, 0x5A, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3:
*/
unsigned char K3_M_274877906943[] = {
  0x37, 0x06, 0xB1, 0xBE, 0xE6, 0xF3, 0xBE, 0xDB, 
  0x74, 0x66, 0x4E, 0x1C, 0x43, 0x40, 0xB5, 0xE1, 
  0x81, 0x5F, 0xFA, 0x87, 0xEA, 0x80, 0xF4, 0x0E, 
  0xAF, 0xCC, 0x28, 0xEF, 0x30, 0xDD, 0xF3, 0xBB, 
};

/*
Выработка ключа защиты записи с номером 274877906944: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1: 
*/
unsigned char K1_M_274877906944[] = {
  0x89, 0xAB, 0x52, 0x9B, 0x2F, 0xE3, 0xDC, 0x74, 
  0xC2, 0x78, 0x46, 0x9F, 0x15, 0x7F, 0xAF, 0x6B,
  0xA9, 0xFB, 0x32, 0xD4, 0xB3, 0xC8, 0xA1, 0x0E, 
  0xC9, 0xDE, 0x68, 0xE5, 0x2A, 0x25, 0x3D, 0xDE, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_M_274877906944[] = {
  0xAA, 0x4D, 0x07, 0x83, 0x68, 0xC7, 0xD8, 0x85, 
  0x3C, 0x77, 0xBC, 0xEF, 0xC2, 0xB5, 0x77, 0xFE, 
  0xEC, 0xEF, 0x53, 0x79, 0xFB, 0x6A, 0x69, 0x22, 
  0x71, 0x5F, 0x6D, 0x70, 0x5F, 0xB9, 0x9F, 0x3D, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3: 
*/
unsigned char K3_M_274877906944[] = {
  0x9B, 0xE5, 0x7C, 0xB5, 0x2F, 0x46, 0xB6, 0x0C, 
  0x68, 0x40, 0xCD, 0x4E, 0x95, 0x9A, 0x16, 0x8A, 
  0x74, 0x82, 0x2C, 0x1D, 0x00, 0x6A, 0xC7, 0x46, 
  0xDA, 0xBB, 0xB9, 0x84, 0x8E, 0xB0, 0xA5, 0x8A, 
};

unsigned char *K3_M[] = {
  K3_M_0,
  K3_M_4095,
  K3_M_4096,
  K3_M_33554431,
  K3_M_33554432,
  K3_M_274877906943,
  K3_M_274877906944,
};

/*
A.2 TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC

Значение корневого ключа Kroot: 
*/
unsigned char KrootK[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
};

unsigned long long secnumsK[] = {
  0, 
  63, 
  64, 
  524287, 
  524288, 
  4294967295, 
  4294967296,
};
/*
Выработка ключа защиты записи с номером 0: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1:
*/
unsigned char K1_K_0[] = {
0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2: 
*/
unsigned char K2_K_0[] = {
0xAB, 0x3D, 0xFD, 0x55, 0x68, 0x6D, 0x55, 0x97, 
0x63, 0x5C, 0xFE, 0x08, 0x6C, 0x12, 0xF0, 0x2D, 
0x40, 0x72, 0x2B, 0xA4, 0x65, 0x9F, 0x51, 0x77, 
0x34, 0xF8, 0xC5, 0x84, 0xB8, 0xF9, 0xE9, 0x9B, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3:
*/
unsigned char K3_K_0[] = {
0x50, 0x76, 0x42, 0xD9, 0x58, 0xC5, 0x20, 0xC6, 
0xD7, 0xEE, 0xF5, 0xCA, 0x8A, 0x53, 0x16, 0xD4, 
0xF3, 0x4B, 0x85, 0x5D, 0x2D, 0xD4, 0xBC, 0xBF, 
0x4E, 0x5B, 0xF0, 0xFF, 0x64, 0x1A, 0x19, 0xFF,
};

/*
Выработка ключа защиты записи с номером 63: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1:
*/
unsigned char K1_K_63[] = {
0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_K_63[] = {
0xAB, 0x3D, 0xFD, 0x55, 0x68, 0x6D, 0x55, 0x97, 
0x63, 0x5C, 0xFE, 0x08, 0x6C, 0x12, 0xF0, 0x2D, 
0x40, 0x72, 0x2B, 0xA4, 0x65, 0x9F, 0x51, 0x77, 
0x34, 0xF8, 0xC5, 0x84, 0xB8, 0xF9, 0xE9, 0x9B, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3:
*/
unsigned char K3_K_63[] = {
0x50, 0x76, 0x42, 0xD9, 0x58, 0xC5, 0x20, 0xC6, 
0xD7, 0xEE, 0xF5, 0xCA, 0x8A, 0x53, 0x16, 0xD4, 
0xF3, 0x4B, 0x85, 0x5D, 0x2D, 0xD4, 0xBC, 0xBF, 
0x4E, 0x5B, 0xF0, 0xFF, 0x64, 0x1A, 0x19, 0xFF, 
};

/*
Выработка ключа защиты записи с номером 64: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1:
*/
unsigned char K1_K_64[] = {
0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_K_64[] = {
0xAB, 0x3D, 0xFD, 0x55, 0x68, 0x6D, 0x55, 0x97, 
0x63, 0x5C, 0xFE, 0x08, 0x6C, 0x12, 0xF0, 0x2D, 
0x40, 0x72, 0x2B, 0xA4, 0x65, 0x9F, 0x51, 0x77, 
0x34, 0xF8, 0xC5, 0x84, 0xB8, 0xF9, 0xE9, 0x9B, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3:
*/
unsigned char K3_K_64[] = {
0xC1, 0x9B, 0x63, 0x9F, 0x4B, 0xEA, 0x78, 0x8C, 
0x1C, 0x59, 0xB4, 0xC8, 0x87, 0xDB, 0x5B, 0x07, 
0xC1, 0x91, 0x19, 0x10, 0x18, 0x68, 0xDA, 0xB8, 
0x9A, 0x8D, 0x93, 0x61, 0xB2, 0xF0, 0x10, 0xF3, 
};

/*
Выработка ключа защиты записи с номером 524287: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1: 
*/
unsigned char K1_K_524287[] = {
0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_K_524287[] = {
0xAB, 0x3D, 0xFD, 0x55, 0x68, 0x6D, 0x55, 0x97, 
0x63, 0x5C, 0xFE, 0x08, 0x6C, 0x12, 0xF0, 0x2D, 
0x40, 0x72, 0x2B, 0xA4, 0x65, 0x9F, 0x51, 0x77, 
0x34, 0xF8, 0xC5, 0x84, 0xB8, 0xF9, 0xE9, 0x9B, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3: 
*/
unsigned char K3_K_524287[] = {
0x92, 0x30, 0x3E, 0xB5, 0x61, 0x56, 0x88, 0x54, 
0xE3, 0x3E, 0x4F, 0xE0, 0x97, 0xA9, 0x95, 0x99, 
0x17, 0x9F, 0x5B, 0x90, 0x94, 0xAE, 0x34, 0x79, 
0xE6, 0x1C, 0x43, 0x69, 0x3A, 0x3F, 0x0A, 0x06, 
};

/*
Выработка ключа защиты записи с номером 524288: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1:
*/
unsigned char K1_K_524288[] = {
0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2: 
*/
unsigned char K2_K_524288[] = {
0x1E, 0xC6, 0x92, 0x34, 0xD7, 0x1F, 0xB8, 0x92, 
0x1A, 0xCF, 0x26, 0xC9, 0x2F, 0xB8, 0x8C, 0x52, 
0x10, 0x57, 0x0B, 0x6B, 0x21, 0x0D, 0xBF, 0x77, 
0x4E, 0x75, 0x97, 0xC1, 0xD8, 0xCE, 0x16, 0x0C, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3: 
*/
unsigned char K3_K_524288[] = {
0xE8, 0x55, 0xA0, 0xE2, 0xCB, 0xDD, 0x68, 0xC1, 
0x13, 0x7C, 0xEF, 0x3E, 0x80, 0x1E, 0x0B, 0xFF, 
0x68, 0x62, 0x8C, 0x36, 0x43, 0x68, 0x27, 0x6D, 
0x0C, 0xB8, 0x7E, 0xB5, 0x6E, 0x94, 0xEF, 0x42,
};
/*
Выработка ключа защиты записи с номером 4294967295: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1:
*/
unsigned char K1_K_4294967295[] = {
0x27, 0x67, 0x9F, 0xFB, 0xFA, 0x99, 0x43, 0x54, 
0x30, 0x51, 0xFD, 0x5E, 0xA3, 0x50, 0xC7, 0xF0, 
0x32, 0xEC, 0xC2, 0xE7, 0x5F, 0xA2, 0x11, 0x96, 
0xA6, 0xAE, 0x12, 0xC0, 0x14, 0x83, 0xF1, 0xA2, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_K_4294967295[] = {
0xED, 0x6A, 0xF8, 0x70, 0x1B, 0x59, 0xA1, 0xEF, 
0xD4, 0x5A, 0x6E, 0x33, 0xCF, 0x80, 0xB7, 0x66, 
0xD5, 0x20, 0x7A, 0x0B, 0x28, 0x80, 0xCD, 0x63, 
0x63, 0x4E, 0x80, 0xB1, 0x83, 0xF9, 0xF3, 0xD4, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3:
*/
unsigned char K3_K_4294967295[] = {
0x93, 0xD3, 0xCA, 0xE9, 0x5A, 0x55, 0xB7, 0x1A, 
0xA3, 0xB9, 0xA7, 0xDD, 0xF9, 0x9A, 0x6A, 0xAC, 
0x3F, 0xDA, 0x17, 0x2A, 0x79, 0x60, 0x58, 0x04, 
0xA9, 0xC9, 0xFC, 0x6E, 0x84, 0x8A, 0xF1, 0xAA, 
};

/*
Выработка ключа защиты записи с номером 4294967296: 
1. Ключ первого уровня, являющийся результатом работы функции Divers1:
*/
unsigned char K1_K_4294967296[] = {
0xE2, 0xBE, 0xDA, 0xBC, 0x66, 0x55, 0x9F, 0x65, 
0xFB, 0x55, 0xE5, 0x52, 0x73, 0x56, 0x50, 0xEE,
0x71, 0x0F, 0x08, 0x81, 0xA0, 0x81, 0xEF, 0xEA, 
0x6B, 0x7A, 0xBA, 0x82, 0xBD, 0xAF, 0x8A, 0x6E, 
};
/*
2. Ключ второго уровня, являющийся результатом работы функции Divers2:
*/
unsigned char K2_K_4294967296[] = {
0x5E, 0x6A, 0xD9, 0x06, 0xEE, 0xE7, 0x85, 0xF8, 
0xBE, 0x28, 0x6C, 0xC7, 0x04, 0xC2, 0x5D, 0x46, 
0xD6, 0x54, 0x9D, 0x18, 0x71, 0x9D, 0x9B, 0xE7, 
0xFE, 0x79, 0xD0, 0x1D, 0xA4, 0x37, 0xA1, 0xDB, 
};
/*
3. Итоговое значение ключа, являющееся результатом работы функции Divers3:
*/
unsigned char K3_K_4294967296[] = {
0x7F, 0xFB, 0x1A, 0xD7, 0xE5, 0x7B, 0x70, 0xBE, 
0x10, 0x96, 0x31, 0xD2, 0x71, 0x92, 0x98, 0xB9, 
0x7D, 0xEE, 0x3B, 0x00, 0x8D, 0x86, 0xF8, 0x3D, 
0xAA, 0xF6, 0x2A, 0x4E, 0xA5, 0xB7, 0xAA, 0xFD,
};

unsigned char *K3_K[] = {
  K3_K_0,
  K3_K_63,
  K3_K_64,
  K3_K_524287,
  K3_K_524288,
  K3_K_4294967295,
  K3_K_4294967296,
};

CK_RV test_tls_tree_gost3411_2012_256(CK_SESSION_HANDLE sess)
{
    CK_RV rc = CKR_OK;
    static CK_BYTE                value[256];
    CK_ULONG               len;
    CK_MECHANISM           mechanism_desc =
    { CKM_TLS_TREE_GOSTR3411_2012_256, NULL, 0 };
    CK_MECHANISM_PTR       mechanism = &mechanism_desc;
	// Тип шифрсьюта определяется по типу исходного ключа - CKK_MAGMA,
	// CKK_KUZNYECHIK или CKK_GENERIC_SECRET.
	// В параметре механизма передается 8 байтов номера сообщения SecNum
	// в порядке big-endian (старший байт - в начале массива).
	// Сообщения нумеруются начиная с 0.
	CK_BYTE SecNum0[] = {
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	};
	CK_BYTE SecNum1[] = {
		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0F, 0xF0, 
	};
	CK_BYTE SecNum2[] = {
		0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0x30, 
	};
  size_t i;
  unsigned long long secnum;
  CK_BYTE SecNumBytes[8];

    CK_OBJECT_HANDLE       keyh          = CK_INVALID_HANDLE;
    CK_OBJECT_HANDLE       kdfkeyh       = CK_INVALID_HANDLE;
    static CK_OBJECT_CLASS oclass        = CKO_SECRET_KEY;
    static CK_KEY_TYPE     key_type_M      = CKK_MAGMA;
    static CK_KEY_TYPE     key_type_K      = CKK_KUZNYECHIK;
    static CK_KEY_TYPE     key_type_N      = CKK_GENERIC_SECRET;
    static CK_BBOOL        ltrue         = CK_TRUE;
    CK_BYTE                key[] = {
        0x79, 0x8b, 0xd0, 0x9e, 0xf7, 0xad, 0x67, 0x64,
        0x6a, 0x3b, 0x74, 0xfe, 0x48, 0xd7, 0x31, 0x73,
        0x50, 0xa8, 0x6f, 0x07, 0x7d, 0x05, 0xef, 0x78,
        0xcb, 0xe9, 0xba, 0x3c, 0x9e, 0xf3, 0xa4, 0x11,
    };

	// Для шифрсьюта TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC
    CK_ATTRIBUTE key_template_M[] = {
        { CKA_VALUE,            NULL_PTR,                 0 },
        { CKA_CLASS,            &oclass,   sizeof(oclass)   },
        { CKA_KEY_TYPE,         &key_type_M, sizeof(key_type_M) },
        { CKA_ENCRYPT,          &ltrue,    sizeof(ltrue)    },
        { CKA_DECRYPT,          &ltrue,    sizeof(ltrue)    },
        { CKA_SIGN,				&ltrue,    sizeof(ltrue)    },
        { CKA_VERIFY,			&ltrue,    sizeof(ltrue)    },
		    { CKA_DERIVE,			&ltrue, sizeof(ltrue) },
    };
	// В данной реализации тип выходного ключа должен совпадать 
	// с типом входного, потому что по типу входного ключа 
	// определяется шифрсьют TLS, от которого зависят константы 
	// C1, C2, C3 алгоритма TLS_TREE.
    CK_ATTRIBUTE key_derive_template_M[] = {
        { CKA_CLASS,            &oclass,   sizeof(oclass)   },
        { CKA_KEY_TYPE,         &key_type_M, sizeof(key_type_M) },
        { CKA_ENCRYPT,          &ltrue,    sizeof(ltrue)    },
        { CKA_DECRYPT,          &ltrue,    sizeof(ltrue)    },
        { CKA_SIGN,				&ltrue,    sizeof(ltrue)    },
        { CKA_VERIFY,			&ltrue,    sizeof(ltrue)    },
    };
    CK_BYTE         et0_M[] = {
		0xa4, 0xc2, 0xc0, 0x3c, 0xda, 0x00, 0x80, 0xf9,
		0xf7, 0xdd, 0x90, 0x5d, 0x1d, 0xd6, 0xa1, 0x24,
		0x22, 0xe5, 0xc6, 0x6e, 0x2c, 0x75, 0xcc, 0xf3,
		0x23, 0x7f, 0x5b, 0xdc, 0x61, 0xd3, 0x5b, 0x3b,    
	};
    CK_BYTE         et1_M[] = {
		0x4f, 0x52, 0x2b, 0x17, 0x30, 0x17, 0x52, 0x7d,
		0x33, 0xd3, 0x4a, 0x1a, 0xb0, 0x4b, 0xe2, 0x1d,
		0x5e, 0x4c, 0xb3, 0x3d, 0x57, 0xe7, 0x46, 0x4f,
		0x8e, 0x4e, 0xf8, 0xba, 0xc1, 0xe8, 0x93, 0x43,	
	};
    CK_BYTE         et2_M[] = {
		0x16, 0xde, 0x23, 0x4e, 0x46, 0x65, 0x10, 0xb0,
		0xfb, 0xa4, 0xbb, 0xb7, 0x32, 0x18, 0x68, 0xd2,
		0x0f, 0x50, 0xc2, 0x71, 0x79, 0x71, 0x68, 0x75,
		0x35, 0xfe, 0x45, 0x45, 0x5f, 0x13, 0x56, 0x38,
	};

	// Для шифрсьюта TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC
    CK_ATTRIBUTE key_template_K[] = {
        { CKA_VALUE,            NULL_PTR,                 0 },
        { CKA_CLASS,            &oclass,   sizeof(oclass)   },
        { CKA_KEY_TYPE,         &key_type_K, sizeof(key_type_K) },
        { CKA_ENCRYPT,          &ltrue,    sizeof(ltrue)    },
        { CKA_DECRYPT,          &ltrue,    sizeof(ltrue)    },
        { CKA_SIGN,				&ltrue,    sizeof(ltrue)    },
        { CKA_VERIFY,			&ltrue,    sizeof(ltrue)    },
		{ CKA_DERIVE,			&ltrue, sizeof(ltrue) },
    };

    CK_ATTRIBUTE key_derive_template_K[] = {
        { CKA_CLASS,            &oclass,   sizeof(oclass)   },
        { CKA_KEY_TYPE,         &key_type_K, sizeof(key_type_K) },
        { CKA_ENCRYPT,          &ltrue,    sizeof(ltrue)    },
        { CKA_DECRYPT,          &ltrue,    sizeof(ltrue)    },
        { CKA_SIGN,				&ltrue,    sizeof(ltrue)    },
        { CKA_VERIFY,			&ltrue,    sizeof(ltrue)    },
    };

    CK_BYTE         et0_K[] = {
		0xa4, 0xc2, 0xc0, 0x3c, 0xda, 0x00, 0x80, 0xf9,
		0xf7, 0xdd, 0x90, 0x5d, 0x1d, 0xd6, 0xa1, 0x24,
		0x22, 0xe5, 0xc6, 0x6e, 0x2c, 0x75, 0xcc, 0xf3,
		0x23, 0x7f, 0x5b, 0xdc, 0x61, 0xd3, 0x5b, 0x3b,    
	};
    CK_BYTE         et1_K[] = {
		0xf6, 0x5f, 0xb3, 0x5f, 0x30, 0x3e, 0x51, 0x81,
		0xc5, 0xad, 0x3b, 0x98, 0xe6, 0x80, 0xd5, 0x39,
		0x1c, 0x2b, 0x8c, 0x79, 0x6b, 0x75, 0x22, 0xa9,
		0x76, 0xd4, 0x60, 0x83, 0xc1, 0xcf, 0x66, 0x13,
	};
    CK_BYTE         et2_K[] = {
		0x3c, 0xf7, 0xb1, 0x42, 0xd8, 0x98, 0xf4, 0xe7,
		0xd9, 0x1d, 0xc8, 0xff, 0x0a, 0x18, 0x7f, 0x98,
		0x63, 0xbb, 0x3f, 0xe9, 0x99, 0xb4, 0x6e, 0x9a,
		0x64, 0x85, 0x96, 0x26, 0xf9, 0x70, 0xa8, 0xed,
	};

	// Для шифрсьюта TLS_GOSTR341112_256_WITH_NULL_HMAC
    CK_ATTRIBUTE key_template_N[] = {
        { CKA_VALUE,            NULL_PTR,                 0 },
        { CKA_CLASS,            &oclass,   sizeof(oclass)   },
        { CKA_KEY_TYPE,         &key_type_N, sizeof(key_type_N) },
        { CKA_SIGN,				&ltrue,    sizeof(ltrue)    },
        { CKA_VERIFY,			&ltrue,    sizeof(ltrue)    },
		{ CKA_DERIVE,			&ltrue, sizeof(ltrue) },
    };

	// Для CKK_GENERIC_SECRET CKA_ENCRYPT и CKA_DECRYPT не указываются,
	// потому что результирующий ключ предназначен только для HMAC.
    CK_ATTRIBUTE key_derive_template_N[] = {
        { CKA_CLASS,            &oclass,   sizeof(oclass)   },
        { CKA_KEY_TYPE,         &key_type_N, sizeof(key_type_N) },
        { CKA_SIGN,				&ltrue,    sizeof(ltrue)    },
        { CKA_VERIFY,			&ltrue,    sizeof(ltrue)    },
    };

    CK_BYTE         et0_N[] = {
		0xa4, 0xc2, 0xc0, 0x3c, 0xda, 0x00, 0x80, 0xf9,
		0xf7, 0xdd, 0x90, 0x5d, 0x1d, 0xd6, 0xa1, 0x24,
		0x22, 0xe5, 0xc6, 0x6e, 0x2c, 0x75, 0xcc, 0xf3,
		0x23, 0x7f, 0x5b, 0xdc, 0x61, 0xd3, 0x5b, 0x3b,    
	};
    CK_BYTE         et1_N[] = {
		0xf6, 0x5f, 0xb3, 0x5f, 0x30, 0x3e, 0x51, 0x81,
		0xc5, 0xad, 0x3b, 0x98, 0xe6, 0x80, 0xd5, 0x39,
		0x1c, 0x2b, 0x8c, 0x79, 0x6b, 0x75, 0x22, 0xa9,
		0x76, 0xd4, 0x60, 0x83, 0xc1, 0xcf, 0x66, 0x13,
	};
    CK_BYTE         et2_N[] = {
		0x3c, 0xf7, 0xb1, 0x42, 0xd8, 0x98, 0xf4, 0xe7,
		0xd9, 0x1d, 0xc8, 0xff, 0x0a, 0x18, 0x7f, 0x98,
		0x63, 0xbb, 0x3f, 0xe9, 0x99, 0xb4, 0x6e, 0x9a,
		0x64, 0x85, 0x96, 0x26, 0xf9, 0x70, 0xa8, 0xed,
	};

    CK_ATTRIBUTE value_template[] = {
        { CKA_VALUE, value, sizeof(value) },
    };

    printf("CKK_MAGMA KrootM:\n");
    print_bytes(KrootM, sizeof(KrootM));

    key_template_M[0].pValue     = KrootM;
    key_template_M[0].ulValueLen = sizeof(KrootM);
    rc                         = funcs->C_CreateObject(sess,
                                                       key_template_M, sizeof(key_template_M) / sizeof(CK_ATTRIBUTE),
                                                       &keyh);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_CreateObject failed: 0x%lx\n", rc);
        goto end;
    }

    for (i=0; i<sizeof(secnumsM)/sizeof(unsigned long long); i++){
      secnum = secnumsM[i];
      printf("secnum = %lld\n", secnum);
      Uint64ToUint8BE(secnum, SecNumBytes);
      mechanism->pParameter     = SecNumBytes;
      mechanism->ulParameterLen = sizeof(SecNumBytes);

      rc                        = funcs->C_DeriveKey(sess, mechanism, keyh,
                                                     key_derive_template_M,
                                                     sizeof(key_derive_template_M) / sizeof(CK_ATTRIBUTE),
                                                     &kdfkeyh);
      if (rc != CKR_OK)
      {
          fprintf(stderr, "C_DeriveKey failed: 0x%lx\n", rc);
          goto end;
      }
      rc = funcs->C_GetAttributeValue(sess, kdfkeyh,
                                      value_template,
                                      sizeof(value_template) / sizeof(CK_ATTRIBUTE));
      if (rc != CKR_OK)
      {
          fprintf(stderr, "C_GetAttributeValue failed: 0x%lx\n", rc);
          goto end;
      }
      len = value_template[0].ulValueLen;
      if (len != sizeof(KrootM))
      {
          fprintf(stderr, "Invalid length: %ld\n", len);
          rc = CKR_FUNCTION_FAILED;
          goto end;
      }
      print_bytes(value, len);
      if (memcmp(value, K3_M[i], len) != 0)
      {
          fprintf(stderr, "Invalid value\n");
          rc = CKR_FUNCTION_FAILED;
          goto end;
      }
      funcs->C_DestroyObject(sess, kdfkeyh);
	    kdfkeyh = CK_INVALID_HANDLE;

      printf("TLS_TREE Magma secnum = %lld OK\n", secnum);
    }

	  funcs->C_DestroyObject(sess, keyh);
	  keyh = CK_INVALID_HANDLE;
    printf("TLS_TREE Magma OK\n");

	  printf("CKK_KUZNYECHIK\n");
    key_template_K[0].pValue     = KrootK;
    key_template_K[0].ulValueLen = sizeof(KrootK);
    rc                         = funcs->C_CreateObject(sess,
                                                       key_template_K, sizeof(key_template_K) / sizeof(CK_ATTRIBUTE),
                                                       &keyh);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_CreateObject failed: 0x%lx\n", rc);
        goto end;
    }

    for (i=0; i<sizeof(secnumsK)/sizeof(unsigned long long); i++){
      secnum = secnumsK[i];
      printf("secnum = %lld\n", secnum);
      Uint64ToUint8BE(secnum, SecNumBytes);
      mechanism->pParameter     = SecNumBytes;
      mechanism->ulParameterLen = sizeof(SecNumBytes);

      rc                        = funcs->C_DeriveKey(sess, mechanism, keyh,
                                                   key_derive_template_K,
                                                   sizeof(key_derive_template_K) / sizeof(CK_ATTRIBUTE),
                                                   &kdfkeyh);
      if (rc != CKR_OK)
      {
        fprintf(stderr, "C_DeriveKey failed: 0x%lx\n", rc);
        goto end;
      }
      rc = funcs->C_GetAttributeValue(sess, kdfkeyh,
                                    value_template,
                                    sizeof(value_template) / sizeof(CK_ATTRIBUTE));
      if (rc != CKR_OK)
      {
        fprintf(stderr, "C_GetAttributeValue failed: 0x%lx\n", rc);
        goto end;
      }
      len = value_template[0].ulValueLen;
      if (len != sizeof(KrootK))
      {
        fprintf(stderr, "Invalid length: %ld\n", len);
        rc = CKR_FUNCTION_FAILED;
        goto end;
      }
      print_bytes(value, len);
      if (memcmp(value, K3_K[i], len) != 0)
      {
        fprintf(stderr, "Invalid value\n");
        rc = CKR_FUNCTION_FAILED;
        goto end;
      }
      funcs->C_DestroyObject(sess, kdfkeyh);
	    kdfkeyh = CK_INVALID_HANDLE;
      printf("TLS_TREE Magma secnum = %lld OK\n", secnum);
    }

	  funcs->C_DestroyObject(sess, keyh);
	  keyh = CK_INVALID_HANDLE;
    printf("TLS_TREE Kuznyechik OK\n");
/*
	printf("CKK_GENERIC_SECRET\n");
    key_template_N[0].pValue     = key;
    key_template_N[0].ulValueLen = sizeof(key);
    rc                         = funcs->C_CreateObject(sess,
                                                       key_template_N, sizeof(key_template_N) / sizeof(CK_ATTRIBUTE),
                                                       &keyh);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_CreateObject failed: 0x%lx\n", rc);
        goto end;
    }

    mechanism->pParameter     = SecNum0;
    mechanism->ulParameterLen = sizeof(SecNum0);

    rc                        = funcs->C_DeriveKey(sess, mechanism, keyh,
                                                   key_derive_template_N,
                                                   sizeof(key_derive_template_N) / sizeof(CK_ATTRIBUTE),
                                                   &kdfkeyh);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_DeriveKey failed: 0x%lx\n", rc);
        goto end;
    }
    rc = funcs->C_GetAttributeValue(sess, kdfkeyh,
                                    value_template,
                                    sizeof(value_template) / sizeof(CK_ATTRIBUTE));
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GetAttributeValue failed: 0x%lx\n", rc);
        goto end;
    }
    len = value_template[0].ulValueLen;
    if (len != sizeof(et0_N))
    {
        fprintf(stderr, "Invalid length: %ld\n", len);
        rc = CKR_FUNCTION_FAILED;
        goto end;
    }
    print_bytes(value, len);
    if (memcmp(value, et0_N, len) != 0)
    {
        fprintf(stderr, "Invalid value\n");
        rc = CKR_FUNCTION_FAILED;
        goto end;
    }
    funcs->C_DestroyObject(sess, kdfkeyh);
	kdfkeyh = CK_INVALID_HANDLE;

    printf("TLS_TREE 0 N OK\n");

    mechanism->pParameter     = SecNum1;
    mechanism->ulParameterLen = sizeof(SecNum1);

    rc                        = funcs->C_DeriveKey(sess, mechanism, keyh,
                                                   key_derive_template_N,
                                                   sizeof(key_derive_template_N) / sizeof(CK_ATTRIBUTE),
                                                   &kdfkeyh);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_DeriveKey failed: 0x%lx\n", rc);
        goto end;
    }
    rc = funcs->C_GetAttributeValue(sess, kdfkeyh,
                                    value_template,
                                    sizeof(value_template) / sizeof(CK_ATTRIBUTE));
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GetAttributeValue failed: 0x%lx\n", rc);
        goto end;
    }
    len = value_template[0].ulValueLen;
    if (len != sizeof(et1_N))
    {
        fprintf(stderr, "Invalid length: %ld\n", len);
        rc = CKR_FUNCTION_FAILED;
        goto end;
    }
    print_bytes(value, len);
    if (memcmp(value, et1_N, len) != 0)
    {
        fprintf(stderr, "Invalid value\n");
        rc = CKR_FUNCTION_FAILED;
        goto end;
    }
    funcs->C_DestroyObject(sess, kdfkeyh);
	kdfkeyh = CK_INVALID_HANDLE;
    printf("TLS_TREE 1 N OK\n");

    mechanism->pParameter     = SecNum2;
    mechanism->ulParameterLen = sizeof(SecNum2);

    rc                        = funcs->C_DeriveKey(sess, mechanism, keyh,
                                                   key_derive_template_N,
                                                   sizeof(key_derive_template_N) / sizeof(CK_ATTRIBUTE),
                                                   &kdfkeyh);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_DeriveKey failed: 0x%lx\n", rc);
        goto end;
    }
    rc = funcs->C_GetAttributeValue(sess, kdfkeyh,
                                    value_template,
                                    sizeof(value_template) / sizeof(CK_ATTRIBUTE));
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_GetAttributeValue failed: 0x%lx\n", rc);
        goto end;
    }
    len = value_template[0].ulValueLen;
    if (len != sizeof(et2_N))
    {
        fprintf(stderr, "Invalid length: %ld\n", len);
        rc = CKR_FUNCTION_FAILED;
        goto end;
    }
    print_bytes(value, len);
    if (memcmp(value, et2_N, len) != 0)
    {
        fprintf(stderr, "Invalid value\n");
        rc = CKR_FUNCTION_FAILED;
        goto end;
    }
    funcs->C_DestroyObject(sess, kdfkeyh);
	kdfkeyh = CK_INVALID_HANDLE;
	funcs->C_DestroyObject(sess, keyh);
	keyh = CK_INVALID_HANDLE;
    printf("TLS_TREE 2 N OK\n");
*/
    rc = CKR_OK;
 end:
    if (keyh != CK_INVALID_HANDLE)
    {
        funcs->C_DestroyObject(sess, keyh);
    }

    return rc;
}

