GOST証明書を使用したユニバーサルhttps

GOST暗号化を使用してさまざまなWebサービスのhttps接続を整理しようとすると、ブラウザーがGOSTアルゴリズムをサポートしていない訪問者に対して常に質問がありました。 https接続をセットアップするとき、システムでサポートされているアルゴリズムに応じてクライアントに証明書を与えることは論理的に思えましたが、最近まで、このアプローチの実用的な実装は見られていませんでした。



kyprizelの記事「YandexでTLSを行う方法と理由」を読んだところ、バージョン1.0.2以降のOpenSSLでは、クライアントパラメーターに応じてサーバー証明書を割り当てることができますが、Webサーバー側には実装されていません。 Nginx 1.11.0はこの機能を導入しました:

ssl_certificateおよびssl_certificate_keyディレクティブを複数回指定して、さまざまなタイプの証明書(RSAやECDSAなど)をダウンロードできるようになりました。



インストールされた暗号プロバイダーGOST暗号化と残りのECDSA証明書を持つ訪問者向けのGOST証明書を使用してhttps Webサーバーを編成する可能性をテストするために、スタンドを組み立てることにしました。



Ubuntu 16.04.1 LTSを搭載したVMがテストベンチとして機能



nginxをビルドする



OpenSSL 1.0.2h静的ライブラリを使用してnginxをコンパイルしました



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
      
      





次に、GOSTアルゴリズムをサポートするようにOpenSSLを構成する必要があります。 ネットワーク上では、怠け者でもチューニング資料を見つけることができます。



私のopenssl.cnf
 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 (eg 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リソースの証明書を発行します。 自己署名証明書に負担をかけることはありませんでしたが、 CryptoProのテストセンターでリクエストを作成し、長い間無料の証明書を発行してきた中国人の「友人 」と署名しました。



 #   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
      
      





受信したリクエストをアップロードし、CAで署名します。



Nginxの構成



以下は私のNginx Webサーバー設定ファイルです。 1つのhttpsサーバーに2つの証明書を指定する重複したssl_certificateおよびssl_certificate_keyディレクティブ 、および使用される暗号化アルゴリズムのリストと順序を決定するssl_ciphersGOST2001-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; } } }
      
      







Webの広大さの中で、より便利に実行できるinitスクリプトを見つけました。



/etc/init.d/nginx
 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
      
      





以上で、Webサーバーを実行して確認します。 暗号化プロバイダーCryptoPro CSPがインストールされたInternet Explorer 11では、gost.example.ruにアクセスする際にCRYPTO-PROテストセンター2によって署名されたGOST証明書が訪問者に与えられます。 。



インターネットエクスプローラー






Mozilla Firefox






私の観点からは、この技術を使用するためのかなり興味深いオプションであることが判明しました。openresty ssl_certificate_by_lua_blockにサポートが間もなく登場することを望みます



All Articles