Согласование SSL со старыми клиентами с использованием SSLEngine (JSSE)

Это дополнительный вопрос к "SSL-подтверждение с использованием самостоятельных Подписанные сертификаты и SSLEngine (JSSE)".

Я реализовал веб-сервер NIO, который может обрабатывать сообщения SSL и не-SSL на одном и том же порту. Чтобы различать сообщения SSL и не-SSL, я проверяю первый байт входящего запроса, чтобы убедиться, что это сообщение SSL/TLS. Пример:

byte a = read(buf);
if (totalBytesRead==1 && (a>19 && a<25)){
    parseTLS(buf);
}

В методе parseTLS() я создаю экземпляр SSLEngine, инициирую рукопожатие, обертываю/разворачиваю сообщения и т. д. Кажется, что все работает нормально для большинства современных веб-браузеров (Firefox 10, IE 9, Safari 5 и т. д.).

Проблема в том, что более старые веб-браузеры, такие как IE 6, и библиотеки, такие как класс Java URLConnection, похоже, по-разному инициируют рукопожатие SSL/TLS. Например, первые несколько байтов из IE 6 выглядят примерно так (шестнадцатеричные значения):

80 4F 01 03 00 ...

Если я передам сообщение SSLEngine, он, похоже, не распознает сообщение и выдаст исключение.

javax.net.ssl.SSLException: Unsupported record version Unknown-0.0

Итак, что именно пересылает класс IE 6 и Java URLConnection? Является ли это действительным сообщением SSL/TLS, которое может поддерживать JSSE SSLEngine? Должен ли я выполнять предварительную обработку или договариваться с клиентом, чтобы отправить другое сообщение?

Заранее спасибо!

ОБНОВЛЕНИЕ

Благодаря Bruno и EJP, а также дальнейшей отладке, я лучше понимаю, что происходит. Как правильно заметил Бруно, клиенты IE6 и Java 6 отправляют через SSLv2 ClientHello. Вопреки одному из моих предыдущих комментариев, SSLEngine в Java 1.6 фактически может развернуть сообщение SSLv2 и сгенерировать допустимый ответ для отправки обратно клиенту. SSLException, о котором я сообщал ранее, был ошибкой на моей стороне и не имеет ничего общего с SSLEngine (я неправильно предположил, что клиент завершил отправку данных, и в итоге я получил пустой ByteBuffer, когда SSLEngine ожидал больше данных для развертывания).


person Peter    schedule 17.04.2012    source источник


Ответы (1)


Это выглядит как клиент SSLv2 Hello (см. спецификацию TLS):

Клиенты TLS 1.1, поддерживающие серверы SSL версии 2.0, ДОЛЖНЫ отправлять приветственные сообщения клиента SSL версии 2.0 [SSL2]. Серверы TLS ДОЛЖНЫ принимать любой формат клиентского приветствия, если они хотят поддерживать клиентов SSL 2.0 на одном и том же порту подключения. Единственными отклонениями от спецификации версии 2.0 являются возможность указать версию со значением три и поддержка большего количества типов шифрования в CipherSpec.

Начиная с Java 7, по умолчанию это отключено< /а>.

ИЗМЕНИТЬ:

Просто чтобы уточнить, на самом деле это не приветствие клиента SSLv2, это приветствие клиента для SSLv3 в формате SSLv2. В этом случае сервер ответит (правильным) приветствием сервера SSLv3 (соответствующим 03 00 запрошенному номеру версии). То же самое работает и для TLS 1.0, 1.1 и 1.2, хотя использование этого формата постепенно устаревает.

JSSE 7 SSLServerSocket по-прежнему будет понимать такое приветствие клиента и соответствующим образом отвечать приветствием сервера SSLv3/TLS1.x.

person Bruno    schedule 17.04.2012
comment
Спасибо. Согласно [docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/ справочное руководство) SSLEngine компании SUN не поддерживает SSLv2. Итак, что я должен отправить обратно клиенту? Просто закрыть соединение? - person Peter; 18.04.2012
comment
Это не так, но он поддерживает более высокие версии SSL/TLS, инициированные этим SSLv2 ClientHello (при условии, что поддерживаемая версия, которую он указывает, является SSLv3 или TLS 1.x): он ответит SSLv3 ServerHello на это сообщение, начинающееся с 80 4F 01 03 00. - person Bruno; 18.04.2012
comment
Извините, я слишком рано нажал клавишу ввода. Итак, вы говорите, что я должен ответить на SSLv2 ClientHello сообщением SSLv3 ServerHello? - person Peter; 18.04.2012
comment
Да, в зависимости от поддерживаемой версии (здесь 03 00 -> SSLv3, 03 01 -> TLSv1.0, 03 02 -> TLSv1.1, ...). - person Bruno; 18.04.2012
comment
Какой API вы предлагаете использовать для генерации ответа? Метод распаковки в SSLEngine мне не помог. - person Peter; 18.04.2012
comment
Я не уверен, unwrap работает для меня с JSSE 7: следующая обертка создает TLSv1 ServerHello, как и ожидалось. Возможно, попробуйте передать ему все сообщение ClientHello за один проход. В вашем примере это будет 0x4F + 2 байта (конечно, это зависит от значения msg_length). - person Bruno; 18.04.2012
comment
@Peter Как и в других наших беседах, вам нужно вызывать только wrap () и unwrap (), как того требует движок, и выполнять чтение и запись, когда он говорит вам. Он понимает сообщение SSLv2Hello: все, что вам нужно сделать, это распознать его как начало сеанса связи SSL. - person user207421; 18.04.2012