"Neispravan digitalni potpis."

Mar 13, 2013 at 7:36 PM
Pozdrav svima.

Malo sam već izludio, pa rekoh ajde da probam ovaj put ne nabijat glavom o zid nego da potražim koji par svježih očiju.

Kraći opis problema:
Pokušavam poslati zahtjev za poslovni prostor i odgovor koji stiže je greška s004, neispravan digitalni potpis. Zanima me što sve podrazumijeva ta pogreška? Odnosi li se ona i na nepropisnu kanonizaciju?
Pokušao sam kanonizirati svoj xml s xmlstarletom (link) ali kako mi je postupak kanonizacije i dalje jako nejasan (posebeno što se tiče namespaceova, link) prilično sam siguran kako moj xml dokument uopće nije dobro kanoniziran.

Duži opis istog:
Kako koristim CryptoAPI i MASM32 navikao sam stvari raditi "ručno." Logički zaključujem da jednom kanonizirani xml ostaje kanoniziran dokle god se pridržavaš valjanog rasporeda formata, samo ga koristiš kao prazan template.
Tako sam u memoriji pripremio ovo:
 <tns:PoslovniProstorZahtjev xmlns:tns="http://www.apis-it.hr/fin/2012/types/f73" Id="PoslovniProstorZahtjev"><tns:Zaglavlje><tns:IdPoruke>47802E89-F7DA-4293-8957-EADDE50EFFBA</tns:IdPoruke><tns:DatumVrijeme>13.03.2013T18:43:40</tns:DatumVrijeme></tns:Zaglavlje><tns:PoslovniProstor><tns:Oib>12345678901</tns:Oib><tns:OznPoslProstora>TERA</tns:OznPoslProstora><tns:AdresniPodatak><tns:Adresa><tns:Ulica>Laginjina</tns:Ulica><tns:KucniBroj>44</tns:KucniBroj><tns:KucniBrojDodatak>b</tns:KucniBrojDodatak><tns:BrojPoste>52100</tns:BrojPoste><tns:Naselje>Pula</tns:Naselje><tns:Opcina>Pula</tns:Opcina></tns:Adresa></tns:AdresniPodatak><tns:RadnoVrijeme>radnim danom od 8 do 22, subotom 10-24, nedjeljom zatvoreno</tns:RadnoVrijeme><tns:DatumPocetkaPrimjene>01.07.2013</tns:DatumPocetkaPrimjene><tns:SpecNamj>86545165826</tns:SpecNamj></tns:PoslovniProstor></tns:PoslovniProstorZahtjev>
Čitljiviji format ovdje.
Kako svi znakovi u tom stringu pripadaju ASCII kodu, string je automatski i UTF8.
sha1 hash za taj string je
D3 DF DB 39 F4 41 1B A9 7D 8C 8E 75 10 43 B9 F4 CD 1A EC 34
Kako CryptoAPI daje little endian rezultate, prebacim taj binarni string u big endian i konačno u base64 format, tako da izadje ovo
NOwazfS5QxB1jox9qRtB9Dnb39M=
U idućem koraku u memoriji pripremim SignedInfo
<SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod><Reference URI="#PoslovniProstorZahtjev"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>NOwazfS5QxB1jox9qRtB9Dnb39M=</DigestValue></Reference></SignedInfo>
Čitljiviji format ovdje.
Za SignedInfo sam prilično siguran da je dobro kanoniziran.
Opet preko CryptoAPI izračunam sha1 hash iz gornjeg stringa i potpišem ga sa svojim digitalnim certifikatom. Što se tiče certifikata, pfx file koji sam preuzeo od FINE importirao sam s lozinkom u personal cert storage te sam ga "našao" CryptoAPI sha1 "otiska." Taj dio prividno funkcionira bez greške.
Nakon importa pfx certifikata eksportirao sam ga u der i to u base64 formatu.
Ovo navodim jer se digitalnim certifikatima nisam nikad prije bavio pa mi je logično da sam mogao napraviti neku glupu pogrešku.

Konačno, evo cijelog upita, kakvog šaljem na server:
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><tns:PoslovniProstorZahtjev xmlns:tns="http://www.apis-it.hr/fin/2012/types/f73" Id="PoslovniProstorZahtjev"><tns:Zaglavlje><tns:IdPoruke>47802E89-F7DA-4293-8957-EADDE50EFFBA</tns:IdPoruke><tns:DatumVrijeme>13.03.2013T18:43:40</tns:DatumVrijeme></tns:Zaglavlje><tns:PoslovniProstor><tns:Oib>12345678901</tns:Oib><tns:OznPoslProstora>TERA</tns:OznPoslProstora><tns:AdresniPodatak><tns:Adresa><tns:Ulica>Laginjina</tns:Ulica><tns:KucniBroj>44</tns:KucniBroj><tns:KucniBrojDodatak>b</tns:KucniBrojDodatak><tns:BrojPoste>52100</tns:BrojPoste><tns:Naselje>Pula</tns:Naselje><tns:Opcina>Pula</tns:Opcina></tns:Adresa></tns:AdresniPodatak><tns:RadnoVrijeme>radnim danom od 8 do 22, subotom 10-24, nedjeljom zatvoreno</tns:RadnoVrijeme><tns:DatumPocetkaPrimjene>01.07.2013</tns:DatumPocetkaPrimjene><tns:SpecNamj>86545165826</tns:SpecNamj></tns:PoslovniProstor><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod><Reference URI="#PoslovniProstorZahtjev"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>NOwazfS5QxB1jox9qRtB9Dnb39M=</DigestValue></Reference></SignedInfo><SignatureValue>41n8WtKDPedMEY1n8dCG0UkdmuiSzbQhmlS24LDb5NnbY8FkOv/vq6u28buay3d+WFxQ9+mtSCxP0hWt6GmPGxxfhfd2MbnnmE/I2vGVUxm49bixSOfSzdUV1c1BcCO+SGh7bT00pEcu0QnD1a/tn5xokdCnQbLo9buBs+x8XjH2dauI+TyX/jHeuO50cJSr01hbUxM70LdOWcffQGhzinQvIiOYGelU+KtH1B0WM356gM6zUILlKJtdyRFODeUYOw5V2gKYT70wx5GkzWswLL/dVmMW1Sn8k9om4dtxFLGBxGX5joq5un0sb83v2b4be56i7Dds0Xnd4Zg9KmVljg==</SignatureValue><KeyInfo><X509Data><X509Certificate>...</X509IssuerName><X509SerialNumber>1053495511</X509SerialNumber></X509IssuerSerial></X509Data></KeyInfo></Signature></tns:PoslovniProstorZahtjev></soapenv:Body></soapenv:Envelope>
Čitljivije ovdje.

Pitanja:
  1. što sve uključuje pogreška s004?
  2. može li mi netko potvrditi jesu li gornji stringovi propisno kanonizirani? Naravno da bi neki referentni postupak bio najbolji. Ako bi netko mogao pojasniti kako se npr. koristi xmlstarlet, to bi bilo ništa manje nego fantastično.
  3. kod određivanja sha1 hasha za SignedInfo, primijetio sam da se dobiju različiti rezultati ukoliko se koristit defaultni CSP umjesto PKI od FINE. To je jedna od stvari koje me dobrano zbunjuju, postupak u CryptoAPI je otprilike ovakav:
;-- otvori cert store
invoke CertOpenStore,CERT_STORE_PROV_SYSTEM_A,0,0,CERT_SYSTEM_STORE_CURRENT_USER,offset szMyStore
mov hStore,eax

;-- pronadji DEMO po sha1 otisku
invoke CertFindCertificateInStore,hStore,X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,0,CERT_FIND_SHA1_HASH,offset cdb,0
mov hCert,eax

;-- private key csp
invoke CryptAcquireCertificatePrivateKey,hCert,0,0,offset hProv,offset keySpec,offset freeProv

;-- hashiraj i potpiši SignedInfo
invoke CryptCreateHash,hProv,CALG_SHA1,0,0,offset hHash
invoke CryptHashData,hHash,buffer,len,0
invoke CryptSignHash,hHash,keySpec,0,0,offset buffer,offset nSize

;-- little endian -> big endian -> base64
ShiftByteOrder offset buffer,nSize
Base64Encode offset buffer,nSize,offset buffer2

;-- pospremanje
invoke CryptDestroyHash,hHash
invoke CryptReleaseContext,hProv,0
invoke CertFreeCertificateContext,hCert
invoke CertCloseStore,hStore,0
Sve u svemu, očekivao bih isti sha1 hash neovisno o korištenom CSP.

Hvala na vašem vremenu.
Mar 14, 2013 at 10:28 AM
Edited Mar 14, 2013 at 10:29 AM
OK, malo sam dalje čačkao i čitao rfcove i došao do zaključka (iako se to eksplicitno navodi na više mjesta) kako kanonizirani XML nije i onaj koji se šalje u zahtjevu. Drugim riječima, kanonizirani se koristi samo za hashiranje i signiranje. Jel tako?

Tragom tog razmišljanja, preradio sam svoju proceduru. Ovo koristim za proračun sha1 hasha:
<tns:PoslovniProstorZahtjev xmlns:tns="http://www.apis-it.hr/fin/2012/types/f73" Id="PoslovniProstorZahtjev">
  <tns:Zaglavlje>
    <tns:IdPoruke>
    801DA903-590E-47AA-90F3-1F0E581AA6B3</tns:IdPoruke>
    <tns:DatumVrijeme>14.03.2013T10:05:52</tns:DatumVrijeme>
  </tns:Zaglavlje>
  <tns:PoslovniProstor>
    <tns:Oib>12345678901</tns:Oib>
    <tns:OznPoslProstora>TERA</tns:OznPoslProstora>
    <tns:AdresniPodatak>
      <tns:Adresa>
        <tns:Ulica>Laginjina</tns:Ulica>
        <tns:KucniBroj>44</tns:KucniBroj>
        <tns:KucniBrojDodatak>b</tns:KucniBrojDodatak>
        <tns:BrojPoste>52100</tns:BrojPoste>
        <tns:Naselje>Pula</tns:Naselje>
        <tns:Opcina>Pula</tns:Opcina>
      </tns:Adresa>
    </tns:AdresniPodatak>
    <tns:RadnoVrijeme>radnim danom od 8 do 22, subotom 10-24,
    nedjeljom zatvoreno</tns:RadnoVrijeme>
    <tns:DatumPocetkaPrimjene>01.07.2013</tns:DatumPocetkaPrimjene>
  </tns:PoslovniProstor>
</tns:PoslovniProstorZahtjev>
Ovo sam koristio za RSA-SHA1
<SignedInfo>
  <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
  </CanonicalizationMethod>
  <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1">
  </SignatureMethod>
  <Reference URI="#PoslovniProstorZahtjev">
    <Transforms>
      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature">
      </Transform>
      <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
      </Transform>
    </Transforms>
    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1">
    </DigestMethod>
    <DigestValue>zqoL+G20aun0gcYu2Dg8b4LFdbs=</DigestValue>
  </Reference>
</SignedInfo>
Konačni zahtjev:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance">
  <soapenv:Body>
    <tns:PoslovniProstorZahtjev xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    Id="PoslovniProstorZahtjev"
    xmlns:tns="http://www.apis-it.hr/fin/2012/types/f73">
      <tns:Zaglavlje>
        <tns:IdPoruke>
        801DA903-590E-47AA-90F3-1F0E581AA6B3</tns:IdPoruke>
        <tns:DatumVrijeme>14.03.2013T10:05:52</tns:DatumVrijeme>
      </tns:Zaglavlje>
      <tns:PoslovniProstor xmlns:tns="http://www.apis-it.hr/fin/2012/types/f73">

        <tns:Oib>12345678901</tns:Oib>
        <tns:OznPoslProstora>TERA</tns:OznPoslProstora>
        <tns:AdresniPodatak>
          <tns:Adresa>
            <tns:Ulica>Laginjina</tns:Ulica>
            <tns:KucniBroj>44</tns:KucniBroj>
            <tns:KucniBrojDodatak>b</tns:KucniBrojDodatak>
            <tns:BrojPoste>52100</tns:BrojPoste>
            <tns:Naselje>Pula</tns:Naselje>
            <tns:Opcina>Pula</tns:Opcina>
          </tns:Adresa>
        </tns:AdresniPodatak>
        <tns:RadnoVrijeme>radnim danom od 8 do 22, subotom 10-24,
        nedjeljom zatvoreno</tns:RadnoVrijeme>
        <tns:DatumPocetkaPrimjene>
        01.07.2013</tns:DatumPocetkaPrimjene>
      </tns:PoslovniProstor>
      <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
          <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
          <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
          <Reference URI="#PoslovniProstorZahtjev">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
            <DigestValue>zqoL+G20aun0gcYu2Dg8b4LFdbs=</DigestValue>
          </Reference>
        </SignedInfo>
        <SignatureValue>
        sJDQJiyTd/IR6YCaj/9sTRsPFElAkwRIJ3aMb7QHcYqJQSG4Z3noSfufjwgA70r94QgAHjH0qt7qRnvt7cqVWoToKWzyoSVN2WQk5+jNk50bYUP+EzrUzHyzxAMUDO4SI/2QT2Slrz0Fpv9cOuA/GgfoFbi/moC21h8x0a+7H8ExvEc1u9BkSt9OAiQqdM1O0zWW6t1VR5QnFhuizfJD1S/9rmNzYDfGL414ui2jMdPFYyLbeugFtZCuOr6UZVD3XLnoPKGV3CSCXzklgcYPK8n2/geN6/rO/PXWe6qfuEdd01fXQgHklfE/u949LtuiAjUzlSwnH0l/Rd1apNdnBw==</SignatureValue>
        <KeyInfo>
          <X509Data>
            <X509IssuerSerial>
              <X509IssuerName>OU=DEMO, O=FINA,
              C=HR</X509IssuerName>
              <X509SerialNumber>1234567890</X509SerialNumber>
            </X509IssuerSerial>
            <X509Certificate>...</X509Certificate>
          </X509Data>
        </KeyInfo>
      </Signature>
    </tns:PoslovniProstorZahtjev>
  </soapenv:Body>
</soapenv:Envelope>
Sav XML prije postanja sam provukao kroz HTML/XML tidy, izvorni XML nema niti razmaka niti LF znakova između tagova. Dakle, nikakve izmjene nisu napravljene na XMLu prije hashanja i sl.

Odgovor sa servera (malo skraćeni):
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <tns:PoslovniProstorOdgovor Id="G0xb9762080-4D"
    xsi:schemaLocation="http://www.apis-it.hr/fin/2012/types/f73 FiskalizacijaSchema.xsd"
    xmlns:tns="http://www.apis-it.hr/fin/2012/types/f73"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <tns:Zaglavlje>
        <tns:IdPoruke>
        801DA903-590E-47AA-90F3-1F0E581AA6B3</tns:IdPoruke>
        <tns:DatumVrijeme>14.03.2013T10:05:55</tns:DatumVrijeme>
      </tns:Zaglavlje>
      <tns:Greske>
        <tns:Greska>
          <tns:SifraGreske>s004</tns:SifraGreske>
          <tns:PorukaGreske>Neispravan digitalni
          potpis.</tns:PorukaGreske>
        </tns:Greska>
      </tns:Greske>
      ...
    </tns:PoslovniProstorOdgovor>
  </soap:Body>
</soap:Envelope>
Drugim riječima, nema promjena na fronti.
Mar 14, 2013 at 1:44 PM
Ako hoces posaljem ti uradak ya prijevu poslovnog prostrora. U njemu imas sve poruke vidljive prije i nakon potpisa, pa mozes usporediti.
Mar 14, 2013 at 1:48 PM
Takva ponuda se ne odbija, šalji :)

Borim se, xmlsec mi daje nekakve rezultate, ali i dalje samo uspijevam promijeniti tip greške koju mi javlja server. Prebacuje me s s004 na s001 i obratno.
Mar 14, 2013 at 1:52 PM
Serveri prihvaćaju samo OIB-e za koji su izdali certifikat. Dakle ako šalješ na testni server, oib naveden u poruci treba biti isti kao za koga je izdan demo certifikat. Isto za produkcijski server. Šalješ datoteku potpisanu certifikatom, i u toj datoteci oib tvrtke kojoj je izdan taj certifikat. Kod tebe vidim da je oib 12345678901, a to nebi išlo.
Mar 14, 2013 at 1:57 PM
Ako hoces posaljem ti uradak ya prijevu poslovnog prostrora. U njemu imas sve poruke vidljive prije i nakon potpisa, pa mozes usporediti.
Mar 14, 2013 at 1:57 PM
Edited Mar 14, 2013 at 1:59 PM
To nisam znao, a nije mi bogami palo ni na pamet.
Hvala, popravit ću to.

EDIT:
da stvar bude gora i SpecNamj mi je ispao negdje u medjuvremenu :sui:
Mar 14, 2013 at 1:58 PM
Spalit cu ga na google drive pa postam link.
Mar 14, 2013 at 2:00 PM
Serveri prihvaćaju samo OIB-e za koji su izdali certifikat. Dakle ako šalješ na testni server, oib naveden u poruci treba biti isti kao za koga je izdan demo certifikat. Isto za produkcijski server. Šalješ datoteku potpisanu certifikatom, i u toj datoteci oib tvrtke kojoj je izdan taj certifikat. Kod tebe vidim da je oib 12345678901, a to nebi išlo.
Mar 14, 2013 at 2:07 PM
Spalit cu ga na google drive pa postam link.
Mar 14, 2013 at 2:12 PM
https://docs.google.com/file/d/0B_YWtUvmdFceWkhDZmpXZC1DMTQ/edit?usp=sharing
Evo linka sa uratkom, pa kome treba.

U fis.ini je url testni.
Certifikat mora biti exportan u pfx formatu.
Mar 14, 2013 at 2:15 PM
Serveri prihvaćaju samo OIB-e za koji su izdali certifikat. Dakle ako šalješ na testni server, oib naveden u poruci treba biti isti kao za koga je izdan demo certifikat. Isto za produkcijski server. Šalješ datoteku potpisanu certifikatom, i u toj datoteci oib tvrtke kojoj je izdan taj certifikat. Kod tebe vidim da je oib 12345678901, a to nebi išlo.
Mar 14, 2013 at 2:20 PM
Nešto čudno se dogadja s postovima ovdje...

Probam pa javim.
Mar 14, 2013 at 2:29 PM
Eh da, sad sam shvatio da ja zapravo uopće ne razumijem što je "X509SerialNumber." Odnosi li se na FINU kao CA ili na moj demo certifikat?
Mar 14, 2013 at 10:47 PM
Čini mi se da napredujem, ali dogadjaju se čudne stvari.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap:Body>
    <PoslovniProstorZahtjev xmlns="http://www.apis-it.hr/fin/2012/types/f73"
    Id="PoslovniProstorZahtjev">
      <Zaglavlje>
        <IdPoruke>ac17d462-c2e1-4cdc-8042-2c6edb4ddd00</IdPoruke>
        <DatumVrijeme>14-03-2013T22:35:53</DatumVrijeme>
      </Zaglavlje>
      <PoslovniProstor>
        <Oib>86545165826</Oib>
        <OznPoslProstora>TERA</OznPoslProstora>
        <AdresniPodatak>
          <Adresa>
            <Ulica>Laginjina</Ulica>
            <KucniBroj>44</KucniBroj>
            <KucniBrojDodatak>b</KucniBrojDodatak>
            <BrojPoste>52100</BrojPoste>
            <Naselje>Pula</Naselje>
            <Opcina>Pula</Opcina>
          </Adresa>
        </AdresniPodatak>
        <RadnoVrijeme>radnim danom od 8 do 22, subotom 10-24,
        nedjeljom zatvoreno</RadnoVrijeme>
        <DatumPocetkaPrimjene>01-07-2013</DatumPocetkaPrimjene>
        <SpecNamj>86545165826</SpecNamj>
      </PoslovniProstor>
      <ds:Signature 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/2000/09/xmldsig#rsa-sha1" />
          <ds:Reference URI="#PoslovniProstorZahtjev">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
            <ds:DigestValue>
            CKSgOgxAtlMr4iRd+b4Ss72jofM=</ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>cQupK5zyQS26UFIu3y4VL+UHbg8XCkk3ueoBQhLFwhCy+Bvm4eKweUs9CigMdV9OvUhorCxyFfN6r4OdckTNn9ox+Mdn1Gq+9jzciOMK+DSZ9SOQ+wvhMtT4uIYWDZImUZ/Vs41d76KL8rT3g7gAduhu4frWpFJmuB49ZfKC9bSbTpYqQH/q7IgWh8e2AQnDBssSFfSeSHrOYo/tvDXBYP0qWZDUo2G/xWZAsgGMGik43vk62xrAp3EjGyfWz+nk0EmCTbAtAB2XY9R5i1sYSiG0WXWW8Cdj/bG1tv5iG+rRjJPYpR01v4uJfKwuQYAZLtDpM8PGCDlDA6c1jqT1/A==</ds:SignatureValue>
        <ds:KeyInfo>
          <ds:X509Data>
            <ds:X509IssuerSerial>
              <ds:X509IssuerName>OU=DEMO, O=FINA,
              C=HR</ds:X509IssuerName>
              <ds:X509SerialNumber>...</ds:X509SerialNumber>
            </ds:X509IssuerSerial>
            <ds:X509SubjectName>...</ds:X509SubjectName>
            <ds:X509Certificate>...</ds:X509Certificate>
          </ds:X509Data>
        </ds:KeyInfo>
      </ds:Signature>
    </PoslovniProstorZahtjev>
  </soap:Body>
</soap:Envelope>
Odgovor na ovaj zahtjev je samo
<?xml version="1.0" encoding="UTF-8"?>
Mar 14, 2013 at 11:58 PM
Edited Mar 14, 2013 at 11:59 PM
Pomalo sam izludio, zaboravio sam da InternetReadFile ne vrati uvijek sve što je u bufferu nego treba pozivati funkciju dok ne potvrdi da više nema što pročitati.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap:Body>
    <tns:PoslovniProstorOdgovor Id="G0x9798c080-4D"
    xsi:schemaLocation="http://www.apis-it.hr/fin/2012/types/f73 FiskalizacijaSchema.xsd"
    xmlns:tns="http://www.apis-it.hr/fin/2012/types/f73">
      <tns:Zaglavlje>
        <tns:IdPoruke>
        bb338581-3767-4958-9071-00b589296c04</tns:IdPoruke>
        <tns:DatumVrijeme>14.03.2013T23:53:42</tns:DatumVrijeme>
      </tns:Zaglavlje>
      <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
          <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
          <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
          <Reference URI="#G0x9798c080-4D">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
              <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
            <DigestValue>1GTay9cJa4+hW3nTqmJjnUmbJ7E=</DigestValue>
          </Reference>
        </SignedInfo>
        <SignatureValue>
        PS0/0Ki07l/OGQlyEWEop7cmKECYy+9d5FuwVZ0PgibvU7zzX76/+ZGi27EhynJ3MPit7gHCtroTMCa/qG/ZrU5ywDy7UuCQ+Sl7tTtzEeiiGU3ClGCkbR6x9rkKeJaZgTRiZJpqyp5j9FqM7nuzYp615dJxjP9YFu61E6rpeceoPQoFfEhTDHFP4A+XiPUYPv14WX4I2HRDbBCYeeCzRfAOI9dmP+QJKLKqQe72H03Eox/zUWlN5ZF+QuxCb98RfHHrR6gV2zC2MWqJx1UrrFqZOy5codrIPPSvAzLU/C+wCjTl/xAO+Vr8j6hA5YR1MlrGCbDSLAhL88nXJIfK5w==</SignatureValue>
        <KeyInfo>
          <X509Data>
            <X509Certificate>
            MIIExDCCA6ygAwIBAgIEPssQcTANBgkqhkiG9w0BAQUFADArMQswCQYDVQQGEwJIUjENMAsGA1UEChMERklOQTENMAsGA1UECxMEREVNTzAeFw0xMjA5MjYwODExNDlaFw0xNDA5MjYwODQxNDlaMHgxCzAJBgNVBAYTAkhSMQ0wCwYDVQQKEwRGSU5BMQ0wCwYDVQQLEwRERU1PMREwDwYDVQQLEwhQb3Nsb3ZuaTEgMB4GA1UECxMXQVBJUyBJVCBELk8uTy4gODA1NDEzNzIxFjAUBgNVBAMTDWZpc2thbGNpc3Rlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC81TtKtJ84emCS/HK7gSovjNdluZWB0DbIMq3cBFpOpmurcbDCJ1Z17XiPLa+UWYIqyAjHQyDnG/H4c5EeGoli9swz5QcZFBmyXTpSd3GuMROgUAd4bcvbw1/HDONE5cE8PL11GIy8gi5ANZkujalYmx+1ImnhHxx1Bh2UJ/bcl2eXPtieBQBwtClATSzseB5FFz8LcSyfzM7h39PsAIZ0p8YzH7W+307gvgrJHYb/n4ADwlxieHqb5j74DVD0rUPcUE5d0nSZ7hfEkW8xICgs1Ly6Vu3w7Z5M8vb4QmoPnlT1EaHCXiweuK6vjkUk8RQmYY4lTFBs8zHiG7h4n9bPAgMBAAGjggGhMIIBnTAOBgNVHQ8BAf8EBAMCBaAwQgYDVR0gBDswOTA3BgkrfIhQBR8FBAIwKjAoBggrBgEFBQcCARYcaHR0cDovL2RlbW8tcGtpLmZpbmEuaHIvY3BzLzCBzgYDVR0fBIHGMIHDMEKgQKA+pDwwOjELMAkGA1UEBhMCSFIxDTALBgNVBAoTBEZJTkExDTALBgNVBAsTBERFTU8xDTALBgNVBAMTBENSTDcwfaB7oHmGT2xkYXA6Ly9kZW1vLWxkYXAuZmluYS5oci9vdT1ERU1PLG89RklOQSxjPUhSP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3QlM0JiaW5hcnmGJmh0dHA6Ly9kZW1vLXBraS5maW5hLmhyL2NybC9kZW1vY2EuY3JsMCsGA1UdEAQkMCKADzIwMTIwOTI2MDgxMTQ5WoEPMjAxNDA5MjYwODQxNDlaMB8GA1UdIwQYMBaAFHpgI45InTJrpOUt3bhZtJT8QmKeMB0GA1UdDgQWBBRgIJsZevSn6kDuSzChmaa9Sqr6sjAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBBQUAA4IBAQCo5kJWaNjgS+UG7XQHsHersDFk4K5W/Y2Pbubary0j3IwJrveHbUR3HOb0KiVenF6+1FL3sCI/2tfH3wSszWL8Gkit8jUudTo5vDyLqEUXYDHlFUBwseudsPkUxPiQ6HuuFd3PiUAWf00chXD38eTjfapNu6VeQt4EORSO+rEXdhWihVb5HxFIVPTkqHmq1KINwtV9+thwE3hNMwacRa4gwTB1O+jadVlJQMq+kgwnLGLBcwr0W+x1ye6MPSYEUxSNFGHPG/evP9DRLwJtR3ngvlCDusnO+A75Nn40VYcoIjw6EN1V+plK+HkLye0zzLsnHIWTSGfZ2sQVG5xCURiI</X509Certificate>
            <X509IssuerSerial>
              <X509IssuerName>OU=DEMO, O=FINA,
              C=HR</X509IssuerName>
              <X509SerialNumber>1053495409</X509SerialNumber>
            </X509IssuerSerial>
          </X509Data>
        </KeyInfo>
      </Signature>
    </tns:PoslovniProstorOdgovor>
  </soap:Body>
</soap:Envelope>
Pretpostavljam da se problem svodio na dvije točke:
  1. byte order SHA1 hasha se ne mijenja, samo ga treba prebaciti u base64. Byte order signature treba prebaciti u big endian.
  2. CISovi primjeri u onom pdf-u su u banani
Mar 15, 2013 at 9:03 AM
Edited Mar 15, 2013 at 9:04 AM
Za buduću referencu, evo popisa stvari kod kojih se može lako pogriješiti te nekih napomena:
  1. GUID mora biti lower case. Funkcija StringFromGUID2 daje upper case string.
  2. Kako je već gore navedeno, SHA1 hash byte order za kanonizirani "PoslovniProstorZahtjev" kakvog daje CryptCreateHash je ispravan i samo ga je potrebno prebaciti u base64, direktno iz binarnog formata. Vidim da ljudi ponegdje binarni SHA1 (20 byte) prebace prvo u heksadecimalni string (40 byte) i tek onda u base64 (56 byte,) dok konačni base64 string treba biti duljine 28 byte. Za prebacivanje u base64 može se koristiti i CryptoAPI funkcija CryptBinaryToString. Ja sam, kao mazohista, išao ručno. Pripazite se nekih funcija koje bi mogle dodavati previše paddinga, u obliku znaka jednakosti (=). U nikojem slučaju broj tih znakova ne smije prelaziti dva, dok sam primijetio da neke funkcije znaju stavljati i tri ili čak četiri.
  3. Byte order potpisa kanoniziranog "SignedInfo" dobivenog od CryptSignHash ne odgovara i njega je potrebno pretvoriti u big endian prije prebacivanja u base64. Ukoliko netko sumnja, za prebaciti byte order sve što je potrebno je prvom i zadnjem bajtu u nizu zamijeniti mjesta, potom zadnjem i pradzadnjem i tako dalje.
  4. PFXImportCertStore s kojim bi se trebalo moći direktno koristiti fiskal1.pfx certifikat nisam uspio dobiti očekivane rezultate. Konačno sam se odlučio importirati certifikat u certificate store i potom pronaći certifikat preko njegovog SHA1 hasha i funkcije CertFindCertificateInStore. SHA1 certifikata se može izračunati iz certifikata ukoliko ga eksportirate u binarni DER format ili se može naći preko windows dijaloga ili u certmgr.msc nakon importiranja DER certifikata.
  5. Format datuma može biti dd-mm-yyyy ili dd.mm.yyyy.
  6. OIB koji se šalje u sklopu zahtjeva mora odgovarati OIBu iz certifikata. To je samo po sebi očito, ali eto može se i tu lako pogriješiti :P
  7. Certifikat koji se dodaje pod "X509Certificate" je base64 DER formata javnog certifikata, kakvog je moguće eksportirati iz certmgr.msc. Možete ga i proračunski odrediti iz binarnog DER formata.
  8. Za sve base64 stringove (signatura, certifikat) nebitno je hoće li base64 string biti "u jednom komadu" ili će nakon nekog broja znakova biti ubačen "LF" (0x0A) znak. To mi se činilo očito, ali u napadu bunila morao sam provjeriti.
  9. Kanoniziranom XMLu nije mjesto u konačnom zahtjevu, on se koristi samo za izračun hasha i signature. Ovo je isto očito, ali tek nakon što se pročita RFC :D
Jedan ispravan primjer za kraj.
Kanonizirani oblik za "PoslovniProstorZahtjev" izgleda ovako
<PoslovniProstorZahtjev xmlns="http://www.apis-it.hr/fin/2012/types/f73" xmlns:sp="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Id="PoslovniProstorZahtjev"><Zaglavlje><IdPoruke>47d016ff-0f0d-49b8-a212-4c44ca8152e6</IdPoruke><DatumVrijeme>15.03.2013T08:33:19</DatumVrijeme></Zaglavlje><PoslovniProstor><Oib>86545165826</Oib><OznPoslProstora>TERA</OznPoslProstora><AdresniPodatak><Adresa><Ulica>Laginjina</Ulica><KucniBroj>44</KucniBroj><KucniBrojDodatak>b</KucniBrojDodatak><BrojPoste>52100</BrojPoste><Naselje>Pula</Naselje><Opcina>Pula</Opcina></Adresa></AdresniPodatak><RadnoVrijeme>radnim danom od 8 do 22, subotom 10-24, nedjeljom zatvoreno</RadnoVrijeme><DatumPocetkaPrimjene>01.07.2013</DatumPocetkaPrimjene><SpecNamj>86545165826</SpecNamj></PoslovniProstor></PoslovniProstorZahtjev>
SHA1 hash u base64 formatu za gornji XML iznosi
xcS790cSwmcPRUusSDnWxiVqdKg=
Kanonizirani oblik "SignedInfo" će izgledati ovako
<ds:SignedInfo xmlns="http://www.apis-it.hr/fin/2012/types/f73" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:sp="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod><ds:Reference URI="#PoslovniProstorZahtjev"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod><ds:DigestValue>xcS790cSwmcPRUusSDnWxiVqdKg=</ds:DigestValue></ds:Reference></ds:SignedInfo>
Signatura za gornji XML ovisi o certifikatu, tako da ovdje nema smisla davati primjer.
Konačni zahtjev izgleda ovako
<?xml version="1.0" encoding="UTF-8"?><sp:Envelope xmlns:sp="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><sp:Body><PoslovniProstorZahtjev xmlns="http://www.apis-it.hr/fin/2012/types/f73" Id="PoslovniProstorZahtjev"><Zaglavlje><IdPoruke>47d016ff-0f0d-49b8-a212-4c44ca8152e6</IdPoruke><DatumVrijeme>15.03.2013T08:33:19</DatumVrijeme></Zaglavlje><PoslovniProstor><Oib>86545165826</Oib><OznPoslProstora>TERA</OznPoslProstora><AdresniPodatak><Adresa><Ulica>Laginjina</Ulica><KucniBroj>44</KucniBroj><KucniBrojDodatak>b</KucniBrojDodatak><BrojPoste>52100</BrojPoste><Naselje>Pula</Naselje><Opcina>Pula</Opcina></Adresa></AdresniPodatak><RadnoVrijeme>radnim danom od 8 do 22, subotom 10-24, nedjeljom zatvoreno</RadnoVrijeme><DatumPocetkaPrimjene>01.07.2013</DatumPocetkaPrimjene><SpecNamj>86545165826</SpecNamj></PoslovniProstor><ds:Signature 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/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#PoslovniProstorZahtjev"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>xcS790cSwmcPRUusSDnWxiVqdKg=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>...</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>...</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature></PoslovniProstorZahtjev></sp:Body></sp:Envelope>
Ja sam se odlučio za XML bez whitespacea. U čitljivom formatu to bi izgledalo ovako
<?xml version="1.0" encoding="utf-8"?>
<sp:Envelope xmlns:sp="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <sp:Body>
    <PoslovniProstorZahtjev xmlns="http://www.apis-it.hr/fin/2012/types/f73" Id="PoslovniProstorZahtjev">
      <Zaglavlje>
        <IdPoruke>47d016ff-0f0d-49b8-a212-4c44ca8152e6</IdPoruke>
        <DatumVrijeme>15.03.2013T08:33:19</DatumVrijeme>
      </Zaglavlje>
      <PoslovniProstor>
        <Oib>86545165826</Oib>
        <OznPoslProstora>TERA</OznPoslProstora>
        <AdresniPodatak>
          <Adresa>
            <Ulica>Laginjina</Ulica>
            <KucniBroj>44</KucniBroj>
            <KucniBrojDodatak>b</KucniBrojDodatak>
            <BrojPoste>52100</BrojPoste>
            <Naselje>Pula</Naselje>
            <Opcina>Pula</Opcina>
          </Adresa>
        </AdresniPodatak>
        <RadnoVrijeme>radnim danom od 8 do 22, subotom 10-24, nedjeljom zatvoreno</RadnoVrijeme>
        <DatumPocetkaPrimjene>01.07.2013</DatumPocetkaPrimjene>
        <SpecNamj>86545165826</SpecNamj>
      </PoslovniProstor>
      <ds:Signature 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/2000/09/xmldsig#rsa-sha1" />
          <ds:Reference URI="#PoslovniProstorZahtjev">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
            <ds:DigestValue>xcS790cSwmcPRUusSDnWxiVqdKg=</ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>...</ds:SignatureValue>
        <ds:KeyInfo>
          <ds:X509Data>
            <ds:X509Certificate>...</ds:X509Certificate>
          </ds:X509Data>
        </ds:KeyInfo>
      </ds:Signature>
    </PoslovniProstorZahtjev>
  </sp:Body>
</sp:Envelope>
samo treba zapamtiti da whitespace mijenja kanonizirani oblik i samim time hash neće biti isti. Zato ovaj gornji čitljiviji oblik nije "kompatibilian" s ostatkom primjera.
Na mjesto prve tri točkice ide signatura dobivena za kanonizirani "SignedInfo" dok se certifikat prilaže pod "X509Certificate."

Također izgleda kako polja "X509IssuerSerial", "X509IssuerName", "X509SerialNumber", "X509SubjectName" nisu neophodna, što je i logično jer se svi ti podaci nalaze u certifikatu. Može li izostavljanje tih polja uzrokovati probleme kasnije, to tek treba vidjeti :D