Некоторые малоизвестные возможности и особенности
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 |