ГИС ЖКХ — подпись сообщений

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

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

Понадобится он в бинарном виде:

cat 509.base64 | base64 -d >509.bin

Далее собираем следующую рыбу:

<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 (см. выше)

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. Их можно получить соответственно командами:

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. У меня получилось что-то вроде:

<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. Если вы пользовались чем-то другим, то с большой долей вероятностью получите ошибку:

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, сделав минимальные косметические изменения. В принципе работает. Скачать тут

Update 16.06.2025: на текущий момент не удалось достичь успешной отправки запроса в ГИС ЖКХ. Ошибка:

  "ErrorCode": "AUT011005",
  "Description": "Ошибка формата подписи запроса"

Подпись не подходит ни крипто-про:

/opt/cprocsp/bin/amd64/csptest -keyset -cont 'HDIMAGE\\e32681d3.000\A3EB' -sign 'GOST12_256' -keytype exchange -in for_sign.xml -out for_sign.xml.sgn |cat for_sign.xml.sgn| base64 -w 0

Ни OpenSSL:

cat for_sign.xml | openssl dgst -md_gost12_256 -sign priv.key -binary | base64 -w 0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.