<?php
$fish_file='in/fish.xml'; // xml - главный шаблон, откуда осуществляем сборку
$xades_file='in/xades_dom.xml'; // xml - шаблон подписи
$cert_file='keys/cert.key'; // Сертификат формата X590
$private_file='keys/priv.key'; // Закрытый ключ
function md_gost($text){
file_put_contents("tmp.xml", $text);
$res=`cat tmp.xml | openssl dgst -binary -md_gost12_256 | base64 -w 0`;
$res= str_replace("\n", "", $res);
return trim($res);
};
function md_gost_bin($text){
file_put_contents("tmp.xml", $text);
$res=`cat tmp.xml | openssl dgst -binary -md_gost12_256>hash.bin`;
return file_get_contents("hash.bin");
};
function get_issuer($cert_file){
$res=`openssl x509 -in $cert_file -issuer -nameopt sep_multiline,utf8 -noout`;
$res= str_replace("issuer=\n", "", $res);
$res= str_replace("emailaddress", "1.2.840.113549.1.9.1", $res);
$res= str_replace("inn", "1.2.643.100.4", $res);
$res= str_replace("ogrn", "1.2.643.100.1", $res);
$res= str_replace('"', "\\", $res);
$res= str_replace(',', "\,", $res);
$res= explode("\n", $res);
$result="";
for ($index = count($res)-1; $index > 0; $index--) {
if (trim($res[$index])!=""){
$prop= explode("=",$res[$index]);
$result=$result.strtolower(trim($prop[0]))."=".trim($prop[1]);
if ($index>1){
$result=$result.",";
};
};
};
return trim($result);
}
function get_serial($cert_file){
$res=`openssl x509 -in $cert_file -serial -nameopt sep_multiline,utf8 -noout`;
$res= str_replace("serial=", "", $res);
$res= str_replace("\n", "", $res);
return base_convert(trim($res),16,10);
}
function get_signature($text, $private_file){
file_put_contents("for_sign.xml", $text);
$res=`cat for_sign.xml | openssl dgst -md_gost12_256 -sign $private_file -binary | base64 -w 0`;
$res= str_replace("\n", "", $res);
return trim($res);
}
function X509($cert_file){
$crt= file_get_contents($cert_file);
$crt= str_replace("-----BEGIN CERTIFICATE-----", "", $crt);
$crt= str_replace("-----END CERTIFICATE-----", "", $crt);
$crt= str_replace("\n", "", $crt);
$crt= str_replace("\r", "", $crt);
return trim($crt);
}
function guidv4($data = null) {
$data = $data ?? random_bytes(16);
assert(strlen($data) == 16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40);
$data[8] = chr(ord($data[8]) & 0x3f | 0x80);
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
$dt=new DateTime();
$signing_time=$dt->format(DateTime::ATOM);
$signature_id=guidv4(); // идентификатор блока "подпись"
$signed_id=guidv4(); // идентификатор блока который подписываем
$fish_xml=file_get_contents($fish_file);
$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadXML($fish_xml);
$root = $dom->documentElement;
$req_xml=$root->getElementsByTagName('exportDSRsRequest')->item(0);
$req_xml->setAttribute('Id',$signed_id);
$req_can=$req_xml->C14N(true);
$digest1=md_gost($req_can);
echo "req=$req_can\n";
echo "digest1=$digest1\n";
$digest2= md_gost(base64_decode(X509($cert_file)));
echo "digest2=$digest2\n";
$dom = new DOMDocument('1.0', 'utf-8');
$tmp_text_xml=$root->C14N(true);
// подмешиваем подпись
$xades= file_get_contents($xades_file);
$tmp_text_xml= str_replace('base:version="15.3.0.0">', 'base:version="15.3.0.0">'.$xades, $tmp_text_xml);
$tmp_text_xml= str_replace("{signing_time}", $signing_time, $tmp_text_xml);
$tmp_text_xml= str_replace("{signature_id}", $signature_id, $tmp_text_xml);
$tmp_text_xml= str_replace("{digest1}", $digest1, $tmp_text_xml);
$tmp_text_xml= str_replace("{digest2}", $digest2, $tmp_text_xml);
$tmp_text_xml= str_replace("{x509_issuer_name}", get_issuer($cert_file), $tmp_text_xml);
$tmp_text_xml= str_replace("{x509_sn}", get_serial($cert_file), $tmp_text_xml);
$dom->loadXML($tmp_text_xml);
$root = $dom->documentElement;
$digest3=md_gost($root->getElementsByTagName('SignedProperties')->item(0)->C14N(true));
echo "digest3=$digest3\n";
$dom = new DOMDocument('1.0', 'utf-8');
$tmp_text_xml=$root->C14N(true);
$tmp_text_xml= str_replace("{digest3}", $digest3, $tmp_text_xml);
$tmp_text_xml= str_replace("{x590_cert}", X509($cert_file), $tmp_text_xml);
$tmp_text_xml= str_replace("{signed_id}", $signed_id, $tmp_text_xml);
$dom->loadXML($tmp_text_xml);
$root = $dom->documentElement;
// подписываем
$for_sign=$root->getElementsByTagName('SignedInfo')->item(0)->C14N(true);
$hash_for_sign= md_gost_bin($for_sign);
$sign=get_signature($hash_for_sign,$private_file);
echo "sign=$sign\n";
$dom = new DOMDocument('1.0', 'utf-8');
$tmp_text_xml=$root->C14N(true);
$tmp_text_xml= str_replace("{signature_value}", $sign, $tmp_text_xml);
$dom->loadXML($tmp_text_xml);
$root = $dom->documentElement;
//
echo "---------------- ИТОГО ---------------\n";
file_put_contents("out.xml", $root->C14N(true));