rtengine и ENGINE_load_private_key

Здравствуйте.

Использую Рутокен ЭЦП, Linux, OpenSSL 1.1.0.

Подпись на Рутокен работает:

$ openssl dgst -engine rtengine -sign 'pkcs11:id=3135' -keyform engine file > sig

Я хочу получить аналогичный результат в коде на C. Примеры, которые поставляются с  rtengine мне не подходят, так как они используют pkcs11 интерфейс и требуют линковки с вашей библиотекой pkcs11.
Мне требуется код, который взаимодействует через интерфейс OpenSSL.

Пытаюсь запустить тест по аналогии с

https://stackoverflow.com/questions/406 … ng-openssl

#include <stdio.h>
#include <openssl/engine.h>

typedef struct pw_cb_data {
    const void *password;
    const char *prompt_info;
}PW_CB_DATA;

int main()
{
    int r;

    ENGINE *e;
    EVP_PKEY * key;

    PW_CB_DATA cb;
    cb.password = "12345678";
    cb.prompt_info = "pkcs11:id=3135";

    ENGINE_load_builtin_engines();
    ENGINE_load_dynamic();

    e = ENGINE_by_id("rtengine");
    if (!e){
        printf("Can't find engine: %s\n", ERR_reason_error_string(ERR_get_error()));
        return -1;
    }
    if (!ENGINE_init(e)){
        printf("Engine initialization failed!\n");
        ENGINE_free(e);
        return -1;
    }
    if (ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
        printf("Engine %s(%s): Activated.\n", ENGINE_get_name(e), ENGINE_get_id(e));
    } else {
        printf("Engine %s(%s): Initialized but not usable.\n",
                ENGINE_get_name(e), ENGINE_get_id(e));
        return -1;
    }
    OpenSSL_add_all_algorithms();


    key = ENGINE_load_private_key(e, "pkcs11:id=3135", UI_OpenSSL(), &cb);
    printf("key = %x\n", key);

    return 0;
}


$ ./test
Engine Rutoken engine(rtengine): Activated.
Segmentation fault
$

Код падает на ENGINE_load_private_key()
ltrace:

ENGINE_load_builtin_engines(1, 0x7ffc0d5d1578, 0x7ffc0d5d1588, 0) = 1
OPENSSL_init_crypto(1024, 0, 0x7ffc0d5d13f4, 0)              = 1
ENGINE_by_id(0x56398512bd60, 0xffffffff, 0x7ffc0d5d13f4, 0)  = 0x563986e58560
ENGINE_init(0x563986e58560, 0, 0x563986e46050, 0)            = 1
ENGINE_set_default(0x563986e58560, 0xffff, 0x563986e46050, 0) = 1
ENGINE_get_id(0x563986e58560, 0, 0x563986e46050, 0)          = 0x7f05af205d93
ENGINE_get_name(0x563986e58560, 0, 0x563986e46050, 0)        = 0x7f05af205d9c
printf("Engine %s(%s): Activated.\n", "Rutoken engine", "rtengine") = 44
OPENSSL_init_crypto(12, 0, 0x7f05afbd4760, 0x7fffffe1)       = 1
UI_OpenSSL(0x7f05b0069314, 129, 0x7fffffff, 0x7f05af426760)  = 0x7f05b0065f80
ENGINE_load_private_key(0x563986e58560, 0x56398512bd51, 0x7f05b0065f80, 0x7ffc0d5d1460 <no return ...>
--- SIGSEGV (Segmentation fault) ---
+++ killed by SIGSEGV +++

Re: rtengine и ENGINE_load_private_key

[ 3224.865515] test[2954]: segfault at 28 ip 00007fee5468c098 sp 00007ffd7d083d40 error 4 in librtengine.so[7fee54683000+30000]

Re: rtengine и ENGINE_load_private_key

Чвсть ltrace openssl dgst -engine rtengine -sign 'pkcs11:id=3135' -keyform engine file > sig

BIO_s_file(0, 2046, 7, 1)                        = 0x7f3edc426c60
BIO_new(0x7f3edc426c60, 2046, 7, 1)              = 0x561b9ebe8200
BIO_f_md(0x561b9ebe8200, 0, 0x561b9ebe8280, 0)   = 0x7f3edc429380
BIO_new(0x7f3edc429380, 0, 0x561b9ebe8280, 0)    = 0x561b9ebe82c0
BIO_new_fp(0x7f3edbb9b600, 0, 0, 0)              = 0x561b9ebe83c0
ENGINE_init(0x561b9ebdd6d0, 8, 0, 0)             = 1
ENGINE_load_private_key(0x561b9ebdd6d0, 0x7ffe9c79d572, 0x561b9ebe7a10, 0x7ffe9c79c070 <unfinished ...>
UI_OpenSSL(0x561b9ebe8640, 0x561b9ebe86c0, 0, 0) = 0x7f3edc44ef80
UI_method_get_opener(0x7f3edc44ef80, 0x561b9ebe86c0, 0, 0) = 0x7f3edc186650
UI_get_input_flags(0x561b9ebe86c0, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 2
UI_get0_user_data(0x561b9ebe8640, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 0x7ffe9c79c070
UI_get_string_type(0x561b9ebe86c0, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 1
UI_get0_user_data(0x561b9ebe8640, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 0x7ffe9c79c070
UI_OpenSSL(0x561b9ebe8640, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 0x7f3edc44ef80
UI_method_get_writer(0x7f3edc44ef80, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 0x7f3edc186070
UI_get_input_flags(0x561b9ebe86c0, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 2
UI_get0_user_data(0x561b9ebe8640, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 0x7ffe9c79c070
UI_get_string_type(0x561b9ebe86c0, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 1
UI_get0_user_data(0x561b9ebe8640, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 0x7ffe9c79c070
UI_OpenSSL(0x561b9ebe8640, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 0x7f3edc44ef80
UI_method_get_reader(0x7f3edc44ef80, 0x561b9ebe86c0, 0, 0x7f3edb8e15ca) = 0x7f3edc1864b0
UI_OpenSSL(0x561b9ebe8640, 0, 0, 0)              = 0x7f3edc44ef80
UI_method_get_closer(0x7f3edc44ef80, 0, 0, 0)    = 0x7f3edc186020
<... ENGINE_load_private_key resumed> )          = 0x561b9eca68d0
ENGINE_finish(0x561b9ebdd6d0, 0xffffffff, 0x7ffe9c79bf1c, 0x561b9ebe85c0) = 1
BIO_free(0, 0, 0x561b9ebd3530, 0)                = 0
BIO_ctrl(0x561b9ebe82c0, 120, 0, 0x7ffe9c79c158) = 1
EVP_DigestSignInit(0x561b9ebe8380, 0x7ffe9c79c160, 0, 0) = 1
BIO_push(0x561b9ebe82c0, 0x561b9ebe8200, 0x101010101010101, 0) = 0x561b9ebe82c0
BIO_ctrl(0x561b9ebe82c0, 120, 0, 0x7ffe9c79c160) = 1
EVP_MD_CTX_md(0x561b9ebe8380, 1, 0, 0x7ffe9c79c160) = 0x561b9ec96af0
BIO_ctrl(0x561b9ebe8200, 108, 3, 0x7ffe9c79d591) = 1
BIO_read(0x561b9ebe82c0, 0x561b9ebe9700, 8192, 0) = 26
BIO_read(0x561b9ebe82c0, 0x561b9ebe9700, 8192, 0) = 0
BIO_ctrl(0x561b9ebe82c0, 120, 0, 0x7ffe9c79c030) = 1
EVP_DigestSignFinal(0x561b9ebe8380, 0x561b9ebe9700, 0x7ffe9c79c028, 0x7ffe9c79c030) = 1

Re: rtengine и ENGINE_load_private_key

Добрый день, RV.

Примеры из SDK по работе с engine (в частности, sdk\openssl\rtengine\samples\SignCMS) показывают как работать с нашим токеном с интерфейсом OpenSSL. Смотрите в них.

Не уловил, чем Вас смущает линковка. Engine все равно пойдет к токену через pkcs11 и его никак не обойти.

Re: rtengine и ENGINE_load_private_key

Здравствуйте, Владимир.

В примерах из SDK ключ считывается функцией get_key_pair(), которая обращается к getHardwareKeyPair(), которая в свою очередь работает с токеном через pkcs11.

Линковка не устраивает так как требуется опциональное присутствие в системе библиотеки librtpkcs11ecp и rtengine, как и поддержка Рутокен вообще. Также не хотелось бы усложнять код dlopen и pkcs11 протоколом.
Работа через интерфейс OpenSSL была бы решением.

Кстати говоря, возник юридический вопрос. На каких условиях могут распространяться эти библиотеки в стороннем софте?

Что касается ENGINE_load_private_key(), судя по ltrace openssl, вообще она работает. Подозреваю что неправильно подготовил UI_OpenSSL.

Re: rtengine и ENGINE_load_private_key

Нашел в чем проблема.
Не хватало этих двух строчек
    ENGINE_ctrl_cmd_string(e, "dynamic_path", "/usr/lib/x86_64-linux-gnu/engines-1.1/librtengine.so", 0);
    ENGINE_ctrl_cmd_string(e, "MODULE_PATH", "/usr/lib/librtpkcs11ecp.so", 0);

При том, что они были в openssl.cnf:
dynamic_path=/usr/lib/x86_64-linux-gnu/engines-1.1/librtengine.so
MODULE_PATH=/usr/lib/librtpkcs11ecp.so

И еще вопрос появился. Можно ли как-то rtengine передать pin?
Пробовал по разному, все равно спрашивает.

#include <stdio.h>
#include <openssl/engine.h>

typedef struct pw_cb_data {
    const void *password;
    const char *prompt_info;
}PW_CB_DATA;

int main()
{
    int r;
    ENGINE *e;
    EVP_PKEY * key;

    PW_CB_DATA cb;
    cb.password = "12345678";
    cb.prompt_info = "pkcs11:id=3135";

    ENGINE_load_builtin_engines();
    ENGINE_load_dynamic();

    e = ENGINE_by_id("rtengine");
    if (!e){
        printf("Can't find engine: %s\n", ERR_reason_error_string(ERR_get_error()));
        return -1;
    }
    ENGINE_ctrl_cmd_string(e, "dynamic_path", "/usr/lib/x86_64-linux-gnu/engines-1.1/librtengine.so", 0);
    ENGINE_ctrl_cmd_string(e, "MODULE_PATH", "/usr/lib/librtpkcs11ecp.so", 0);
    ENGINE_ctrl_cmd_string(e, "PIN", "12345678", 0);

    if (!ENGINE_init(e)){
        printf("Engine initialization failed!\n");
        ENGINE_free(e);
        return -1;
    }
    if (ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
        printf("Engine %s(%s): Activated.\n", ENGINE_get_name(e), ENGINE_get_id(e));
    } else {
        printf("Engine %s(%s): Initialized but not usable.\n",
                ENGINE_get_name(e), ENGINE_get_id(e));
        return -1;
    }

    key = ENGINE_load_private_key(e, "pkcs11:id=3135", UI_OpenSSL(), &cb);

    printf("key = %x\n", key);

    return 0;
}

Re: rtengine и ENGINE_load_private_key

Добрый день, RV.

Никаких проблем с юридической точки зрения с распространением наших библиотек. Главное их не модифицировать, а распространять как есть. В идеале конечно, чтобы пользователь ставил сам последнюю версию библиотеки, благо они всегда доступны на нашем сайте.

"При том, что они были в openssl.cnf " - тут помочь ничем не могу. Это поведение openssl.

Можно ли как-то rtengine передать pin? - уточню у разработчиков.

Re: rtengine и ENGINE_load_private_key

Добрый день, RV.

По PIN-коду уточнил у разработчиков. Раньше такая возможность была, но сейчас PIN можно передать только через PKCS#11. Причина - engine не умеет корректно работать с PIN-кодами в многопоточном режиме.