Проблемы при написании модуля-замены TLS для NGINX (NoiseSocket)

Alexey Ermishkin scratch на virgilsecurity.com
Чт Ноя 23 09:51:49 UTC 2017


Приветствую, меня зовут Алексей. Я работаю в компании VirgilSecurity и
являюсь разработчиком протокола NoiseSocket (noisesocket.com).
Так же наша компания занимается разработкой модуля для NGINX, реализующего
протокол NoiseSocket.
Я хотел бы описать цели, результаты и узнать мнение о решениях и спросить
совета о других путях решения задачи.
Протокол NoiseSocket позиционируется как более простая в реализации и
быстрая альтернатива TLS. Одной  из его главных фич является возможность
установки безопасного соединения без использования сертификатов, используя
лишь "сырые" приватные\публичные ключи. Это необходимо для IoT, бекендов,
p2p и многих других задач.
Основной целью создания модуля для NGINX - это обеспечение функциональности
reverse proxy и load balancing, где соединение между прокси-сервером и
backend серверами осуществляется по протоколу NoiseSocket. Второй целью
является возможность принимать входящие соединения по протоколу NoiseSocket,
то есть обеспечивать поддержку протокола на стороне backend с помощью NGINX.
Для обеспечения нужного функционала модуль должен обеспечить:
1 При создании соединения на стороне noise client инициировать и отработать
handshake phase по алгоритму noise initiator.
2 При входящем соединении на стороне noise server ответить на входящие
handshake сообщения и отработать handshake phase по алгоритму noise .
3 После успешного завершения handshake phase упаковывать/распаковывать
сетевой траффик в NoiseSocket transport messages.
Сначала была рассмотрена возможность создания модуля для контекста http,
однако здесь траффик для сторонних модулей предоставляется в виде
составляющих http, что не дает возможности для работы протокола, имеющего
более низкий уровень, чем http.
Затем был рассмотрен вариант для контекста stream. Однако предоставляемый
функционал для сторонних модулей здесь оказался весьма ограничен. Здесь для
работы протокола уровня представления есть возможность только на стороне
noise server, когда появляется входящее соединение и можно прицепить модуль
к одной из фаз обработки входящего запроса. На стороне noise client такой
возможности нет, потому что здесь имеется функционал только для custom load
balancing. Мы можем добавить свой обработчик:
 ngx_stream_session_t->peer.get(ngx_peer_connection_t *pc,void *data);
Однако его вызов осуществляется до создания соединения:
В файле  ngx_event_connect.c:
ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc)
{
:.
rc = pc->get(pc, pc->data);
:.
c = ngx_get_connection(s, pc->log);
:
}
Таким образом нет никакой возможности инициировать процедуру handshake и
назначить свои обработчики recv, send, recv_chain, send_chain для обработки
траффика средствами стороннего модуля.
В итоге было принято решение создать модуль, реализующий собственный
контекст по обработке траффика. За основу был взят код контекста stream, где
был убран TLS, и добавлен NoiseSocket. 
Для обработки траффика только по протоколу NoiseSocket приемлема следующая
конфигурация, которая наиболее оптимальна по быстродействию:

 https://i.imgur.com/fucb9J0.png

В итоге для сохранения существующего функционала NGINX по обработке http
контента определена следующая конфигурация:

https://i.imgur.com/6vnOdwd.png

или
https://i.imgur.com/WpMhdKh.png

Так как подобная конфигурация не оптимальна в плане быстродействия, то
хотелось бы узнать о более перспективных вариантах внедрения протокола
уровня представления для NGINX в качестве модуля.
Рабочий вариант спецификации для NoiseSocket:
http://noisesocket.com/spec/noisesocket/
 Репозиторий с кодом модуля
https://github.com/VirgilSecurity/virgil-NGINX-noise-socket


Подробная информация о списке рассылки nginx-ru