Вопрос по c++, openssl, thrift, ssl – SSL-сертификат, не аутентифицирующийся через комиссионные, но с помощью браузера

8

Вот как я генерирую свой сертификат SSL, ключ и т. Д.

openssl genrsa -out server.key 1024
openssl rsa -in server.key -out new_key.pem
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 10000 -in server.csr -signkey new_key.pem -out server.crt

Это работает, я вижу вывод в chrome, хотя я получаю предупреждение, что сначала собираюсь получить вирусы.

openssl s_server -cert server.crt -www -key new_key.pem

это фрагмент с сервера. Я буду честен, я не уверен точно, что делает каждая строка, хотя у меня есть хорошая идея:

socketFactory->server(true); // this is the server
socketFactory->authenticate(false); // no auth?
socketFactory->loadCertificate("server.crt"); 
socketFactory->loadPrivateKey("new_key.pem");

клиент:

socketFactory->loadTrustedCertificates("server.crt");
socketFactory->authenticate(true); //auth? wierd, right? This guy does this:[1]

[1] http://permalink.gmane.org/gmane.comp.lib.thrift.user/1651

Если я закомментируюloadTrustedCertificates в клиенте, тогда я получаю исключение неподтвержденного сертификата SSL. С той строкой, оставленной в, я получаю исключение ошибки аутентификации.

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

shared_ptr<SkullduggeryHandler> handler(new SkullduggeryHandler());
shared_ptr<TBufferedTransportFactory> transportFactory =
        shared_ptr<TBufferedTransportFactory>(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
shared_ptr<TProcessor> processor(new SkullduggeryProcessor(handler));
shared_ptr<TSSLSocketFactory> socketFactory = 
      shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
socketFactory->server(true);
socketFactory->authenticate(false);
socketFactory->loadCertificate("server.crt");
socketFactory->loadPrivateKey("new_key.pem");
shared_ptr<TSSLServerSocket> socket(new TSSLServerSocket(port, socketFactory));
TThreadedServer server(processor,
                               socket,
                               transportFactory,
                               protocolFactory);
server.serve();

клиент:

shared_ptr <TSSLSocketFactory> socketFactory = shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
socketFactory->loadTrustedCertificates("server.crt");
socketFactory->authenticate(false);
shared_ptr <TSSLSocket>socket = socketFactory->createSocket(configuration.ip, configuration.port);
shared_ptr<TBufferedTransport> transport(new TBufferedTransport(socket));
shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
SkullduggeryClient client(protocol);
transport->open();

Спасибо, что нашли время, чтобы прочитать это. Если будут явные ошибки, я буду рад услышать об этом. Это было проклятием моего существования слишком долго. Слишком долго.

Ваш Ответ

1   ответ
11

вы генерируете самозаверяющие сертификаты (что нормально), но операции, которые вы выполняете сopenssl утилиты сбивают с толку.

Строка 1 в порядке, она генерирует закрытый ключ.
Строка 2 бесполезна: клавиша вывода такая же, как клавиша ввода! (Пробоватьdiff две клавиши, чтобы увидеть).
Строка 3 генерирует CSR, а строка 4 фактически самоподписывает его, поэтому их можно объединить в одну строку, как мы увидим.

Теперь давайте сделаем шаг назад и попытаемся понять, что мы делаем :-)

Вы используете SSL для аутентификации и шифрования связи между сервером Thrift и клиентом Thrift. Я полагаю, вы хотите оба:

Protect the client from a rogue server (what your code is attempting to do) Protect the server from a rogue client (which seems even more important to me).

Чтобы провести аналогию HTTPS, (1) является классическим сертификатом сервера, (2) обычно является именем пользователя / паролем для пользователя. Но с Thrift SSL мы получим взаимную аутентификацию, выдав сертификат также клиенту.

В примерах, которые я приведу, будут использоваться самозаверяющие сертификаты. Их легко можно адаптировать к мини-CA, управляемому openssl, и я оставляю это как упражнение для читателя.

Сгенерируйте закрытый ключ сервера:
openssl genrsa -out server-key.pem 2048

Создайте связанный открытый ключ и подпишите его:
openssl req -new -x509 -key server-key.pem -out server-cert.pem -days 10000

Сгенерируйте закрытый ключ клиента:
openssl genrsa -out client-key.pem 2048

Создайте связанный открытый ключ и подпишите его:
openssl req -new -x509 -key client-key.pem -out client-cert.pem -days 10000

Примечание: когдаopenssl req просит"Common Name (e.g. server FQDN or YOUR name)"введите полное доменное имя хоста, на котором будет работать программа Thrift. Это позволит не настраивать Thrift'ыAccessManager учебный класс. Если, с другой стороны, полное доменное имя не может быть известно заранее, необходимо наследоватьAccessManager и переопределитьverify() методы соответственно. УвидетьTSSLSocket.cpp.

Хорошо, теперь к коду.

На стороне сервера:

socketFactory->server(true); избыточно, удалите его.

socketFactory->authenticate(false) немного вводит в заблуждение. Лучшее имя было быauthenticatePeer, Если вы говоритеfalse, он не будет аутентифицировать клиента, но мы решили, прежде чем мы хотим взаимную аутентификацию.

Итак, преамбула SSL для сервера:

try {
    signal(SIGPIPE, SIG_IGN); // See README.SSL
    shared_ptr<TSSLSocketFactory> sslSocketFactory(new TSSLSocketFactory());
    sslSocketFactory->loadPrivateKey(myKey);
    sslSocketFactory->loadCertificate(myCert);
    sslSocketFactory->authenticate(true);
    sslSocketFactory->loadTrustedCertificates(trustedCerts);
    sslSocketFactory->ciphers("HIGH:!DSS:[email protected]");
    ...
    } catch (TException& tx) {
        ....
    }

кудаmyKey являетсяserver-key.pem, myCert являетсяserver-cert.pem а такжеtrustedCerts это ... либо сертификат доверенного центра сертификации, либо, в случае самозаверяющего сертификата, сертификат клиента. Вы можетеcat несколько сертификатов один за другим в одном файле. В нашем примере мы поместимclient-cert.pem что мы создали раньше.

Преамбула SSL для клиента точно такая же, с правильным личным ключом клиента, сертификатом клиента и, дляtrustedCertsСертификат сверстника:server-cert.pem что мы создали раньше.

Вот и все :-) Прежде чем переходить к кодированию, постарайтесь понять, если у вас нет четкого представления о том, как работает (взаимная) аутентификация SSL, трудно понять сообщения об ошибках. Код, который я показал, протестирован для работы.

По документации, к сожалению, Thrift близок к нулю. Для SSL вы можете увидеть:lib/cpp/README.SSL, test/cpp/src/TestServer.cpp а такжеtest/cpp/src/TestClient.cpp, Будьте предупреждены, чтоTestServer.cpp не выполняет взаимную аутентификацию, что является ошибкой IMHO.

Похожие вопросы