GOSTに従ってstunnelおよびopensslを使用したGISユーティリティとの相互作用





GISユーティリティとの相互作用を確立するという課題に直面しました。 文書によると、トンネルを暗号化し、GOSTに従ってEDSを形成するために、よく知られている国内のソフトウェアを使用することになっていますが、これは私たちの方法ではありません。 Googleとコンソールで武装し、私とslavamは利用可能なツールで必要な機能を実装しました。

必要なソフトウェアはすべて、LinuxプラットフォームとWindowsプラットフォームの両方で利用できるため、この手法はマルチプラットフォームと呼ばれます。







  1. 準備する
  2. GOSTによる暗号トンネル
  3. XMLDSigの形成
  4. 参照資料




準備する





相互作用は、次の部分で構成されます。



作業には、CentOS 6サーバー、Python 2.7.11、OpenSSL + GOSTエンジン、stunnelが使用されます。 GOSTをサポートするopensslのクイックインストールガイド

怠け者のために:
# wget https://www.openssl.org/source/openssl-1.0.2g.tar.gz # tar -xvf openssl-1.0.2g.tar.gz # cd openssl-1.0.2g/ # yum groupinstall "Development Tools" # yum install zlib zlib-devel # ./config shared zlib enable-rfc3779 # make && make install # echo "/usr/local/ssl/lib/" > /etc/ld.so.conf.d/openssl.conf # ldconfig # /usr/local/ssl/bin/openssl ciphers | tr ":" "\n" | grep -i gost GOST2001-GOST89-GOST89 GOST94-GOST89-GOST89 # cat /usr/local/ssl/openssl.cnf ………… openssl_conf = openssl_def [openssl_def] engines = engine_section [engine_section] gost = gost_section [gost_section] engine_id = gost default_algorithms = ALL …………
      
      







複雑なことは何もないはずで、すべてがすでに何百回も説明されていると思います。 また、最近のディストリビューションでは、 gostモジュールはすぐに使用できます。



OpenSSLは2つの方法で使用されます。stunnelはGSSLに従って構築されるため、GOSTに従って動作します。 また、 openssl



ユーティリティは、署名を生成および検証するためにPythonコードから呼び出されます。 opensslの呼び出しは、使用されている暗号モジュールを設定することがPythonコードから可能でなかったという事実によるものです。 必要なソフトウェアはすべて、LinuxプラットフォームとWindowsプラットフォームの両方で利用できるため、この手法はマルチプラットフォームと呼ばれます。



Pythonの場合、CentOS 6サーバーはlxmlライブラリを更新する必要があります。これを行うには、いくつかの追加パッケージをインストールします。

 # yum install libxml2 libxml2-devel libxslt libxslt-devel python-devel # pip install lxml --upgrade
      
      







PKCS12(.pem)形式の証明書と秘密キーファイルも必要です。 P12FromGostCSPなどのユーティリティを使用して、または手動で eTokenから取得できます。 何らかの理由でこれができない場合は、 「Rutoken EDS」キーを直接操作するオプションです。 このサイトには、OpenSSLとstunnelを教える方法に関する詳細な手順があります。 したがって、タスクは前のタスクに削減されます。 そのような鍵は手元になかったので、確認できませんでした。



GOSTによる暗号トンネル



トンネルは、プロキシモードで動作するStunnelを使用して上がります。 あなたは彼にgostモジュールの使い方を教える必要があります。 ただし、少し時間がかかります。モジュールを正しく初期化するには、ソースをわずかに修正する必要があります。 私が理解しているように、問題はモジュールとメソッドの初期化順序に関連しています。 だから:

 # wget https://www.stunnel.org/downloads/stunnel-5.31.tar.gz # tar -xvf stunnel-5.31.tar.gz # cd stunnel-5.31
      
      





src / options.cファイルを編集し、関数「 NOEXPORT char *engine_init(void)



」の最後にSSL_library_init()呼び出しを追加します

次のようになります。
 NOEXPORT char *engine_init(void) { if(engine_initialized) /* either first or already initialized */ return NULL; /* OK */ s_log(LOG_DEBUG, "Initializing engine #%d (%s)", current_engine+1, ENGINE_get_id(engines[current_engine])); if(!ENGINE_init(engines[current_engine])) { if(ERR_peek_last_error()) /* really an error */ sslerror("ENGINE_init"); else s_log(LOG_ERR, "Engine #%d (%s) not initialized", current_engine+1, ENGINE_get_id(engines[current_engine])); return "Engine initialization failed"; } #if 0 /* it is a bad idea to set the engine as default for all sections */ /* the "engine=auto" or "engineDefault" options should be used instead */ if(!ENGINE_set_default(engines[current_engine], ENGINE_METHOD_ALL)) { sslerror("ENGINE_set_default"); return "Selecting default engine failed"; } #endif s_log(LOG_INFO, "Engine #%d (%s) initialized", current_engine+1, ENGINE_get_id(engines[current_engine])); SSL_library_init(); engine_initialized=1; return NULL; /* OK */ }
      
      







ここで解決策が見つかりました

以前にアセンブルされたOpenSSLの接続でアセンブルします。

 # ./configure --with-ssl=/usr/local/ssl --disable-libwrap # make && make install
      
      







設定ファイル/etc/stunnel.conf

 client=yes #    (). CAFile=/etc/crypto/CA-SIT.pem engine=gost sslVersion=TLSv1 engineDefault = ALL output=/var/log/stunnel.log DEBUG=4 #   eToken-. cert=/etc/crypto/public.pem key=/etc/crypto/private.key [pseudo-https] #    ,    . accept = 10.1.5.133:8080 #    ,    (). connect = 54.76.42.99:60045 ciphers = GOST2001-GOST89-GOST89
      
      





証明書ファイルを/ etc / crypto /ディレクトリに配置します。 一般に、stunnelはどのユーザーでも機能しますが、rootになりましょう。

最も単純なinit.dサービス制御スクリプト:
 #! /bin/bash # # stunnel Start/Stop Stunnel # # chkconfig: 2345 90 60 # description: launches Stunnel # processname: stunnel # config: /etc/stunnel.conf # Source function library. . /etc/init.d/functions # See how we were called. prog="Stunnel CryptoTunnel" RNG=PROGRAM export RNG start() { echo -n $"Starting $prog: " /usr/local/bin/stunnel /etc/stunnel.conf RETVAL=$? [ $RETVAL -eq 0 ] && success [ $RETVAL -ne 0 ] && failure echo return $RETVAL } stop() { echo -n $"Stopping $prog: " /usr/bin/killall /usr/local/bin/stunnel >/dev/null 2>&1 RETVAL=$? [ $RETVAL -eq 0 ] && success [ $RETVAL -ne 0 ] && failure echo return $RETVAL } restart() { stop start } case "$1" in start) start ;; stop) stop ;; restart) restart ;; *) echo $"Usage: $0 {start|stop|status|restart}" exit 1 esac
      
      







たとえば、実行して確認することができます

サーバーアドレスへのリクエスト:
 # curl http://10.1.5.133:8080/ext-bus-nsi-service/services/Nsi?wsdl <?xml version='1.0' encoding='UTF-8'?><wsdl:definitions xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/nsi-service/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:nsi-common="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/nsi-common/" xmlns:nsi="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/nsi/" xmlns:ns="http://www.w3.org/2000/09/xmldsig#" xmlns:base="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/" targetNamespace="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/nsi-service/"> <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/nsi-service/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:nsi-common="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/nsi-common/" xmlns:nsi="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/nsi/" xmlns:ns="http://www.w3.org/2000/09/xmldsig#" xmlns:base="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/"> <xs:import namespace="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/" schemaLocation="http://54.76.42.99:60046//ext-bus-nsi-service/services/Nsi?xsd=hcs-basetypes-8.7.0.7.xsd"/> <xs:import namespace="http://dom.gosuslugi.ru/schema/integration/8.7.0.7/nsi/" schemaLocation="http://54.76.42.99:60046//ext-bus-nsi-service/services/Nsi?xsd=hcs-nsi-types-8.7.0.7.xsd"/> </xs:schema> ………
      
      







出力が完全に異なる場合は、ログファイル/var/log/stunnel.logを注意深く調べます。



XMLDSigの形成



GISハウジングおよび共同サービスサーバーへのトンネルが構成されて機能している場合、そこにあらゆる種類のリクエストを送信し、必要な回答を得ることができます。 要求はXMLDSigの形式で送信されます。XMLDSigには、要求自体、この要求のハッシュ、証明書ハッシュ、証明書自体、証明書ハッシュを含む要求ハッシュの署名、およびすべてを記述するフィールドの束が含まれます。 最も難しかったのは、チェーン全体を解き、XMLを取得することでした。これは、GISユーティリティによって正常にテストされます。 すべての署名済みブロックは標準形式で取得され、受信した署名とハッシュ量はBASE64でエンコードされます。



XMLDSig生成アルゴリズムは、便利なプログラミング言語を使用して実装できます。 python 2.7.11を使用しました。デモコードが添付されています。 例として、コンソールのアナログも提供します。



0.証明書から、発行者に関するシリアル番号と情報が取得され、必要なIDが生成され、現在の時間が記憶されます。

1.任意の石鹸クライアント(Pythonの泡など)を使用して、GISユーティリティサーバーに対してSOAP要求が生成されます。

SOAPリクエストの例:
 <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:ns0="http://dom.gosuslugi.ru/schema/integration/8.7.0.3/nsi/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header> <RequestHeader xmlns="http://dom.gosuslugi.ru/schema/integration/8.7.0.4/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Date>2016-04-11T14:28:28</Date> <MessageGUID>29f93de1-25b6-21e5-24ae-2c6f65dfe2b2</MessageGUID> <SenderID>4eb0a7d6-6317-45cf-8974-10e75cbb0cbc</SenderID> </RequestHeader> </SOAP-ENV:Header> <ns1:Body> <ns0:exportDataProviderNsiItemRequest Id="signed-element"> <ns0:RegistryNumber>51</ns0:RegistryNumber></ns0:exportDataProviderNsiItemRequest> </ns1:Body> </SOAP-ENV:Envelope>
      
      





ここで、 SenderID



は、要求が行われた管理会社の識別子です。 MessageGUID



は、必要に応じて生成される一意のIDです。 本体<ns1:Body>



は、追加フィールドを持つリクエスト自体です。 Id="signed-element"



-要求ID。要求に応じて指定し、要求に署名するときに焦点を合わせます。





2. <ns1:Body>



タグの内容(より正確には、IDがあり、最初と最後の改行文字がない部分)が取得され、C14Nアルゴリズムによって正規化され(排他= True)、ハッシュ合計がGOSTに従って計算され、BASE64の形式で表示されます。 digest1



digest1



。 コンソールアナログ:

 # cat in.xml ; echo <ns0:exportDataProviderNsiItemRequest Id="signed-element"> <ns0:RegistryNumber>51</ns0:RegistryNumber></ns0:exportDataProviderNsiItemRequest> # cat in.xml | openssl dgst -engine gost -md_gost94 -binary | base64
      
      





* GOSTサポート付きのopenssl。 エンジンは明示的に指定されますが、openssl.cnfをセットアップすることにより、これを停止できます。



3. x509の証明書が取得され、BASE64からデコードされ、そこからハッシュ量が考慮され、出力がBASE64でエンコードされます。 digest2



digest2







4.取得したデータを使用して、 <xades:SignedProperties>



タグのコンテンツが<xades:SignedProperties>



(テンプレートを参照)、C14Nアルゴリズムによって正規化され(排他= False)、 digest3



(BASE64)がコンテンツと見なされます。



5. <ds:SignedInfo>



ブロックが<ds:SignedInfo>



れ、C14Nアルゴリズムによって正規化され(排他的= False)、BASE64で署名およびエンコードされます。 <ds:SignatureValue>



ブロックの値が判明します。 コンソールアナログ:

 cat SignedInfo.xml | openssl dgst -sign private.key -engine gost -md_gost94 -binary | base64
      
      





ここで、SignedInfo.xmlはすでに最後の改行なしの正規化されたブロックです。



6.得られたすべての値は

XAdES-BES形式のXMLドキュメントテンプレート:
 <ds:Signature Id="xmldsig-{signature_id}" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"/> <ds:Reference Id="xmldsig-{signature_id}-ref0" URI="#{signed_id}"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/> <ds:DigestValue>{digest1}</ds:DigestValue> </ds:Reference> <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#xmldsig-{signature_id}-signedprops"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/> <ds:DigestValue>{digest3}</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue Id="xmldsig-{signature_id}-sigvalue"> {signature_value} </ds:SignatureValue> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:X509Data> <ds:X509Certificate> {x590_cert} </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> <ds:Object><xades:QualifyingProperties Target="#xmldsig-{signature_id}" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#"><xades:SignedProperties Id="xmldsig-{signature_id}-signedprops"><xades:SignedSignatureProperties><xades:SigningTime>{signing_time}</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/><ds:DigestValue>{digest2}</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>{x509_issuer_name}</ds:X509IssuerName><ds:X509SerialNumber>{x509_sn}</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate></xades:SignedSignatureProperties></xades:SignedProperties></xades:QualifyingProperties></ds:Object> </ds:Signature>
      
      







このテンプレートは、GISユーティリティの使用を推奨する複合体を選択して分析することで作成できました。 それ自体は無料で入手できますが、CryptoPro CSP CIPとTrusted Java 2.0 CIPIが必要です。



7.このようにして作成された署名を検証するには、すべての操作を逆の順序で実行する必要があります。 コンソール署名検証オプション:

 # cat SignedInfo.xml | openssl dgst -engine gost -md_gost94 -verify <(openssl x509 -engine gost -in public.pem -pubkey -noout) -signature signature.sig
      
      





ここで、signature.sigはBASE64からデコードされた署名であり、SignedInfo.xmlはチェック済みブロック<ds:SignedInfo>...</ds:SignedInfo>



です。 ハッシュ値は単純に比較されます。



Pythonのデモコードは、ここから (独自の危険とリスクで)使用できます 。 コードの作成者はVyacheslav(@ slavam、RO)です。 同様のアルゴリズムは、追加のツールやコンポーネントを購入することなく、便利な言語を使用して実装できます。 コードからOpenSSLユーティリティを呼び出すのは面倒ですが、LinuxとWindowsプラットフォームの両方で機能し、CryptoProと追加コンポーネントの使用を排除します。

GISハウジングおよび共同サービスとの対話システムはまだ作成段階ですが、結果のXMLDSigは必要なチェックに合格します。

この記事により、誰かがそのような自転車を簡単に実装できるようになることを願っています。



UPD

GISユーティリティとの相互作用の順序で変更が発生しています。 現在の規則はウェブサイトで見つけることができます。 主な変更:



また、かなりのプログラミング例が登場しました(試してみれば)OpenSSLと友達になれます。



UPD2

GOSTサポートのあるWindowsでOpenSSLを取得するには、次のものが必要です。

1. ここから OpenSSL インストールします。すでにGOSTがサポートされていますgost.lib



フォルダーには、対応するライブラリgost.lib



ます。



2.構成ファイルで、その使用を明示的に示します。

 openssl_conf = openssl_def [openssl_def] engines = engine_section [engine_section] gost = gost_section [gost_section] engine_id = gost dynamic_path = ./gost.dll default_algorithms = ALL
      
      





OpenSSLが構成を読み取る場所を正確に判断するには、環境変数を設定できます。

 set OPENSSL_CONF=C:\OpenSSL-Win32\openssl.cnf
      
      







3.結果を確認します。

 C:\OpenSSL-Win32\bin>openssl.exe ciphers -v | find /I "gost" GOST2001-GOST89-GOST89 SSLv3 Kx=GOST Au=GOST01 Enc=GOST89(256) Mac=GOST89 GOST94-GOST89-GOST89 SSLv3 Kx=GOST Au=GOST94 Enc=GOST89(256) Mac=GOST89
      
      







ご清聴ありがとうございました。



リンク集






All Articles