Персональный
сайт
Игоря
Сысоева


 
english
обо мне
 
sysoev.ru
 
nginx
 
mod_accel
mod_realip
mod_deflate
программирование
всякая всячина
windows
freebsd
apache
pppd
unix
web
 
 

Некоторые малоизвестные возможности и особенности OpenSSL

 

25.12.2007

К сожалению, достаточно широко используемая библиотека OpenSSL плохо документирована, особенно учитывая её объёмы. Часть пробелов восполнено в книге "Network Security with OpenSSL" и в статье "An Introduction to OpenSSL Programming" в Linux Journal (часть 1 и часть 2). Но всё равно какие-то вещи остаются малоизвестными. На этой странице я решил описать некоторые возможности и особенности, с которыми мне пришлось столкнуться.

  • В OpenSSL часто используются callback-функции, однако возникает вопрос — как в такую функцию передать данные, специфичные для приложения, поскольку никаких opaque параметров в callback'ах не предусмотрено. Тем не менее, это всё же возможно — с помощью функций SSL_get_ex_new_index(), SSL_set_ex_data() и SSL_get_ex_data() можно связать произвольные (opaque) данные с SSL соединением.

  • Старые версии MSIE 5.0 и 5.01 с экспортными ограничениями на криптографию не могут работать с RSA-ключами больше 512 бит и поэтому не могут установить соединение с серверами, использующими 1024-битные сертификаты (а таковые сейчас все). Специально для них можно создать 512-битный ключ функцией RSA_generate_key(512, RSA_F4, NULL, NULL) и установить его с помощью SSL_CTX_set_tmp_rsa() или SSL_set_tmp_rsa() соответственно в SSL_CTX или SSL. Созданный ключ можно сразу же освободить функцией RSA_free(), поскольку в SSL_CTX или SSL хранится его копия. До создания ключа можно с помощью функций SSL_CTX_need_tmp_RSA() или SSL_need_tmp_RSA() проверить, а нужно ли вообще этот ключ создавать.

  • В OpenSSL одна операция может породить несколько ошибок, которые записываются в очередь, причём очередь эта глобальная, а не локальная для одного соединения SSL. Поэтому, если ошибки обрабатывать так:

    ERR_error_string_n(ERR_get_error(), buf, len);
    

    то из очереди будет удалена только одна ошибка, а другие возможно оставшиеся в очереди ошибки, приведут к ошибочному результату операции с другим соединением SSL. Поэтому при возникновении ошибки нужно полностью чистить очередь примерно таким циклом:

    for ( ;; ) {
        n = ERR_get_error();
    
        if (n == 0) {
            break;
        }
    
        *buf++ = ' ';
    
        ERR_error_string_n(n, buf, len);
    
        buf += len;
    }
    

    Забавно, что эту ошибку допустил не только я, но и разработчики lighttpd и cherokee — похоже, это общее место.

  • До версии OpenSSL 0.9.8m функция SSL_shutdown() в случае ошибки всегда возвращала 0, несмотря на то, что в man'е написано, что должно быть -1.

  • Для проверки клиентских сертификатов не достаточно загрузить CA сертификаты с помощью SSL_CTX_load_verify_locations(), нужно ещё и сформировать список их subject'ов, которые будут передаваться клиенту. Делается это с помощью функций SSL_load_client_CA_file() и SSL_CTX_set_client_CA_list() или SSL_set_client_CA_list(). Без этого клиент просто не будет знать, какой из имеющихся у него сертификатов нужно передавать серверу.

    Необходимо заметить, что в OpenSSL до версий 0.9.7h and 0.9.8 функция SSL_load_client_CA_file() после успешного завершения оставляет в очереди ошибку, поэтому её нужно очистить с помощью ERR_clear_error().

(C) Игорь Сысоев
http://sysoev.ru