Как подписать сложный XML-документ? - PullRequest
0 голосов
/ 14 февраля 2019

Я новичок в этом мире XML и электронных подписей.Я пытаюсь подписать документ XML с помощью библиотеки xmlseclibs .

Возможно, кто-то сталкивался с этой методологией при подписании гораздо более сложных документов.В моем XML-документе у меня есть эта метка без значения, поэтому именно в этом разделе я должен подписать документ:

<ext:UBLExtension>
  <ext:ExtensionContent/>
</ext:UBLExtension>

, и этим кодом я подписываю сгенерированный документ:

PHP

  function sign()
  {
    // Load the XML to be signed
    $doc = new DOMDocument();

    // Open XML
    if ($doc->load('file.xml'))
    {
      echo "<p><b>3. XML loaded.</b></p><br/>";
      // Create a new Security object
      $objDSig = new XMLSecurityDSig();

      // Use the c14n exclusive canonicalization
      $objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
      // Sign using SHA-256
      $objDSig->addReference(
          $doc,
          XMLSecurityDSig::SHA256,
          array('http://www.w3.org/2000/09/xmldsig#enveloped-signature')
      );

      // Create a new (private) Security key
      $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type'=>'private'));


      if (!$pfx = file_get_contents('keys/private.pem'))
      {
            echo "Error: The private key could not be opened!\n";
            exit;
        }
      else
      {
        /*
        If key has a passphrase, set it using
        $objKey->passphrase = '<passphrase>';
        */
        // Load the private key
        $prueba = $objKey->loadKey('keys/private.pem', TRUE);
        echo "<p><b>4.Private key has been loaded!</b></p><br/>";
        // Sign the XML file
        $objDSig->sign($objKey);

      }


      if (!$pfx = file_get_contents('keys/public.crt'))
      {
            echo "Error: The public key could not be opened!\n";
            exit;
        }
      else
      {
        $objDSig->add509Cert(file_get_contents('keys/public.crt'));
        echo "<p><b>5. Public key has been loaded.</b></p><br/>";
        // Append the signature to the XML
        $objDSig->appendSignature($doc->documentElement);
        // Save the signed XML
        $doc->save('signed.xml');
      }
    }
    else
    {
      echo "XML could not be opened!";
    }
  }

Результат

<?xml version="1.0" encoding="UTF-8"?>
<fe:Invoice xmlns:fe="http://www.dian.gov.co/contratos/facturaelectronica/v1" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:clm54217="urn:un:unece:uncefact:codelist:specification:54217:2001" xmlns:clm66411="urn:un:unece:uncefact:codelist:specification:66411:2001" xmlns:clmIANAMIMEMediaType="urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2" xmlns:sts="http://www.dian.gov.co/contratos/facturaelectronica/v1/Structure" xmlns:udt="urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.dian.gov.co/contratos/facturaelectronica/v1 ../xsd/DIAN_UBL.xsd urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2 ../../ubl2/common/UnqualifiedDataTypeSchemaModule-2.0.xsd urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2 ../../ubl2/common/UBL-QualifiedDatatypes-2.0.xsd">
  <ext:UBLExtensions>
    <ext:UBLExtension>
      <ext:ExtensionContent>
        <sts:DianExtensions>
          <sts:InvoiceControl>
            <sts:InvoiceAuthorization>9000000107023546</sts:InvoiceAuthorization>
            <sts:AuthorizationPeriod>
              <cbc:StartDate>2018-04-20</cbc:StartDate>
              <cbc:EndDate>2026-12-21</cbc:EndDate>
            </sts:AuthorizationPeriod>
            <sts:AuthorizedInvoices>
              <sts:Prefix>PRUE</sts:Prefix>
              <sts:From>980000000</sts:From>
              <sts:To>985000000</sts:To>
            </sts:AuthorizedInvoices>
          </sts:InvoiceControl>
          <sts:InvoiceSource>
            <cbc:IdentificationCode listAgencyID="6" listAgencyName="United Nations Economic Commission for Europe" listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.0">CO</cbc:IdentificationCode>
          </sts:InvoiceSource>
          <sts:SoftwareProvider>
            <sts:ProviderID schemeAgencyID="195" schemeAgencyName="CO, DIAN (Direccion de Impuestos y Aduanas Nacionales)">900411455</sts:ProviderID>
            <sts:SoftwareID schemeAgencyID="195" schemeAgencyName="CO, DIAN (Direccion de Impuestos y Aduanas Nacionales)">3e82b097-fed0-44e0-8fbc-370fa4bbe718</sts:SoftwareID>
          </sts:SoftwareProvider>
          <sts:SoftwareSecurityCode schemeAgencyID="195" schemeAgencyName="CO, DIAN (Direccion de Impuestos y Aduanas Nacionales)">8f86d8751e4cb9c9c6107bc3d95f727796ad5401e55859cab92c8e28d380f2f4e6bbfe66ded0f2c22344d23661c86da7</sts:SoftwareSecurityCode>
        </sts:DianExtensions>
      </ext:ExtensionContent>
    </ext:UBLExtension>
    <ext:UBLExtension>
      <ext:ExtensionContent/>
    </ext:UBLExtension>
  </ext:UBLExtensions>
  <cbc:UBLVersionID>UBL 2.0</cbc:UBLVersionID>
  <cbc:ProfileID>DIAN 1.0</cbc:ProfileID>
  <cbc:ID>PRUE980000007</cbc:ID>
  <cbc:UUID schemeAgencyID="195" schemeAgencyName="CO, DIAN (Direccion de Impuestos y Aduanas Nacionales)">b1f15bbfbd3743c5a43aa60f6e6fe79467719153</cbc:UUID>
  <cbc:IssueDate>2018-07-06</cbc:IssueDate>
  <cbc:IssueTime>08:04:19</cbc:IssueTime>
  <cbc:InvoiceTypeCode listAgencyID="195" listAgencyName="CO, DIAN (Direccion de Impuestos y Aduanas Nacionales)" listSchemeURI="http://www.dian.gov.co/contratos/facturaelectronica/v1/InvoiceType">1</cbc:InvoiceTypeCode>
  <cbc:Note>FACTURA DE PRUEBA</cbc:Note>
  <cbc:DocumentCurrencyCode>COP</cbc:DocumentCurrencyCode>
  <fe:AccountingSupplierParty>
    <cbc:AdditionalAccountID>1</cbc:AdditionalAccountID>
    <fe:Party>
      <cac:PartyIdentification>
        <cbc:ID schemeAgencyID="195" schemeAgencyName="CO, DIAN (Direccion de Impuestos y Aduanas Nacionales)" schemeID="31">900411455</cbc:ID>
      </cac:PartyIdentification>
      <cac:PartyName>
        <cbc:Name>EMPRESA DE PRUEBA</cbc:Name>
      </cac:PartyName>
      <fe:PhysicalLocation>
        <fe:Address>
          <cbc:Department>BOGOTA, DC</cbc:Department>
          <cbc:CitySubdivisionName>BOGOTA, DC</cbc:CitySubdivisionName>
          <cbc:CityName>BOGOTA, DC</cbc:CityName>
          <cac:AddressLine>
            <cbc:Line>DIRECCION DEL CLIENTE</cbc:Line>
          </cac:AddressLine>
          <cac:Country>
            <cbc:IdentificationCode>CO</cbc:IdentificationCode>
          </cac:Country>
        </fe:Address>
      </fe:PhysicalLocation>
      <fe:PartyTaxScheme>
        <cbc:TaxLevelCode>2</cbc:TaxLevelCode>
        <cac:TaxScheme/>
      </fe:PartyTaxScheme>
      <fe:PartyLegalEntity>
        <cbc:RegistrationName>EMPRESA DE PRUEBA</cbc:RegistrationName>
      </fe:PartyLegalEntity>
    </fe:Party>
  </fe:AccountingSupplierParty>
  <fe:AccountingCustomerParty>
    <cbc:AdditionalAccountID>2</cbc:AdditionalAccountID>
    <fe:Party>
      <cac:PartyIdentification>
        <cbc:ID schemeAgencyID="195" schemeAgencyName="CO, DIAN (Direccion de Impuestos y Aduanas Nacionales)" schemeID="31">830507412</cbc:ID>
      </cac:PartyIdentification>
      <fe:PhysicalLocation>
        <fe:Address>
          <cbc:Department>BOGOTA DC</cbc:Department>
          <cbc:CitySubdivisionName>BOGOTA</cbc:CitySubdivisionName>
          <cbc:CityName>CITY</cbc:CityName>
          <cac:AddressLine>
            <cbc:Line>DIRECCION</cbc:Line>
          </cac:AddressLine>
          <cac:Country>
            <cbc:IdentificationCode>CO</cbc:IdentificationCode>
          </cac:Country>
        </fe:Address>
      </fe:PhysicalLocation>
      <fe:PartyTaxScheme>
        <cbc:TaxLevelCode>2</cbc:TaxLevelCode>
        <cac:TaxScheme/>
      </fe:PartyTaxScheme>
      <fe:Person>
        <cbc:FirstName>NOMBRE DE EMPRESA</cbc:FirstName>
        <cbc:FamilyName>APELLIDO</cbc:FamilyName>
        <cbc:MiddleName>NOMBRE</cbc:MiddleName>
      </fe:Person>
    </fe:Party>
  </fe:AccountingCustomerParty>
  <fe:TaxTotal>
    <cbc:TaxAmount currencyID="COP">0.00</cbc:TaxAmount>
    <cbc:TaxEvidenceIndicator>false</cbc:TaxEvidenceIndicator>
    <fe:TaxSubtotal>
      <cbc:TaxableAmount currencyID="COP">0.00</cbc:TaxableAmount>
      <cbc:TaxAmount currencyID="COP">0.00</cbc:TaxAmount>
      <cbc:Percent>19.00</cbc:Percent>
      <cac:TaxCategory>
        <cac:TaxScheme>
          <cbc:ID>01</cbc:ID>
        </cac:TaxScheme>
      </cac:TaxCategory>
    </fe:TaxSubtotal>
  </fe:TaxTotal>
  <fe:LegalMonetaryTotal>
    <cbc:LineExtensionAmount currencyID="COP">0.00</cbc:LineExtensionAmount>
    <cbc:TaxExclusiveAmount currencyID="COP">0.00</cbc:TaxExclusiveAmount>
    <cbc:PayableAmount currencyID="COP">0.00</cbc:PayableAmount>
  </fe:LegalMonetaryTotal>
  <fe:InvoiceLine>
    <cbc:ID>PV00000001</cbc:ID>
    <cbc:InvoicedQuantity>1.00</cbc:InvoicedQuantity>
    <cbc:LineExtensionAmount currencyID="COP">20.00</cbc:LineExtensionAmount>
    <fe:Item>
      <cbc:Description>PRODUCTOS VARIOS</cbc:Description>
    </fe:Item>
    <fe:Price>
      <cbc:PriceAmount currencyID="COP">20.00</cbc:PriceAmount>
    </fe:Price>
  </fe:InvoiceLine>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
    <ds:Reference>
      <ds:Transforms>
        <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
      </ds:Transforms>
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>54iNdi7I+p1PnU0zXuXn89HUdlmkMK3ZoRPHpcaqlOQ=</ds:DigestValue>
    </ds:Reference>
  </ds:SignedInfo>
  <ds:SignatureValue>
    WmZG4QHfKqBsjtoFjP3BNTLoZVV3+Bww/XjH4gXW+6FDm+J/fkGR1wnmt9C3t98nwFlpOAl5gaOyhC0DNHce3MYWobMNc08hcFES9EV13/tqNsXiCrXXwXVzmwY7CDge0wGa9jYVo6CaLj+t9+IbvgNVc6HdRuVeLzojmO+iyBOPTC5w5QWVVdRV4HeBsxYNsIRNIclp34TsljHYy1g7sMjMAm0SMHkduwgXNn96q+GX/v8pjckdxeZwAYKB+yW3US6mr5lzvyWr9e7pQ0LqZBgX3tT9b050rQHBE8t/H4sh665JyBjSafBSV8/NYRgEafhqBvL0SLVwOESvmvg98Q==
  </ds:SignatureValue>
  <ds:KeyInfo>
    <ds:X509Data>
      <ds:X509Certificate>
        MIID0DCCArigAwIBAgIJAKRguh9Kxjd4MA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAkJSMQswCQYDVQQIDAJTUDEMMAoGA1UEBwwDUmlvMQ4wDAYDVQQKDAVGSVJNUzEQMA4GA1UECwwHRkVSTUlOTzEQMA4GA1UEAwwHRkVSTUlOTzEfMB0GCSqGSIb3DQEJARYQZ3VpaGdmQGdtYWlsLmNvbTAeFw0xNzA2MjcxMzU2MTBaFw0yNzA2MjUxMzU2MTBaMH0xCzAJBgNVBAYTAkJSMQswCQYDVQQIDAJTUDEMMAoGA1UEBwwDUmlvMQ4wDAYDVQQKDAVGSVJNUzEQMA4GA1UECwwHRkVSTUlOTzEQMA4GA1UEAwwHRkVSTUlOTzEfMB0GCSqGSIb3DQEJARYQZ3VpaGdmQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMxoXF67vmncyWwoJ3h3MK/foNuP7uvmSv1aiLgLgc0dH1SGQWqM33ocloBtHWs1QFpU7TGVVmyS9bf47fdVxa/75MLV7mSMdWDiK0cIBDwQFAhSu+ipQ3kpTJSmJWiXKd16Xtrxq9XtwdwC25kVMEws7ggZoMHzrmmKPtTUwvbaqy0xXw5IFFt/r9L6dzOQcfwdNhQACLlO7cEGdJQXbwvICn3VN6M5nwTXec6vlalppX3kmjTiVJURKi64hmih84Hf12loDbtyiuxYcc8rK0ceUAxhFtmekwDAcV+EAr7sXUrNDKZErpK6HZ/QDrhZVeXzVuKsHyRmYYn0RUGzNqMCAwEAAaNTMFEwHQYDVR0OBBYEFONdUpNRKv8PN9499PBw0zVD+025MB8GA1UdIwQYMBaAFONdUpNRKv8PN9499PBw0zVD+025MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAK5OwB/iVWDHEtGKkQCmMqXOcsVz7PvYJIaGtSUq1X6CWDGZoEtyCkfoMC/FYPz6V8JgSwDFENyw4VaH0HWggwz2vCDEA5Mg3iOobRG98gk9lLolk7DjXsfvHkCYI6ncvz7eIdawwzddhSaj+2LSUCB8UNONYsl6CPdioNGUVJix9QDSrf5gcMkWsWa8Sg3f6vjVCWdgl5mOnJeeXapxvg1VEjnmOLDb25hNKO44i4jVNKN4+jSKCcECCKw7fu7uD4PyVbTCZi037svPzMZ6dG7wlWLBWOopbj7G2sAMMVwCoHAJBoEV8lArRq4n1ZW3DAW9NQ8+OQcJMXWGWQhSmJk=
      </ds:X509Certificate>
    </ds:X509Data>
  </ds:KeyInfo>
</ds:Signature>
</fe:Invoice>

Как видите, подпись появляется в конце документа, номне нужно сгенерировать подпись внутри вышеупомянутого ярлыка.Кто-нибудь сталкивался с этим неудобством?

1 Ответ

0 голосов
/ 15 февраля 2019

Ваш код говорит:

$objDSig->appendSignature($doc->documentElement);

Кажется довольно очевидным, что это добавит подпись к элементу документа.Если вы хотите добавить его к чему-то другому, я бы предложил вместо этого указать его в качестве аргумента.

Одним из способов сделать это может быть запрос XPath для поиска пустого элемента нужного вам типа.добавить к:

$xpath = new DomXPath($doc);
$nodes = $xpath->query("//ext:ExtensionContent[not(normalize-space())]");
if ($nodes->count()) {
    $objDSig->appendSignature($nodes[0]);
}
...