package ru.rutoken.samples.pkcs11Wrapper;

import com.sun.jna.Memory;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.NativeLongByReference;
import ru.rutoken.Pkcs11.*;

public class PKIExtensions {
    // Значения ключевой пары ГОСТ Р 34.10-2001
    private final static byte[] cbPubKeyValue = {
        (byte)0xfb, (byte)0x3c, (byte)0xdc, (byte)0x59, (byte)0xc3, (byte)0x9c, (byte)0x4a, (byte)0x43,
        (byte)0x89, (byte)0x87, (byte)0xc7, (byte)0xd7, (byte)0xfe, (byte)0x50, (byte)0x19, (byte)0xb3,
        (byte)0x0c, (byte)0x8b, (byte)0x76, (byte)0x97, (byte)0xa9, (byte)0xdf, (byte)0xb7, (byte)0xca,
        (byte)0x2c, (byte)0x6c, (byte)0x3b, (byte)0xa9, (byte)0x13, (byte)0xf4, (byte)0xe0, (byte)0x69,
        (byte)0x02, (byte)0x59, (byte)0x92, (byte)0x47, (byte)0x21, (byte)0x1a, (byte)0xef, (byte)0x90,
        (byte)0x61, (byte)0x91, (byte)0x40, (byte)0x30, (byte)0xdd, (byte)0x7c, (byte)0xb0, (byte)0x4f,
        (byte)0x64, (byte)0x5f, (byte)0x24, (byte)0x9a, (byte)0xf1, (byte)0xd6, (byte)0x0f, (byte)0xa9,
        (byte)0xf0, (byte)0x86, (byte)0xd9, (byte)0x35, (byte)0x2b, (byte)0x3e, (byte)0xf2, (byte)0xf3,
    };

    private final static byte[] cbPrvKeyValue = {
        (byte)0x8b, (byte)0x1d, (byte)0x96, (byte)0xf7, (byte)0x53, (byte)0x7e, (byte)0x69, (byte)0xe2,
        (byte)0xa6, (byte)0x5e, (byte)0xf1, (byte)0xf4, (byte)0xbd, (byte)0xed, (byte)0x84, (byte)0xb4,
        (byte)0xa9, (byte)0x60, (byte)0xba, (byte)0xdd, (byte)0x7b, (byte)0x9f, (byte)0x27, (byte)0x5f,
        (byte)0x68, (byte)0xe3, (byte)0x5e, (byte)0x1a, (byte)0x5c, (byte)0x6e, (byte)0xa4, (byte)0xf6,
    };

    // Значение сертификата ключа подписи
    private final static byte[] cbCertificate = {
        (byte)0x30, (byte)0x82, (byte)0x03, (byte)0x36, (byte)0x30, (byte)0x82, (byte)0x02, (byte)0xe5,
        (byte)0xa0, (byte)0x03, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x0a, (byte)0x24,
        (byte)0xa5, (byte)0x24, (byte)0x63, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x01, (byte)0xa7,
        (byte)0x15, (byte)0x30, (byte)0x08, (byte)0x06, (byte)0x06, (byte)0x2a, (byte)0x85, (byte)0x03,
        (byte)0x02, (byte)0x02, (byte)0x03, (byte)0x30, (byte)0x65, (byte)0x31, (byte)0x20, (byte)0x30,
        (byte)0x1e, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7,
        (byte)0x0d, (byte)0x01, (byte)0x09, (byte)0x01, (byte)0x16, (byte)0x11, (byte)0x69, (byte)0x6e,
        (byte)0x66, (byte)0x6f, (byte)0x40, (byte)0x63, (byte)0x72, (byte)0x79, (byte)0x70, (byte)0x74,
        (byte)0x6f, (byte)0x70, (byte)0x72, (byte)0x6f, (byte)0x2e, (byte)0x72, (byte)0x75, (byte)0x31,
        (byte)0x0b, (byte)0x30, (byte)0x09, (byte)0x06, (byte)0x03, (byte)0x55, (byte)0x04, (byte)0x06,
        (byte)0x13, (byte)0x02, (byte)0x52, (byte)0x55, (byte)0x31, (byte)0x13, (byte)0x30, (byte)0x11,
        (byte)0x06, (byte)0x03, (byte)0x55, (byte)0x04, (byte)0x0a, (byte)0x13, (byte)0x0a, (byte)0x43,
        (byte)0x52, (byte)0x59, (byte)0x50, (byte)0x54, (byte)0x4f, (byte)0x2d, (byte)0x50, (byte)0x52,
        (byte)0x4f, (byte)0x31, (byte)0x1f, (byte)0x30, (byte)0x1d, (byte)0x06, (byte)0x03, (byte)0x55,
        (byte)0x04, (byte)0x03, (byte)0x13, (byte)0x16, (byte)0x54, (byte)0x65, (byte)0x73, (byte)0x74,
        (byte)0x20, (byte)0x43, (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x65, (byte)0x72, (byte)0x20,
        (byte)0x43, (byte)0x52, (byte)0x59, (byte)0x50, (byte)0x54, (byte)0x4f, (byte)0x2d, (byte)0x50,
        (byte)0x52, (byte)0x4f, (byte)0x30, (byte)0x1e, (byte)0x17, (byte)0x0d, (byte)0x31, (byte)0x31,
        (byte)0x31, (byte)0x31, (byte)0x32, (byte)0x32, (byte)0x31, (byte)0x30, (byte)0x31, (byte)0x33,
        (byte)0x34, (byte)0x32, (byte)0x5a, (byte)0x17, (byte)0x0d, (byte)0x31, (byte)0x34, (byte)0x31,
        (byte)0x30, (byte)0x30, (byte)0x34, (byte)0x30, (byte)0x37, (byte)0x30, (byte)0x39, (byte)0x34,
        (byte)0x31, (byte)0x5a, (byte)0x30, (byte)0x65, (byte)0x31, (byte)0x10, (byte)0x30, (byte)0x0e,
        (byte)0x06, (byte)0x03, (byte)0x55, (byte)0x04, (byte)0x03, (byte)0x13, (byte)0x07, (byte)0x49,
        (byte)0x76, (byte)0x61, (byte)0x6e, (byte)0x6f, (byte)0x66, (byte)0x66, (byte)0x31, (byte)0x0b,
        (byte)0x30, (byte)0x09, (byte)0x06, (byte)0x03, (byte)0x55, (byte)0x04, (byte)0x06, (byte)0x13,
        (byte)0x02, (byte)0x52, (byte)0x55, (byte)0x31, (byte)0x14, (byte)0x30, (byte)0x12, (byte)0x06,
        (byte)0x03, (byte)0x55, (byte)0x04, (byte)0x05, (byte)0x13, (byte)0x0b, (byte)0x31, (byte)0x32,
        (byte)0x33, (byte)0x31, (byte)0x32, (byte)0x33, (byte)0x31, (byte)0x32, (byte)0x33, (byte)0x31,
        (byte)0x32, (byte)0x31, (byte)0x1d, (byte)0x30, (byte)0x1b, (byte)0x06, (byte)0x09, (byte)0x2a,
        (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x09, (byte)0x01,
        (byte)0x16, (byte)0x0e, (byte)0x69, (byte)0x76, (byte)0x61, (byte)0x6e, (byte)0x6f, (byte)0x76,
        (byte)0x40, (byte)0x6d, (byte)0x61, (byte)0x69, (byte)0x6c, (byte)0x2e, (byte)0x72, (byte)0x75,
        (byte)0x31, (byte)0x0f, (byte)0x30, (byte)0x0d, (byte)0x06, (byte)0x03, (byte)0x55, (byte)0x04,
        (byte)0x08, (byte)0x13, (byte)0x06, (byte)0x4d, (byte)0x6f, (byte)0x73, (byte)0x63, (byte)0x6f,
        (byte)0x77, (byte)0x30, (byte)0x63, (byte)0x30, (byte)0x1c, (byte)0x06, (byte)0x06, (byte)0x2a,
        (byte)0x85, (byte)0x03, (byte)0x02, (byte)0x02, (byte)0x13, (byte)0x30, (byte)0x12, (byte)0x06,
        (byte)0x07, (byte)0x2a, (byte)0x85, (byte)0x03, (byte)0x02, (byte)0x02, (byte)0x23, (byte)0x01,
        (byte)0x06, (byte)0x07, (byte)0x2a, (byte)0x85, (byte)0x03, (byte)0x02, (byte)0x02, (byte)0x1e,
        (byte)0x01, (byte)0x03, (byte)0x43, (byte)0x00, (byte)0x04, (byte)0x40, (byte)0xfb, (byte)0x3c,
        (byte)0xdc, (byte)0x59, (byte)0xc3, (byte)0x9c, (byte)0x4a, (byte)0x43, (byte)0x89, (byte)0x87,
        (byte)0xc7, (byte)0xd7, (byte)0xfe, (byte)0x50, (byte)0x19, (byte)0xb3, (byte)0x0c, (byte)0x8b,
        (byte)0x76, (byte)0x97, (byte)0xa9, (byte)0xdf, (byte)0xb7, (byte)0xca, (byte)0x2c, (byte)0x6c,
        (byte)0x3b, (byte)0xa9, (byte)0x13, (byte)0xf4, (byte)0xe0, (byte)0x69, (byte)0x02, (byte)0x59,
        (byte)0x92, (byte)0x47, (byte)0x21, (byte)0x1a, (byte)0xef, (byte)0x90, (byte)0x61, (byte)0x91,
        (byte)0x40, (byte)0x30, (byte)0xdd, (byte)0x7c, (byte)0xb0, (byte)0x4f, (byte)0x64, (byte)0x5f,
        (byte)0x24, (byte)0x9a, (byte)0xf1, (byte)0xd6, (byte)0x0f, (byte)0xa9, (byte)0xf0, (byte)0x86,
        (byte)0xd9, (byte)0x35, (byte)0x2b, (byte)0x3e, (byte)0xf2, (byte)0xf3, (byte)0xa3, (byte)0x82,
        (byte)0x01, (byte)0x73, (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x6f, (byte)0x30, (byte)0x0b,
        (byte)0x06, (byte)0x03, (byte)0x55, (byte)0x1d, (byte)0x0f, (byte)0x04, (byte)0x04, (byte)0x03,
        (byte)0x02, (byte)0x04, (byte)0xf0, (byte)0x30, (byte)0x26, (byte)0x06, (byte)0x03, (byte)0x55,
        (byte)0x1d, (byte)0x25, (byte)0x04, (byte)0x1f, (byte)0x30, (byte)0x1d, (byte)0x06, (byte)0x07,
        (byte)0x2a, (byte)0x85, (byte)0x03, (byte)0x02, (byte)0x02, (byte)0x22, (byte)0x06, (byte)0x06,
        (byte)0x08, (byte)0x2b, (byte)0x06, (byte)0x01, (byte)0x05, (byte)0x05, (byte)0x07, (byte)0x03,
        (byte)0x02, (byte)0x06, (byte)0x08, (byte)0x2b, (byte)0x06, (byte)0x01, (byte)0x05, (byte)0x05,
        (byte)0x07, (byte)0x03, (byte)0x04, (byte)0x30, (byte)0x1d, (byte)0x06, (byte)0x03, (byte)0x55,
        (byte)0x1d, (byte)0x0e, (byte)0x04, (byte)0x16, (byte)0x04, (byte)0x14, (byte)0x8a, (byte)0x24,
        (byte)0x35, (byte)0x74, (byte)0x6b, (byte)0xf7, (byte)0x91, (byte)0x17, (byte)0x92, (byte)0xb2,
        (byte)0xcf, (byte)0x8f, (byte)0x63, (byte)0x87, (byte)0xb7, (byte)0x69, (byte)0x06, (byte)0xe1,
        (byte)0x71, (byte)0xf2, (byte)0x30, (byte)0x1f, (byte)0x06, (byte)0x03, (byte)0x55, (byte)0x1d,
        (byte)0x23, (byte)0x04, (byte)0x18, (byte)0x30, (byte)0x16, (byte)0x80, (byte)0x14, (byte)0x6d,
        (byte)0x8f, (byte)0x5e, (byte)0x05, (byte)0xd9, (byte)0x5f, (byte)0xac, (byte)0x91, (byte)0x17,
        (byte)0x94, (byte)0x1e, (byte)0x95, (byte)0x9a, (byte)0x05, (byte)0x30, (byte)0x38, (byte)0x37,
        (byte)0x7a, (byte)0x10, (byte)0x2a, (byte)0x30, (byte)0x55, (byte)0x06, (byte)0x03, (byte)0x55,
        (byte)0x1d, (byte)0x1f, (byte)0x04, (byte)0x4e, (byte)0x30, (byte)0x4c, (byte)0x30, (byte)0x4a,
        (byte)0xa0, (byte)0x48, (byte)0xa0, (byte)0x46, (byte)0x86, (byte)0x44, (byte)0x68, (byte)0x74,
        (byte)0x74, (byte)0x70, (byte)0x3a, (byte)0x2f, (byte)0x2f, (byte)0x77, (byte)0x77, (byte)0x77,
        (byte)0x2e, (byte)0x63, (byte)0x72, (byte)0x79, (byte)0x70, (byte)0x74, (byte)0x6f, (byte)0x70,
        (byte)0x72, (byte)0x6f, (byte)0x2e, (byte)0x72, (byte)0x75, (byte)0x2f, (byte)0x43, (byte)0x65,
        (byte)0x72, (byte)0x74, (byte)0x45, (byte)0x6e, (byte)0x72, (byte)0x6f, (byte)0x6c, (byte)0x6c,
        (byte)0x2f, (byte)0x54, (byte)0x65, (byte)0x73, (byte)0x74, (byte)0x25, (byte)0x32, (byte)0x30,
        (byte)0x43, (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x65, (byte)0x72, (byte)0x25, (byte)0x32,
        (byte)0x30, (byte)0x43, (byte)0x52, (byte)0x59, (byte)0x50, (byte)0x54, (byte)0x4f, (byte)0x2d,
        (byte)0x50, (byte)0x52, (byte)0x4f, (byte)0x28, (byte)0x32, (byte)0x29, (byte)0x2e, (byte)0x63,
        (byte)0x72, (byte)0x6c, (byte)0x30, (byte)0x81, (byte)0xa0, (byte)0x06, (byte)0x08, (byte)0x2b,
        (byte)0x06, (byte)0x01, (byte)0x05, (byte)0x05, (byte)0x07, (byte)0x01, (byte)0x01, (byte)0x04,
        (byte)0x81, (byte)0x93, (byte)0x30, (byte)0x81, (byte)0x90, (byte)0x30, (byte)0x33, (byte)0x06,
        (byte)0x08, (byte)0x2b, (byte)0x06, (byte)0x01, (byte)0x05, (byte)0x05, (byte)0x07, (byte)0x30,
        (byte)0x01, (byte)0x86, (byte)0x27, (byte)0x68, (byte)0x74, (byte)0x74, (byte)0x70, (byte)0x3a,
        (byte)0x2f, (byte)0x2f, (byte)0x77, (byte)0x77, (byte)0x77, (byte)0x2e, (byte)0x63, (byte)0x72,
        (byte)0x79, (byte)0x70, (byte)0x74, (byte)0x6f, (byte)0x70, (byte)0x72, (byte)0x6f, (byte)0x2e,
        (byte)0x72, (byte)0x75, (byte)0x2f, (byte)0x6f, (byte)0x63, (byte)0x73, (byte)0x70, (byte)0x6e,
        (byte)0x63, (byte)0x2f, (byte)0x6f, (byte)0x63, (byte)0x73, (byte)0x70, (byte)0x2e, (byte)0x73,
        (byte)0x72, (byte)0x66, (byte)0x30, (byte)0x59, (byte)0x06, (byte)0x08, (byte)0x2b, (byte)0x06,
        (byte)0x01, (byte)0x05, (byte)0x05, (byte)0x07, (byte)0x30, (byte)0x02, (byte)0x86, (byte)0x4d,
        (byte)0x68, (byte)0x74, (byte)0x74, (byte)0x70, (byte)0x3a, (byte)0x2f, (byte)0x2f, (byte)0x77,
        (byte)0x77, (byte)0x77, (byte)0x2e, (byte)0x63, (byte)0x72, (byte)0x79, (byte)0x70, (byte)0x74,
        (byte)0x6f, (byte)0x70, (byte)0x72, (byte)0x6f, (byte)0x2e, (byte)0x72, (byte)0x75, (byte)0x2f,
        (byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74, (byte)0x45, (byte)0x6e, (byte)0x72, (byte)0x6f,
        (byte)0x6c, (byte)0x6c, (byte)0x2f, (byte)0x70, (byte)0x6b, (byte)0x69, (byte)0x2d, (byte)0x73,
        (byte)0x69, (byte)0x74, (byte)0x65, (byte)0x5f, (byte)0x54, (byte)0x65, (byte)0x73, (byte)0x74,
        (byte)0x25, (byte)0x32, (byte)0x30, (byte)0x43, (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x65,
        (byte)0x72, (byte)0x25, (byte)0x32, (byte)0x30, (byte)0x43, (byte)0x52, (byte)0x59, (byte)0x50,
        (byte)0x54, (byte)0x4f, (byte)0x2d, (byte)0x50, (byte)0x52, (byte)0x4f, (byte)0x28, (byte)0x32,
        (byte)0x29, (byte)0x2e, (byte)0x63, (byte)0x72, (byte)0x74, (byte)0x30, (byte)0x08, (byte)0x06,
        (byte)0x06, (byte)0x2a, (byte)0x85, (byte)0x03, (byte)0x02, (byte)0x02, (byte)0x03, (byte)0x03,
        (byte)0x41, (byte)0x00, (byte)0x2b, (byte)0xd2, (byte)0xfe, (byte)0x64, (byte)0x54, (byte)0x3a,
        (byte)0xe1, (byte)0xf6, (byte)0x89, (byte)0x75, (byte)0xfe, (byte)0xbb, (byte)0xa6, (byte)0x29,
        (byte)0xed, (byte)0x0b, (byte)0x92, (byte)0xc0, (byte)0xa4, (byte)0x84, (byte)0x15, (byte)0x59,
        (byte)0x23, (byte)0x12, (byte)0x08, (byte)0xbb, (byte)0xd3, (byte)0xab, (byte)0x8e, (byte)0x2e,
        (byte)0x75, (byte)0xb9, (byte)0xbf, (byte)0x9e, (byte)0xd1, (byte)0x9d, (byte)0x1e, (byte)0xf9,
        (byte)0x6a, (byte)0x24, (byte)0xed, (byte)0xb8, (byte)0x58, (byte)0x15, (byte)0x1f, (byte)0x03,
        (byte)0x11, (byte)0xfa, (byte)0xd3, (byte)0x85, (byte)0xf1, (byte)0x34, (byte)0x96, (byte)0xac,
        (byte)0x20, (byte)0x8e, (byte)0xdd, (byte)0xad, (byte)0x4e, (byte)0xae, (byte)0x55, (byte)0x3e,
        (byte)0x8d, (byte)0xd1, (byte)0xff,
    };

    private final static byte[] ATTR_CRYPTO_PRO_A = {
        0x06, 0x07, 0x2A, (byte)0x85, 0x03, 0x02, 0x02, 0x23, 0x01};

    // Шаблон для импорта открытого ключа ГОСТ Р 34.10-2001
    private final static CK_ATTRIBUTE[] PublicKeyTmpl = (CK_ATTRIBUTE[]) (new CK_ATTRIBUTE()).toArray(8);
    private static void initPubKeyTemplate(){
        PublicKeyTmpl[0].setAttr(Pkcs11Constants.CKA_CLASS, Pkcs11Constants.CKO_PUBLIC_KEY);
        PublicKeyTmpl[1].setAttr(Pkcs11Constants.CKA_LABEL, new String("Sample GOST R 34.10-2001 Public Key (Aktiv Co.)"));
        PublicKeyTmpl[2].setAttr(Pkcs11Constants.CKA_ID, new String("Sample GOST R 34.10-2001 Keypair (Aktiv Co.)"));
        PublicKeyTmpl[3].setAttr(Pkcs11Constants.CKA_KEY_TYPE, RtPkcs11Constants.CKK_GOSTR3410);
        PublicKeyTmpl[4].setAttr(Pkcs11Constants.CKA_TOKEN, true);
        PublicKeyTmpl[5].setAttr(Pkcs11Constants.CKA_PRIVATE, false);
        PublicKeyTmpl[6].setAttr(RtPkcs11Constants.CKA_GOSTR3410_PARAMS, ATTR_CRYPTO_PRO_A);
        PublicKeyTmpl[7].setAttr(Pkcs11Constants.CKA_VALUE, cbPubKeyValue);
    }

    // Шаблон для импорта закрытого ключа ГОСТ Р 34.10-2001
    private final static CK_ATTRIBUTE[] PrivateKeyTmpl =  (CK_ATTRIBUTE[])(new CK_ATTRIBUTE()).toArray(9);
    private static void initPrivKeyTemplate(){
        PrivateKeyTmpl[0].setAttr(Pkcs11Constants.CKA_CLASS, Pkcs11Constants.CKO_PRIVATE_KEY);
        PrivateKeyTmpl[1].setAttr(Pkcs11Constants.CKA_LABEL, new String("Sample GOST R 34.10-2001 Private Key (Aktiv Co.)"));
        PrivateKeyTmpl[2].setAttr(Pkcs11Constants.CKA_ID, new String("Sample GOST R 34.10-2001 Keypair (Aktiv Co.)"));
        PrivateKeyTmpl[3].setAttr(Pkcs11Constants.CKA_KEY_TYPE, RtPkcs11Constants.CKK_GOSTR3410);
        PrivateKeyTmpl[4].setAttr(Pkcs11Constants.CKA_TOKEN, true);
        PrivateKeyTmpl[5].setAttr(Pkcs11Constants.CKA_PRIVATE, true);
        PrivateKeyTmpl[6].setAttr(Pkcs11Constants.CKA_DERIVE, true);
        PrivateKeyTmpl[7].setAttr(RtPkcs11Constants.CKA_GOSTR3410_PARAMS, ATTR_CRYPTO_PRO_A);
        PrivateKeyTmpl[8].setAttr(Pkcs11Constants.CKA_VALUE, cbPrvKeyValue);
    }

    // Шаблон для импорта сертификата ключа подписи
    private final static CK_ATTRIBUTE[] CertTmpl =  (CK_ATTRIBUTE[])(new CK_ATTRIBUTE()).toArray(6);
    private static void initCertTemplate(){
        CertTmpl[0].setAttr(Pkcs11Constants.CKA_CLASS, Pkcs11Constants.CKO_CERTIFICATE);
        CertTmpl[1].setAttr(Pkcs11Constants.CKA_CERTIFICATE_TYPE, Pkcs11Constants.CKC_X_509);
        CertTmpl[2].setAttr(Pkcs11Constants.CKA_ID, new String("Sample GOST R 34.10-2001 Keypair (Aktiv Co.)"));
        CertTmpl[3].setAttr(Pkcs11Constants.CKA_TOKEN, true);
        CertTmpl[4].setAttr(Pkcs11Constants.CKA_PRIVATE, false);
        CertTmpl[5].setAttr(Pkcs11Constants.CKA_VALUE, cbCertificate);
    }

    // Список полей DN (Distinguished Name)
    private final static String[] dn = 	{
            new String ("CN"),
            new String ("Ivanoff"),
            new String ("C"),
            new String ("RU"),
            new String ("2.5.4.5"),
            new String ("12312312312"),
            new String ("1.2.840.113549.1.9.1"),
            new String ("ivanov@mail.ru"),
            new String ("ST"),
            new String ("Moscow"),
   };

    // Список дополнительных полей
    private final static String[] exts = {
            new String ("keyUsage"),
            new String ("digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment"),
            new String ("extendedKeyUsage"),
            new String ("1.2.643.2.2.34.6,1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.4"),
    };

    // Данные для подписи
    private final static byte[] pbtData = { '1' };

    private final static byte[] USER_PIN = {'1', '2', '3', '4', '5', '6', '7', '8'};

    // Хендлы объектов, которые будут созданы вызовами C_CreateObject
    private final static NativeLongByReference hPubKey = new NativeLongByReference();
    private final static NativeLongByReference hPrvKey = new NativeLongByReference();
    private final static NativeLongByReference hCert = new NativeLongByReference();

    // Указатели на объектов, которые будут созданы вызовами C_CreateObject
    private final static Pointer ppbtCsr = new Memory(Pointer.SIZE);
    private final static Pointer pptSignature = new Memory(Pointer.SIZE);
    private final static Pointer ppbtInfo = new Memory(Pointer.SIZE);

    public static void main(String[] args) {
        NativeLong hSession = Pkcs11Constants.CK_INVALID_HANDLE;

        try {
            System.out.println("Example of rtpkcs11ecp PKI extensions usage via JNA");

            System.out.println("Library initialization and acquiring of function list");
            NativeLong rv = RtPkcs11Library.getInstance().C_Initialize(null);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("Failed to initialize library, error code:" + Long.toHexString(rv.longValue()));
            }

            initPubKeyTemplate();
            initPrivKeyTemplate();
            initCertTemplate();

            ppbtCsr.setPointer(0, null);
            pptSignature.setPointer(0, null);
            ppbtInfo.setPointer(0, null);

            System.out.println("Acquiring list of slots with connected tokens");
            NativeLongByReference slotsCount = new NativeLongByReference();
            rv = RtPkcs11Library.getInstance().C_GetSlotList(true, null, slotsCount);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_GetSlotList failed, error code: " + Long.toHexString(rv.longValue()));
            }
            if (slotsCount.getValue().intValue() == 0)
            {
                throw new Exception("No Rutoken is available!");
            }
            NativeLong[] pSlotList = new NativeLong[slotsCount.getValue().intValue()];
            rv = RtPkcs11Library.getInstance().C_GetSlotList(true, pSlotList, slotsCount);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_GetSlotList failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Opening session");
            NativeLongByReference phSession = new NativeLongByReference();
            rv = RtPkcs11Library.getInstance().C_OpenSession(pSlotList[0],
                    new NativeLong(Pkcs11Constants.CKF_SERIAL_SESSION.longValue() | Pkcs11Constants.CKF_RW_SESSION.longValue()),
                    null, null, phSession);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_OpenSession failed, error code: " + Long.toHexString(rv.longValue()));
            }
            hSession = phSession.getValue();

            System.out.println("Logging in as user");
            rv = RtPkcs11Library.getInstance().C_Login(hSession, Pkcs11Constants.CKU_USER, USER_PIN, new NativeLong(USER_PIN.length));
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_Login failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Creating public key");
            rv = RtPkcs11Library.getInstance().C_CreateObject(hSession, PublicKeyTmpl, new NativeLong(PublicKeyTmpl.length), hPubKey);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_CreateObject failed, error code: " + Long.toHexString(rv.longValue()));
            }
            System.out.println("Creating private key");
            rv = RtPkcs11Library.getInstance().C_CreateObject(hSession, PrivateKeyTmpl, new NativeLong(PrivateKeyTmpl.length), hPrvKey);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_CreateObject failed, error code: " + Long.toHexString(rv.longValue()));
            }

            // Cоздание запроса на сертификат
            System.out.println("Creating certificate request");
            NativeLongByReference ulCsrSize = new NativeLongByReference();
            rv = RtPkcs11Ex.getInstance().C_EX_CreateCSR(hSession, hPubKey.getValue(), dn, new NativeLong(dn.length),
                                                         ppbtCsr, ulCsrSize, hPrvKey.getValue(), null, new NativeLong(0),
                                                         exts, new NativeLong(exts.length));
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_EX_CreateCSR failed, error code" + Long.toHexString(rv.longValue()));
            }
            Pointer pbtCsr = ppbtCsr.getPointer(0);
            System.out.println("Certificate request is: ");
            for (int i = 0; i < ulCsrSize.getValue().intValue(); ++i)
            {
                System.out.printf(" %02X", pbtCsr.getByteArray(0, ulCsrSize.getValue().intValue())[i]);
                if ((i + 1) % 8 == 0)
                    System.out.println();
            }

            System.out.println("\nCreating certificate");
            rv = RtPkcs11Library.getInstance().C_CreateObject(hSession, CertTmpl, new NativeLong(CertTmpl.length), hCert);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_CreateObject failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Acquiring info about certificate");
            NativeLongByReference ulInfoSize = new NativeLongByReference();
            rv = RtPkcs11Ex.getInstance().C_EX_GetCertificateInfoText(hSession, hCert.getValue(), ppbtInfo, ulInfoSize);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("Failed on acquiring info about certificate, error code " + Long.toHexString(rv.longValue()));
            }
            Pointer pbtInfo = ppbtInfo.getPointer(0);
            System.out.println("Certificate is: ");
            for (int i = 0; i < ulInfoSize.getValue().intValue(); ++i)
            {
                System.out.printf(" %02X", pbtInfo.getByteArray(0, ulInfoSize.getValue().intValue())[i]);
                if ((i + 1) % 8 == 0)
                    System.out.println();
            }

            System.out.println("\nPKCS7 signing");
            NativeLongByReference ulSignatureLen = new NativeLongByReference();
            rv = RtPkcs11Ex.getInstance().C_EX_PKCS7Sign(hSession, pbtData, new NativeLong(pbtData.length), hCert.getValue(),
                                                         pptSignature, ulSignatureLen, hPrvKey.getValue(),
                                                         null, new NativeLong(0), new NativeLong(0));
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_EX_PKCS7Sign failed, error code " + Long.toHexString(rv.longValue()));
            }
            Pointer pbtSignature = pptSignature.getPointer(0);

            System.out.println("Signed data is:");
            for (int i = 0; i < ulSignatureLen.getValue().intValue(); ++i)
            {
                System.out.printf(" %02X", pbtSignature.getByteArray(0, ulSignatureLen.getValue().intValue())[i]);
                if ((i + 1) % 8 == 0)
                    System.out.println();
            }
            System.out.println("\nData has been signed successfully.");
        }
        catch(Exception e) {
            System.out.println(e.getMessage());
        }
        finally {
            NativeLong rv = RtPkcs11Ex.getInstance().C_EX_FreeBuffer(ppbtCsr.getPointer(0));
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_EX_FreeBuffer failed, error code: " + Long.toHexString(rv.longValue()));
            }

            rv = RtPkcs11Ex.getInstance().C_EX_FreeBuffer(pptSignature.getPointer(0));
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_EX_FreeBuffer failed, error code: " + Long.toHexString(rv.longValue()));
            }

            rv = RtPkcs11Ex.getInstance().C_EX_FreeBuffer(ppbtInfo.getPointer(0));
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_EX_FreeBuffer failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Deleting public key");
            rv = RtPkcs11Ex.getInstance().C_DestroyObject(hSession, hPubKey.getValue());
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_DestroyObject failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Deleting private key");
            rv = RtPkcs11Ex.getInstance().C_DestroyObject(hSession, hPrvKey.getValue());
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_DestroyObject failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Deleting certificate");
            rv = RtPkcs11Ex.getInstance().C_DestroyObject(hSession, hCert.getValue());
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_DestroyObject failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Logging out");
            rv = RtPkcs11Library.getInstance().C_Logout(hSession);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_Logout failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Closing session");
            rv = RtPkcs11Library.getInstance().C_CloseSession(hSession);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_CloseSession failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Finalizing PKCS11 library");
            rv = RtPkcs11Library.getInstance().C_Finalize(null);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_Finalize failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Test has been completed.");
        }
    }
}
