DTLS с использованием Schannel

Я пытаюсь создать «соединение» DTLS с помощью Schannel под Windows (я тестирую в последней версии Windows 10, поэтому должны быть доступны все версии DTLS, поддерживаемые Schannel)

Я попытался начать с рабочего кода, чтобы установить обычное соединение TLS, следуя документации:

  1. InitializeSecurityContext с нулевым вводом на первом проходе, SECBUFFER_TOKEN и SECBUFFER_ALERT на выходе
  2. AcceptSecurityContext с SECBUFFER_TOKEN и SECBUFFER_EMPTY на входе, SECBUFFER_TOKEN и SECBUFFER_ALERT на выходе.
  3. Повторяйте два шага до тех пор, пока они не увенчаются успехом, а затем переходите к использованию Encrypt / DecryptMessage.

Это отлично работает в потоковом режиме (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM)

Если я попытаюсь заменить STREAM на ISC / ASC_REQ_DATAGRAM, мой InitializeSecurityContext преуспеет с SEC_I_CONTINUE_NEEDED, как и ожидалось, но мой самый первый AcceptSecurityContext затем выйдет из строя с SEC_E_INVALID_PARAMETER.

Я попытался установить для grbitEnabledProtocols моего SCHANNEL_CRED значение 0, чтобы использовать значения по умолчанию, задокументированные с обеих сторон, я также попытался установить его на SP_PROT_DTLS1_X, и я все еще получаю возврат неверного параметра из моего первого ASC. Еще на всякий случай пробовал константы DTLS_1_0.

Кроме того, все протоколы безопасности по умолчанию включены в настройках моего реестра.

Насколько я понимаю DTLS RFC, мой код не работает на этапе HelloVerifyRequest, и, опять же, исходя из моего понимания RFC, эта часть требует, чтобы провайдер безопасности генерировал cookie из нескольких частей сообщения ClientHello, а также из исходных файлов. Айпи адрес. Однако я не смог найти какой-либо задокументированный способ передать эту информацию функции ASC.

(Думаю? :)) Я безуспешно искал во всем Интернете любой рабочий пример использования DTLS под Schannel. В stackoverflow я нашел этот вопрос, в котором просто упоминается, что он поддерживается: Поддерживается ли DTLS Schannel в Windows 7?, а связанная статья MSDN представляет собой лишь общий обзор.

Я искал любое использование констант, связанных с этой функцией ... Я искал любое использование констант, связанных с этим (ISC_REQ_DATAGRAM, SP_PROT_DTLS *, SECBUFFER_DTLS_MTU, ...), и единственное, что я смог найти на все поисковые системы, о которых я мог думать, были либо копиями sspi.h, либо сайтами, индексирующими константы в Windows API ...

Я знаю, что DTLS хорошо поддерживается другими реализациями (OpenSSL и т. Д.), Но я бы предпочел остаться с Schannel, поскольку другие части моего кода в настоящее время отлично работают с Schannel в режиме TLS.


person fbrosseau    schedule 06.12.2017    source источник


Ответы (2)


От Microsoft: нет документации по внедрению DTLS с использованием Schannel. Известный и постоянный пробел в документации.

Есть несколько отличий, но клиент или сервер TLS можно довольно легко адаптировать к DTLS (ряд клиентов успешно это сделали).

  1. Установите SCHANNEL_CRED.grbitEnabledProtocols на SP_PROT_DTLS1_X.
  2. При вызове AcceptSecurityContext передайте SOCKADDR клиента через SECBUFFER_EXTRA.
  3. MTU можно установить через SetContextAttributes, используя константу SECPKG_ATTR_DTLS_MTU, где буфер является просто указателем на ULONG. [По умолчанию 1096 байт.]
  4. Когда ISC / ASC возвращает SEC_I_MESSAGE_FRAGMENT, отправьте этот фрагмент и снова вызовите ISC / ASC в цикле, чтобы получить следующий фрагмент (без попытки чтения данных из сети).
  5. Реализуйте логику тайм-аута и повторной передачи в своем приложении (поскольку schannel не владеет сокетом).
  6. При получении фрагментов schannel будет пытаться удалить дубликаты, изменить порядок и собрать заново, если это возможно.
  7. SCHANNEL_SHUTDOWN не применяется к DTLS.
person Matthew J. Bobowski    schedule 22.01.2021
comment
Рассматриваете возможность открытия нового вопроса, но, может быть, вы сможете здесь ответить? После того, как я получаю SEC_I_MESSAGE_FRAGMENT от ASC и снова вызываю его для получения следующего фрагмента, я получаю SEC_E_INCOMPLETE_MESSAGE и ничего в буфере выходного токена. (Это происходит при передаче буфера входных токенов нулевой длины - если я повторно передаю исходный вход, я получаю повтор первого фрагмента в качестве выходных.) Есть ли что-то конкретное, что мне нужно сделать, чтобы указать ASC, что он должен дать мне следующий фрагмент? - person Haddon CD.; 07.05.2021
comment
Я так понимаю, вы все еще в процессе переговоров? Если это так, выйдите из цикла и обработайте ошибку из-за недостаточного количества зашифрованных данных, поставьте в очередь и обработайте при следующем возврате. Для этого проверьте SECBUFFER_EXTRA из индекса 1 (второй элемент), возвращенного из ASC. Резервное копирование данных для удаления уже обработанной информации из входного буфера. При повторном получении данных добавьте новые данные в резервную копию данных, изменив размер буфера сохраненных данных, и либо продолжите согласование, либо вызовите DecryptMessage (). - person Matthew J. Bobowski; 21.05.2021
comment
Мэтью, спасибо (и извиняюсь, если я ошибаюсь), но это похоже на то, как обрабатывать SEC_E_INCOMPLETE_MESSAGE. У меня проблемы с обработкой SEC_I_MESSAGE_FRAGMENT, то есть шага 4 вашего ответа выше. На самом деле я задал это как новый вопрос (с более подробной информацией и образцом кода, который воспроизводит проблему), который остается без ответа здесь, если вы хотите взглянуть: stackoverflow.com/q/67463514/1831696 - person Haddon CD.; 14.07.2021
comment
Мой комментарий был для SEC_I_MESSAGE_FRAGMENT. Разница в том, что вы продолжаете цикл, а не выходите из цикла для SEC_E_INCOMPLETE_MESSAGE (потеря значимости данных). - person Matthew J. Bobowski; 15.07.2021
comment
Привет, Мэтью. Для получения более подробной информации см. Мой вопрос, но когда я получаю SEC_I_MESSAGE_FRAGMENT, я продолжаю свой цикл (т.е. отправляю выходной сигнал SECBUFFER_TOKEN, затем снова вызываю ASC, не опрашивая сокет), но я не уверен, что передать ASC в качестве ввода на следующем итерация. Я предполагаю (как и в случае с SEC_E_INCOMPLETE_MESSAGE) я не должен передавать повторяющиеся данные SECBUFFER_TOKEN, если ASC не указывает их как необработанные с выходом SECBUFFER_EXTRA, но если я передаю ввод нулевой длины (либо как SECBUFFER_TOKEN, либо _EMPESSAGE_), вместо этого я просто получаю SECBUFFER_TOKEN или _EMPESSAGE_ следующего фрагмента. Еще раз спасибо! - person Haddon CD.; 27.07.2021

Вы можете использовать https://github.com/mobius-software-ltd/iotbroker.cloud-windows-client В качестве образца для реализации DTLS в Windows. Он использует не SChannel, а библиотеку netty. MQTT-SN и CoAP оба поддерживают DTLS в рамках этого проекта. BR Юлиан Ойфа

person Yulian Oifa    schedule 06.02.2021
comment
Этот вопрос был конкретно о SChannel. Вне SChannel DTLS можно тривиально реализовать с помощью OpenSSL и других. Большинство ваших ответов на stackoverflow кажутся рекламой ваших проектов. - person fbrosseau; 06.02.2021