Когда-то я прочитал статью kyprizel «Как и зачем мы делаем TLS в Яндексе», где упоминалось о том, что OpenSSL начиная с версии 1.0.2 позволяет назначать сертификат сервера в зависимости от параметров клиента, но реализации на стороне Web-сервера нет. В Nginx 1.11.0 появилась такая возможность:
директивы ssl_certificate и ssl_certificate_key теперь можно указывать несколько раз для загрузки сертификатов разных типов (например, RSA и ECDSA).
Я решил собрать стенд с целью протестировать возможность организации https web-сервера c сертификатами ГОСТ для посетителей с установленным крипопровайдером ГОСТ-шифрования и сертификатами ECDSA для остальных.
В качестве тестового стенда выступила VM с Ubuntu 16.04.1 LTS
Собираем nginx
Я собирал nginx со статической библиотекой OpenSSL 1.0.2h
cd /opt/src/
#Скачиваем nginx
wget http://nginx.org/download/nginx-1.11.2.tar.gz
#Скачиваем openssl
wget https://openssl.org/source/openssl-1.0.2h.tar.gz
#Распаковываем
tar -zxvf nginx-1.11.2.tar.gz
tar -zxvf openssl-1.0.2h.tar.gz
cd nginx-1.11.2
#И собираем
./configure --prefix=/opt/work/nginx2 --user=nginx --group=nginx --with-http_ssl_module --with-openssl=/opt/src/openssl-1.0.2h/
make
make install
Далее необходимо сконфигурировать OpenSSL для поддержки алгоритмов ГОСТ. В сети даже ленивый сможет найти материалы по настройке.
cat /opt/src/openssl-1.0.2h/.openssl/ssl/openssl.cnf
openssl_conf=openssl_def
HOME = .
RANDFILE = $ENV::HOME/.rnd
oid_section = new_oids
[ new_oids ]
tsa_policy1 = 1.2.3.4.1
tsa_policy2 = 1.2.3.4.5.6
tsa_policy3 = 1.2.3.4.5.7
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = ./demoCA
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/cacert.pem
serial = $dir/serial
crlnumber = $dir/crlnumber
crl = $dir/crl.pem
private_key = $dir/private/cakey.pem
RANDFILE = $dir/private/.rand
x509_extensions = usr_cert
name_opt = ca_default
cert_opt = ca_default
default_days = 365
default_crl_days= 30
default_md = default
preserve = no
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 2048
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
req_extensions = v3_req
x509_extensions = v3_ca
string_mask = utf8only
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = RU
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Moscow region
localityName = Locality Name (eg, city)
localityName_default = Moscow
0.organizationName = Organization Name (eg, company)
0.organizationName_default = JSC Example
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = It Department
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
unstructuredName = An optional company name
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = test.example.ru
DNS.2 = gost.example.ru
[ usr_cert ]
basicConstraints=CA:FALSE
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = CA:true
[ crl_ext ]
authorityKeyIdentifier=keyid:always
[ proxy_cert_ext ]
basicConstraints=CA:FALSE
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
[ tsa ]
default_tsa = tsa_config1
[ tsa_config1 ]
dir = ./demoCA
serial = $dir/tsaserial
crypto_device = builtin
signer_cert = $dir/tsacert.pem
certs = $dir/cacert.pem
signer_key = $dir/private/tsakey.pem
default_policy = tsa_policy1
other_policies = tsa_policy2, tsa_policy3
digests = md5, sha1
accuracy = secs:1, millisecs:500, microsecs:100
clock_precision_digits = 0
ordering = yes
tsa_name = yes
ess_cert_id_chain = no
[openssl_def]
engines = engine_section
[engine_section]
gost = gost_section
[gost_section]
engine_id = gost
default_algorithms = ALL
CRYPT_PARAMS = id-Gost28147-89-CryptoPro-A-ParamSet
Выпускаем сертификаты для тестового web-ресурса. Я не стал отягощать себя самоподписанными сертификатами, а создал запросы и подписал их в Тестовом УЦ КриптоПРО и у Китайских «друзей», уже давно выдающих бесплатные сертификаты.
#Формируем закрытый ключ
openssl genrsa -out test.example.ru.key 2048
#генерируем запрос
openssl req -new -sha256 -key test.example.ru.key -out test.example.ru.csr
#генерирум закрытый ключ по алгоритму ГОСТ
openssl genpkey -algorithm gost2001 -pkeyopt paramset:A -out gost.example.ru.key
#генерируем запрос
openssl req -engine gost -new -key gost.example.ru.key -out gost.example.ru.csr
Выгружаем полученные запросы и подписываем в УЦ.
Конфигурирование Nginx
Ниже приведен мой конфигурационный файл Web-сервера Nginx. Следует обратить внимание на дублирующиеся директивы ssl_certificate и ssl_certificate_key, в которых задаются 2 сертификата для одного https сервера, а также на строку ssl_ciphers GOST2001-GOST89-GOST89:HIGH:MEDIUM , где определяется список и порядок применяемых алгоритмов шифрования.
user nginx;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 443 ssl;
server_name gost.example.ru;
ssl_certificate keys/gost.example.ru_bundle.crt;
ssl_certificate_key keys/gost.example.ru.key;
ssl_certificate keys/test.example.ru_bundle.crt;
ssl_certificate_key keys/test.example.ru.key;
ssl_ciphers GOST2001-GOST89-GOST89:HIGH:MEDIUM;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://192.168.1.249;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
На просторах паутины я нашел init script для более удобного запуска:
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="Nginx Daemon"
NAME=nginx
PREFIX=/opt/work/nginx2
DAEMON=$PREFIX/sbin/$NAME
CONF=$PREFIX/conf/$NAME.conf
PID=$PREFIX/logs/$NAME.pid
SCRIPT=/etc/init.d/$NAME
if [ ! -x "$DAEMON" ] || [ ! -f "$CONF" ]; then
echo -e "\033[33m $DAEMON has no permission to run. \033[0m"
echo -e "\033[33m Or $CONF doesn't exist. \033[0m"
sleep 1
exit 1
fi
do_start() {
if [ -f $PID ]; then
echo -e "\033[33m $PID already exists. \033[0m"
echo -e "\033[33m $DESC is already running or crashed. \033[0m"
echo -e "\033[32m $DESC Reopening $CONF ... \033[0m"
$DAEMON -s reopen -c $CONF
sleep 1
echo -e "\033[36m $DESC reopened. \033[0m"
else
echo -e "\033[32m $DESC Starting $CONF ... \033[0m"
$DAEMON -c $CONF
sleep 1
echo -e "\033[36m $DESC started. \033[0m"
fi
}
do_stop() {
if [ ! -f $PID ]; then
echo -e "\033[33m $PID doesn't exist. \033[0m"
echo -e "\033[33m $DESC isn't running. \033[0m"
else
echo -e "\033[32m $DESC Stopping $CONF ... \033[0m"
$DAEMON -s stop -c $CONF
sleep 1
echo -e "\033[36m $DESC stopped. \033[0m"
fi
}
do_reload() {
if [ ! -f $PID ]; then
echo -e "\033[33m $PID doesn't exist. \033[0m"
echo -e "\033[33m $DESC isn't running. \033[0m"
echo -e "\033[32m $DESC Starting $CONF ... \033[0m"
$DAEMON -c $CONF
sleep 1
echo -e "\033[36m $DESC started. \033[0m"
else
echo -e "\033[32m $DESC Reloading $CONF ... \033[0m"
$DAEMON -s reload -c $CONF
sleep 1
echo -e "\033[36m $DESC reloaded. \033[0m"
fi
}
do_quit() {
if [ ! -f $PID ]; then
echo -e "\033[33m $PID doesn't exist. \033[0m"
echo -e "\033[33m $DESC isn't running. \033[0m"
else
echo -e "\033[32m $DESC Quitting $CONF ... \033[0m"
$DAEMON -s quit -c $CONF
sleep 1
echo -e "\033[36m $DESC quitted. \033[0m"
fi
}
do_test() {
echo -e "\033[32m $DESC Testing $CONF ... \033[0m"
$DAEMON -t -c $CONF
}
do_info() {
$DAEMON -V
}
case "$1" in
start)
do_start
;;
stop)
do_stop
;;
reload)
do_reload
;;
restart)
do_stop
do_start
;;
quit)
do_quit
;;
test)
do_test
;;
info)
do_info
;;
*)
echo "Usage: $SCRIPT {start|stop|reload|restart|quit|test|info}"
exit 2
;;
esac
exit 0
Все, запускаем веб-сервер и проверяем. В браузере Internet Explorer 11 c установленным криптопровайдером КриптоПро CSP посетителю отдается ГОСТ сертификат, подписанный CRYPTO-PRO Test Center 2 при обращении к gost.example.ru, в Mozilla Firefox нет поддержки алгоритмов ГОСТ и посетитель получает «обычный» сертификат, подписанный WoSign CA Limited.
Internet Explorer
Mozilla Firefox
С моей точки зрения получился достаточно интересный вариант использования технологии, хочется надеяться, что скоро появится поддержка в openresty ssl_certificate_by_lua_block.
Комментарии (35)
mrdoger
27.07.2016 17:57Использовать криптосредства можно, но в с соответствии указом президента России от 5 мая 2004 г. № 580 необходимо согласовать с ФСБ
sumanai
28.07.2016 06:51Так и не понял, по каким алгоритмам Nginx выбирает, какой из сертификатов подходит, и где прописан ssl_ciphers для нормального сертификата.
mrdoger
28.07.2016 09:20+1Постараюсь пояснить:
В строке директиве ssl_ciphers с лева на право перечисляются допустимые алгоритмы шифрования. В данном случае самым приоритетным (левым) указан алгоритм GOST2001-GOST89-GOST89, далее указаны алгоритмы HIGH — это ключевое слово указывает алгоритмы с длиной ключа более 128 бит, и MEDIUM — алгоритмы с длиной ключа 128 бит. Получается, что сначала NGINX предложит построить https соединение по ГОСТ, если отказались то RSA-like.Envek
28.07.2016 09:57Ещё: при SSL-хэндшейке браузер отправляет серверу список алгоритмов шифрования, которые он поддерживает и браузер с сервером выбирают алгоритм, из пересечения этих списков. Тут в дело вступает директива
ssl_prefer_server_ciphers on;
, которая и заставляет выбирать GOST2001-GOST89-GOST89, если браузер его поддерживает, поскольку в директивеssl_ciphers
он стоит первым, т.е. имеет наивысший приоритет. Если браузер его не поддерживает, то выбирается первый алгоритм из спискаHIGH
, который поддерживает браузер.
sumanai
28.07.2016 10:04mrdoger, Envek, благодарю, как я и предполагал. Просто забыл про ключевое слово HIGH, привык к простыням генератора Mozilla, и поэтому показалось, что ssl_ciphers слишком короткий для работы на RSA-like сертификатах ))
Envek
28.07.2016 10:17Кстати, а что про ваш сервер говорит SSL Test? Не падает ли случаем, какую оценку выдаёт, проверьте :-) https://www.ssllabs.com/ssltest/
mrdoger
28.07.2016 11:29С тестовым стендом все в порядке, а вот ssllabs не смог закончить тестирование на 98% Assessment failed: Unsupported key algorithm: ECGOST3410
mexobrlabs
28.07.2016 14:11>Далее необходимо сконфигурировать OpenSSL для поддержки алгоритмов ГОСТ
правильно я понял, что вы использовали «чистый» OpenSSL, без отечественных модулей типа «КриптоПро CSP для nginx »?
mrdoger
28.07.2016 14:13Да. Но использование таких модулей возможно. Я уже протестировал работу с крипто про engine
ALexhha
28.07.2016 15:12А openssl из коробки, который в ubuntu 16.04 — openssl-1.0.2g-1ubuntu4.1, чем то не устроил? Чем вызвана необходимость сборки из исходников?
mrdoger
28.07.2016 16:01Да ничем, просто привычка свежие версии по на тестовом стенде всегда собирать из исходников. В статье я хотел осветить новые возможности появившиеся в связке nginx 1.11.0+openssl 1.0.2g, и я надеюсь, что статью не будут использовать как пошаговое руководство при пром. внедрении.
Envek
28.07.2016 20:21Если настроить системный OpenSSL на использование ГОСТовых алгоритмов, то глюки и странные сообщения об ошибках могут полезть из всех углов системы (я такое видел, хотя ничего страшного и не случилось), так что лучше системный OpenSSL не трогать.
ALexhha
29.07.2016 12:13Если настроить системный OpenSSL на использование ГОСТовых алгоритмов
как это настроить системный openssl на использование ГОСТовых алгоритмов? Я всегда думал, что алгоритмы, и поведение в целом, вы задаете в конкретной программе, которая использует openssl библиотеку. Например, postfix/nginx/apache/ssh и т.п. Т.е. вам никто не мешает в nginx отсавить возможность использовать sslv3, а в postfix запретить, конечно при условии что сама поддержка есть в openssl
Разве у openssl есть какой то глобальный конфигурационный файл, который влияет на работу всех программ, его использующих?
Prototik
Не холивара ради, а образования для:
Гостовские сертификаты, кроме как на винде под IE, ещё где-нибудь поддерживаются?
VasiliyIsaichkin
К примеру если поставить плагин КриптоПро ЭЦП Browser plug-in
Prototik
Хм, а есть открытый (пускай и сторонний) плагин? Как-то немного нелогично в погоне за безопасностью ставить такие вот плагины…
sumanai
А кто утверждал, что гостовские сертификаты ставят для безопасности?
Тут скорее требования властей и силовых служб.
VasiliyIsaichkin
Думаю маловероятно. ГОСТ ставят не для прикола, тут вся штука в слове 'сертификация', а на открытом откуда она появится? Кому не надо — тем и не надо :) используйте RSA-like и не парьте голову
mrdoger
Не задумываясь могу сказать, что браузеры использующие библиотеки openssl должны поддерживать ГОСТ сертификаты. А так же есть такой продукт как КриптоПРО Fox
deemru
А также сборка Chromium с поддержкой ГОСТ
mexobrlabs
>браузеры использующие библиотеки openssl
Опера?
Если нет, можете дать ссылку на такой браузер?
vladadm
Опционально гост уже давно входит в состав openssl, а по-опыту — «вживую» я пользовал гостовское шифрование, вместе с выпиской и подписями сертификатов для организации vpn-тунелей (на том же openvpn — и под win и под фрёй и под прочими центосями :) ) — это обязательное условие при работе/передаче с персональных данных на территории РФ
BigD
А за границей сервер/концентратор с ГОСТ можно ставить?
vladadm
Если этот сервер не будет участвовать в обработке/хранении или передаче персональных данных наших граждан, то никто не запрещает :)
BigD
А если как раз будет при трансграничной передаче?
BigW
Успокойтесь ;) У openssl нет сертификата ФСТЭК и ФСБ, так что хоть формально это и гост, но по бумагам это решение ничуть не лучше обычного https. Т.е. штрафануть вас могут в обоих случаях. Но если гост — ФСБшники могут закрыть глаза. Поможет только модель угроз/нарушителя где будет написано что ПДн общедоступные, например…
По поводу трансграничной передачи:
— делаете перевалочный сервак (если у вас, например, несколько отделений, где будет информация со всех отделений) на территории РФ, и шлите себе спокойно за границу.
BigD
Просто есть какое-то устойчивое мнение, что экспорт ГОСТ криптографии за границу запрещен, поэтому можно спокойно передавать ПДн трансгранично через обычный https (TLS), и этого в силу вышеупомянутого запрета достаточно.
Пытался найти обоснование — не нашел. Так и не понимаю до конца, можно ли передавать ПДн за границу через обычный https, если первичный ввод производится в БД в России, и данные никак не являются общедоступными.
BigW
Мое мнение:
есть 1119 пп и пункт 13г:
г) использование средств защиты информации, прошедших процедуру оценки соответствия
требованиям законодательства Российской Федерации в области обеспечения безопасности информации,
в случае, когда применение таких средств необходимо для нейтрализации актуальных угроз.
Т.е. если у вас актуальна угроза перехвата ПДн при передаче за границу, то вы сами себе злобные буратины и тогда привет сертифицированные СЗИ и СКЗИ в том числе. и повторюсь openssl вас в этом случае не спасет — бумажки нет.
Если угроза не актуальна (нет методики определения ущерба при разглашении, данные не очень критичные — типа ФИО и телефон и т.д. ) то речи о сертифицированных СЗИ не идет. таким образом и ФСБ требовать от вас госта не имеет права…
Может быть есть какие-то запреты за экспорт самой реализации ГОСТ за границу (как например в США во времена диффи и хелмана такое было) но тут я, увы, не подскажу…
Повторюсь, по возможности берите согласие что ПДн общедоступные… и не забудьте согласие на трансграничную передачу 3м лицам… и вы избавите себя от кучи бумажных проблем. Ну а защиту сделайте нормальными средствами и нормально :))) РЖД, ксттаи, так и поступает… ваши данные общедоступные… почему им можно а нам нет?
BigW
Вам могут сделать ата-та когда ФСБ придет вас проверять (если придет) и выяснит, что модель угроз написана некорректно. Но в этом случае у вас будет время на доработку и вы всегда можете поспорить — предъяви, например, некое экспертное заключение о том что эти угрозы признаны не актуальными, где экспертами может быть кто угодно…
Нет, в целом направление деятельности хорошее и правильное… реализация, как всегда, подкачала…