повысить двустороннюю аутентификацию asio SSL

#c #boost #boost-asio

#c #ssl #повысить #повышение asio #взаимная аутентификация

Вопрос:

Мне нужен фрагмент кода для программы, с которой я пишу Boost Asio SSL . У меня есть система из двух клиентов, которые соединяются друг с другом. Я требую, чтобы они выполнили взаимную аутентификацию, чтобы в конце handshake() команды оба клиента могли быть уверены, что у другого клиента есть закрытый ключ к предоставленному ими сертификату. У обоих клиентов есть context объект, давайте вызовем их ctx1 , ctx2 и у каждого клиента есть открытый сертификат и закрытый ключ.

Можно ли настроить контекстные объекты так, чтобы при вызове socket.handshake() клиенты выполняли двустороннюю аутентификацию. Если нет, то каков был бы правильный путь для достижения моей цели?

Комментарии:

1. Я не думаю, что это проблема, если у другого клиента есть закрытый ключ. Если другой клиент этого не сделал, он все равно не сможет декодировать ваше сообщение. Если оба клиента выполняют аутентификацию X.509, возможно, на общем поставщике аутентификации, они могут просто обмениваться открытыми ключами.

Ответ №1:

Похоже, boost просто использует интерфейс OpenSSL. Я не очень разбираюсь в boost, но я реализовал множество внутренних компонентов OpenSSL для Perl и пришел к следующим выводам после прочтения соответствующих частей исходного кода boost:

Чтобы иметь взаимную аутентификацию с OpenSSL, вы должны использовать SSL_VERIFY_PEER как на стороне клиента, так и SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT на стороне сервера. Если вы используете только SSL_VERIFY_PEER на стороне сервера, он будет отправлять только запрос сертификата клиенту, но молча примет, если клиент не отправит сертификат обратно.

С помощью boost это, вероятно, будет:

 ctx.set_verify_mode(ssl::verify_peer); // client side
ctx.set_verify_mode(ssl::verify_peer|ssl::verify_fail_if_no_peer_cert); // server side
 

Если вы установите verify_mode таким образом, он будет проверять сертификаты на соответствие настроенным доверенным центрам сертификации (заданным с ctx.load_verify_file помощью или ctx.load_verify_path ).

Если у вас есть полный контроль над центром сертификации, который подписал сертификаты (т. Е. Ваш собственный центр сертификации), вам может быть достаточно принять любые сертификаты, подписанные этим центром сертификации. Но если вы используете центр сертификации, который также подписывает сертификаты, которые вы не хотите принимать, как это обычно бывает с общедоступными центрами сертификации, вам также необходимо проверить содержимое сертификата. Подробности о том, как это сделать, зависят от вашего протокола, но для обычных интернет-протоколов, таких как HTTP или SMTP, это включает проверку commonName и / или subjectAltNames сертификата. Такие детали, как обработка подстановочных знаков, различаются в зависимости от протоколов.

Boost предоставляет rfc2818_verification, чтобы помочь вам с проверкой в стиле HTTP, хотя, прочитав код, я думаю, что реализация немного неправильная (принимаются несколько подстановочных знаков, разрешены подстановочные знаки IDN — см. Требования RFC6125).

Я не знаю никаких стандартов для проверки клиентских сертификатов. Часто принимается только любой сертификат, подписанный конкретным (частным) центром сертификации. В других случаях сертификаты от общедоступного центра сертификации соответствуют определенному шаблону электронной почты. Похоже, boost вам не очень поможет в этом случае, поэтому вам, вероятно, придется получить SSL* дескриптор OpenSSL sock.native_handle() , а затем использовать функции OpenSSL для извлечения certificate ( SSL_get_peer_certificate ) и проверки содержимого сертификата (различные X509_* функции).

По крайней мере, если задействованы общедоступные центры сертификации, вы также должны проверить статус отзыва сертификатов. Похоже, boost не предоставляет прямого интерфейса с CRL (список отзыва сертификатов), поэтому вам необходимо использовать ctx.native_handle() с соответствующими функциями OpenSSL ( X509_STORE_add_crl и т.д.). Использование OCSP (online status revocation protocol) намного сложнее, а соответствующие функции OpenSSL в основном недокументированы, что означает, что для их использования вам нужно прочитать исходный код OpenSSL: (

Комментарии:

1. Итак, если я вызову verify_peer на обоих концах, клиент1 может быть уверен, что у client2 есть закрытый ключ к предоставленному им сертификату, и наоборот?

2. Вы можете быть уверены, что у обоих есть ключ к сертификату, который они предоставляют. Но вам также необходимо verify_fail_if_no_peer_cert на стороне сервера для сбоя, если клиент не предоставил сертификат.

Ответ №2:

Нельзя заставить другую сторону аутентифицироваться против вас, это зависит от протокола, т.Е. Каждая сторона аутентифицируется только против другой стороны. Просто следуйте инструкциям, как http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/ssl.html

 ssl::context ctx(ssl::context::sslv23);
ctx.set_verify_mode(ssl::verify_peer);
ctx.load_verify_file("ca.pem");
 

Комментарии:

1. Вам необходимо verify_peer|verify_fail_if_no_peer_cert обеспечить взаимную аутентификацию. При этом только verify_peer сервер будет запрашивать сертификат у клиента, но продолжит работу без ошибок, если сертификат не был предоставлен. На стороне клиента verify_peer достаточно.

2. @Steffen сделайте свой комментарий ответом

3. Я специально попросил использовать идентифицирующие имена, такие как client1.crt или client2.pem или что-то в этом роде, потому что документация Asio-s достаточно запутанна, но пока это лучший ответ, спасибо