ГИС ЖКХ — подпись сообщений
Ранее уже описывал как поднять защищенный туннель с ГИС ЖКХ.Теперь настало время научится делать запросы. Для этого их необходимо подписывать. Подписывается тело сообщения XML заключенное внутри тега body:

Сохраню его в файл in.xml. Далее для работы понадобится сертификат в формате x.509, он выгружается в формате BASE64 из Крипто-про

Понадобится он в бинарном виде:
1 |
cat 509.base64 | base64 -d >509.bin |
Далее собираем следующую рыбу:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<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> |
digest1 считается как хеш-сумма по ГОСТу и выводится в виде BASE64 содержимым тега body (см. выше)
1 |
cat in.xml | openssl dgst -engine gost -md_gost94 -binary | base64 >digest1 |
digest2 считается как хэш-сумма бинарного файла сертификата x509 и преобразованное в base64:
cat 509.bin | openssl dgst -engine gost -md_gost94 -binary | base64 >digest2
Далее заполняем блок SignedProperties, а в частности поля x509_issuer_name и x509_sn. Их можно получить соответственно командами:
1 2 |
openssl x509 -in cert.pem -serial -nameopt sep_multiline,utf8 -noout openssl x509 -in cert.pem -issuer -nameopt sep_multiline,utf8 -noout |
Причем x509_issuer_name нужно привести к виду:
cn=Тестовый УЦ ООО \»КРИПТО-ПРО\»,o=ООО \»КРИПТО-ПРО\»,l=Москва,st=г. Москва,c=RU,street=ул. Сущёвский вал д.18,1.2.643.3.131.1.1=001234567890,1.2.643.100.1=1234567890123
Тег emailaddress, заменяется на 1.2.840.113549.1.9.1, inn на 1.2.643.100.4, а ogrn на 13 1.2.643.100.1
Теперь необходимо подписать то, что мы заполнили между тегами SignedInfo. У меня получилось что-то вроде:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<xd:SignedInfo xmlns:base="http://dom.gosuslugi.ru/schema/integration/base/" xmlns:drs="http://dom.gosuslugi.ru/schema/integration/drs/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#"> <xd:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></xd:CanonicalizationMethod> <xd:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"></xd:SignatureMethod> <xd:Reference Id="xmldsig-e99d1872-укепкеп54e8bb16d4-ref0" URI="#f9f93dкепуке6-11e5-b4ae-1c6f65dfe2b1"> <xd:Transforms> <xd:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></xd:Transform> <xd:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></xd:Transform> </xd:Transforms> <xd:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"></xd:DigestMethod> <xd:DigestValue>b\'укепукепукепке/imNA=\'</xd:DigestValue> </xd:Reference> <xd:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#xmldsig-e99d1872-4534-11f0-b35a-e454e8bb16d4-signedprops"> <xd:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"></xd:DigestMethod> <xd:DigestValue>DLYx2a/3ц4кц34к3/XQtrUiKviYQ=</xd:DigestValue> </xd:Reference> </xd:SignedInfo> |
Подпись осуществляется так:
openssl dgst -sign key.key -out to_sign.sig -binary to_sign
Подпись сохранилась в файл to_sign.sig, помещаем содержимое внутри тега SignatureValue и получившийся таким образом файл пробуем отправить в ГИС ЖКХ.
Некоторые заметки:
1) Как вытащить закрытый ключ с флешки с подписью — нужно воспользоваться утилитой P12FromGostCSP. Если вы пользовались чем-то другим, то с большой долей вероятностью получите ошибку:
1 2 3 4 5 6 7 8 9 10 11 12 |
root@vlg1w-bb16d4:/home/укацук@укацук.ru/Desktop/ЖКХ/БоевыеКлючи# openssl pkcs12 -in укацук.p12 -engine gost engine "gost" set. Enter Import Password: Bag Attributes localKeyID: 01 00 00 00 friendlyName: e3йуцвйцуd8c1319fa1d5 Microsoft CSP Name: Crypto-Pro GOST R 34.10-2012 KC1 CSP Error outputting keys and certificates 140097466021056:error:06074079:digital envelope routines:EVP_PBE_CipherInit:unknown pbe algorithm:../crypto/evp/evp_pbe.c:95:TYPE=1.2.840.113549.1.12.1.80 140097466021056:error:23077073:PKCS12 routines:PKCS12_pbe_crypt:pkcs12 algor cipherinit error:../crypto/pkcs12/p12_decr.c:41: 140097466021056:error:2306A075:PKCS12 routines:PKCS12_item_decrypt_d2i:pkcs12 pbe crypt error:../crypto/pkcs12/p12_decr.c:94: |
2) Формировать подпись через КриптоПро — возможно, но ни у кого не получилось. Рабочий вариант только через OpenSSL. Почему — никто не знает.
3) Есть готовая утилита для формирования шапки с подписью написанная на Python 2.7. Я её перевел на Python3, сделав минимальные косметические изменения. В принципе работает. Скачать тут