Disassembler

Artificial intelligence is no match for natural stupidity.
30květen2014

ORO WebService - Testovací tragikomedie


Před půl rokem jsem v článku o podepisování XML SHA256 hashi v .NET psal o jakési oznamovací povinnosti podle zákona pro značení lihu. Celní správa se naštěstí pohybuje již v jednadvacátém století, takže většinu záležitostí je s ní možno řešit skrze různá webová rozhraní a webové služby. To jsem ale tak úplně netušil, že psát aplikaci podle jejích specifikací bude takové drama.

Expozice


Pro jednu blíže nespecifikovanou firmu vyvíjím aplikaci, která právě zmíněné oznámení systémově řeší. Pověřený zaměstnanec prostě poklepe na ikonu a aplikace mu vyrobí XML dokument se všemi potřebnými údaji a náležitostmi. Doposud se zmíněný dokument předával celní správě pomocí datové schránky a celníci si jej do svého systému nasypali ručně. V případě, že byl s oznámením nějaký problém, napsali mail a doufali, že si jej na naší straně třeba někdo přečte. Relativně nově přibyla možnost, o které se posledního půl roku jen mluvilo – odeslání digitálně podepsaného XML skrze webovou službu ORO. Tím by se celý proces vytvoření a odevzdání zjednodušil na pouhý dvojklik (a v případě použití plánovače úloh by ani ten nemusel být potřeba), protože veškeré validace, zpracování chyb a odpovědí a další záležitosti by si vyřídily počítače mezi sebou. Podotýkám, že webové služby celní správy fungují převážně na .NET platformách, což by mi jako .NET vývojáři mělo práci zatraceně zjednodušit, protože Visual Studiu stačí předhodit WSDL deskriptor a veškerou špinavou práci udělá samo.

Kolize


První zádrhel přišel společně s verifikací elektronického podpisu. Webová služba mi tvrdošíjně odmítala přijmout XML a stále tvrdila, že elektronický podpis není platný i přesto, že moje verifikační funkce jej byla schopná úspěšně ověřit. Po příjemném večeru stráveným pouze nad touto jedinou chybou jsem zjistil, že není podpis jako podpis. I přesto, že XML před podpisem prochází kanonizační transformací, podpis samotný bere v potaz i whitespace znaky (tj. mezery, tabulátory a konce řádků). XML, které jsem právě vyrobil a jeho XmlDocument, případně XDocument objekt mám stále v paměti, je tedy zatraceně odlišné od XML s totožným obsahem, které ale již bylo uloženo do souboru a pak z něj znova načteno. Kdybyste se náhodou zahnali do toho samého kouta jako já, zkuste podepisovat a ověřovat následujícím kódem:

public static class XmlHelper
{
    public static XmlDocument Sign(string filename)
    {
        XmlDocument doc = new XmlDocument();
        doc.PreserveWhitespace = true;
        doc.Load(filename);

        SignedXml signedXml = new SignedXml(doc);
        signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
        signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"; // Metodu si musíte vyrobit sami
        signedXml.SigningKey = Config.SigningPrivateKey; // Config je moje statická třída, která mimo jiné drží certifikát i jeho soukromý klíč

        Reference reference = new Reference("");
        reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
        reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha512";
        signedXml.AddReference(reference);

        signedXml.KeyInfo = new KeyInfo();
        signedXml.KeyInfo.AddClause(new RSAKeyValue((RSACryptoServiceProvider)Config.SigningCert.PublicKey.Key));
        signedXml.KeyInfo.AddClause(new KeyInfoX509Data(Config.SigningCert));

        signedXml.ComputeSignature();
        doc.DocumentElement.AppendChild(signedXml.GetXml());
        return doc;
    }

    public static bool VerifySignature(string filename)
    {
        XmlDocument doc = new XmlDocument();
        doc.PreserveWhitespace = true;
        doc.Load(filename);

        SignedXml signedXml = new SignedXml(doc);

        XmlNodeList signature = doc.GetElementsByTagName("Signature");
        signedXml.LoadXml((XmlElement)signature[0]);

        return signedXml.CheckSignature();
    }
}

Metodu http://www.w3.org/2001/04/xmldsig-more#rsa-sha512 .NET ve výchozím stavu nezná, takže je třeba ji definovat podobným způsobem jako v minulém článku zmiňovanou RSAPKCS1SHA256SignatureDescription (která je, jak název napovídá, pro #rsa-sha256).

Také jsem se snažil najít nějakou příčetnou verifikační službu třetí strany, která by mi byla schopna říct, zda podpis XML je platný nebo ne, abych vyvrátil případnou chybu na straně celní správy (jedná se o testovací verzi webové služby, takže neomylnost zaručit nelze) a zjistil, že ani takový úkol není úplně jednoduchý. Nakonec jsem našel u našich jižnějších sousedů tohle.

Krize


Největší špek však přišel ve chvíli, kdy veškeré podepisování a odesílání skrze webovou službu fungovalo, ale odchozí zprávy mi byly zastavovány ECR bránou s jakousi obskurní hláškou

ID for declarant is unknown

Neznaje celnické hantýrky mi ani rozšířený popis, zmíněný v dokumentaci, moc nenapověděl.

ID deklaranta není známo. Nejčastější příčinou tohoto stavu je, že deklarant nemá správně nastavené komunikační parametry v systému ZJP (např. ZJP obsahuje neplatný certifikát)

ZJP? Za prvé nevím co to je a za druhé mě to uráží. Protože se nezdálo, že chyba je v mé aplikaci, pověřil jsem kolegu, který ve zmíněné firmě dělá IT děvečku pro všechno, ať zkusí zjistit a případně nastavit tadyto co tomu chybí, ať už je to cokoliv. Ten se po pár dnech ozval se slovy: „Tak jsem volal Černýmu. Říkal, že vidí, že nám to tam failuje a že prý by nám řekl jak to spravit už dřív, ale neměl na nás kontakt.“ Pan Černý je sice styčnou osobou ve věcech kolem hlášení lihu, ale zdálo se mi, že má na práci i lepší věci, než aby koukal na každou ze zpráv zaslaných skrze testovací webovou službu, protože takových tam přece musí být mraky, když každá větší firma touhle dobou vyvíjí vlastní řešení. Pak jsem si uvědomil, že vždycky, když po dlouhé době (řádově hodiny) zkusím se systémem komunikovat, první požadavek se vyřizuje šíleně dlouho a další už pak jedou daleko svižněji. Skoro jako bych jim tím prvním požadavkem vzbudil servery a roztočil spící disky.

Peripetie


Myšlenku jsem nechal být a věnoval se dalšímu vývoji. S nově nabytými informacemi a opraveným ID deklaranta už jsem chybové hlášky z ECR brány nedostával. Nedostával jsem pro jistotu žádné. A to ani přesto, že podle specifikací bych měl dostat alespoň nějakou zprávu typu CZLOK nebo CZLERR, podle toho jestli systém za bránou data spolkl nebo vyplivnul. OK, tak druhé kolo dotazů na pověřené osoby. Tentokrát se můj dotaz skládal ze dvou částí. Za prvé, „Proč se to se mnou nebaví?“ A za druhé, „Kdy ta služba bude v ostrém provozu?“

Dnes mi obě otázky byly zodpovězeny takto: „Všechny tři poslední testovací zprávy jsou podle Černýho v pořádku. Odpovědi nepřišly, protože se na ně ptáme moc brzo. Testovací mašiny jsou pomalý, takže se máme zkusit zeptat nejdřív za minutu nebo dotaz opakovat. Služba bude v ostrým provozu, jakmile ji někdo otestuje, což jsme právě udělali, takže nasazení na ostro proběhne příští týden. Nikomu jinýmu se to prý zatím nepodařilo, což odpovídá tomu, že jim ty uspaný disky roztáčíme my. A ne, prdel si nedělám.“ V reakci na tuto odpověď jsem se zmohl pouze vcítit se do role Kaina, tak jak jej vysochal Henri Vidal.

Stone hard facepalm

Katarze


Takže systém za jánevímkolik desítek nebo stovek tisíc bude nakonec využíván jedinou firmou v republice a to ještě tak, že jsem jim z klientské strany nevědomky otestoval, zda je jejich dokumentace dostatečně srozumitelná, aby vývoj takové aplikace vůbec byl v lidských silách. No, alespoň v něčem jsem jednou první. Takže kdybyste potřebovali pomoct s oznamovací povinností podle zákona o značení lihu, můžete mne kontaktovat. Pravděpodobně mě najdete někde na okraji louky, jak pečuju o včelstvo, protože po tomhle už na nějaké další programování systémů pro komunikaci se státní správou fakt kašlu.