Сокет SSL между .Net и Java с аутентификацией клиента - PullRequest
4 голосов
/ 15 марта 2012

Я пытаюсь создать сокет-сервер / клиент SSL между .NET и Java.В этом случае мой сервер SSL Socket Server будет работать в .net, а клиент работает на Java под Linux.Моя проблема заключается в том, что во время установления соединения происходит сбой соединения, в частности, когда сервер запрашивает сертификат у клиента, клиент не может отправить что-либо обратно, и соединение не устанавливается.

В .net Я использую sslStream для установкисоединение и на Java я использую стандартный SSLSocket.Ниже приведены некоторые фрагменты кода, но это то, что у меня пока есть:

На стороне сервера (Windows) у меня есть личный сертификат в папках Personal / Certificates в MMC.У меня есть открытый сертификат от клиента в доверенных лиц / сертификаты.Оба сертификата были выданы одним и тем же центром сертификации.Цепочка сертификатов для обоих сертификатов имеет несколько уровней, но она одинакова для обоих.Сертификат корневого уровня в цепочке также установлен в папке доверенных центров сертификации / сертификатов.

На стороне клиента (Linux) у меня есть хранилище ключей, которое содержит частный сертификат, соответствующий общедоступному сертификату, установленному насервер.У меня есть хранилище доверенных сертификатов, которое содержит общедоступный сертификат сервера, совпадающий с частным сертификатом сервера.

На стороне сервера (.net) я использую сокет, который выполняет асинхронное чтение, а затем помещается вSSLStream, фрагмент кода выглядит следующим образом:

NetworkStream ns = new NetworkStream(socket, false);
SslStream ssl = new SslStream(ns, true);
ssl.AuthenticateAsServer(serverCertificate, true, SslProtocols.Default, true);

Код клиента в значительной степени стандартный код:

SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
InetAddress addr = InetAddress.getByName(servername);
SSLSocket socket = (SSLSocket) factory.createSocket(addr,port);
socket.setUseClientMode(true);
socket.setNeedClientAuth(true);
socket.setWantClientAuth(true);
socket.startHandshake();
os = new DataOutputStream(socket.getOutputStream());
is = new DataInputStream(socket.getInputStream());
byte[] outBuf = new byte[50];
os.write("SEND SOMETHING".getBytes("UTF-8"));
is.read(outBuf);

В Java я установил правильные varialbes, чтобы указывать на довериеи хранилище ключей с их паролем.

Теперь, после стандартного SSL Handshake, вот что происходит:

  • ClientHello
  • ServerHello
  • Serverотправляет открытый сертификат
  • Клиент сопоставляет открытый сертификат с сертификатом, хранящимся в доверенном хранилище
  • Сервер отправляет запрос сертификата
  • При запросе сертификата сервер отправляет список действительных центров сертификации., в этом списке отправляется только мой корневой ЦС (среди длинных списков других известных ЦС.).
  • Сертификат клиента равен нулю.
  • Сервер получает нулевое значениеЯ получу сертификат от клиента, тем самым закрою соединение.

И все, клиент не отправит действительный сертификат обратно на сервер.У меня есть несколько вопросов по этому поводу:

Кто-нибудь испытывал что-то подобное?Что касается списка CA, отправленного сервером (Windows), как .net определяет, что отправить клиенту?Есть ли способ изменить этот список?Нужно ли отправлять все полномочия в цепочке, которые использовались для подписи моего сертификата в этом списке центров сертификации?или Root достаточно?

Я что-то упустил по обе стороны моего кода?

Любая помощь будет принята с благодарностью.В

1 Ответ

1 голос
/ 16 марта 2012

Следующие два утверждения бесполезны на стороне клиента (хотя они не должны причинять вреда):

socket.setNeedClientAuth(true);
socket.setWantClientAuth(true);

Тот факт, что вы видите сообщение запроса сертификата и сообщение сертификата клиента, показывает, что сервер настроен правильно.

Наиболее вероятная причина отсутствия сертификата в сообщении сертификата клиента состоит в том, что хранилище ключей (на стороне клиента) может быть неправильно настроено. Вас может заинтересовать этот ответ , чтобы убедиться, что ваше хранилище ключей клиента настроено правильно. В частности, вам необходимо убедиться, что закрытый ключ для вашего клиентского сертификата был импортирован с тем же псевдонимом, что и цепочка сертификатов (и что эта цепочка возвращается к ЦС, объявленному в сообщении запроса сертификата).

(Что касается остальной части вашего вопроса, я не уверен, как изменить список CA, отправленный сервером при использовании SslStream в C #. Этот более ранний вопрос , похоже, предполагает, что нет Решение, хотя в более новых версиях .Net могут быть решены проблемы, так как этот вопрос был задан. Я не смог найти ничего, что могло бы сделать это, просмотрев документацию SslStream API и связанные с ней классы, но это не значит, его не существует.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...