E-Java: XML podpis – validace
V návaznosti na předchozí článek, ve kterém jsme XML podpis vytvářeli, budeme pokračovat ověřením platnosti všech XML podpisů obsažených v XML dokumentu.
Nalezení elementů podpisu
Nejprve potřebujeme v dokumentu najít XML podpisy, které budeme ověřovat. V našem případě víme, že se element ds:Signature
nachází v dokumentu jako potomek kořenového elementu dokument
. Pokud bychom však dostali k ověření neznámý XML soubor obsahující nějaké podpisy, mohli bychom najít všechny elementy podpisů například vyhledáváním pomocí XPath. Příslušný XPath výraz, který identifikuje všechny elementy ds:Signature
obsažené v podstromu aktuálního uzlu (počítaje tento aktuální uzel do podstromu), vypadá takto: descendant-or-self::ds:Signature
.
Abychom se nemuseli vázat na používání konkrétního prefixu ds
pro jmenný prostor XML podpisu v ověřovaných souborech, implementujeme rozhraní NamespaceContext
, které bude obsahovat mapování prefixu ds
na URI http://www.w3.org/2000/09/xmldsig#
a naopak. Tuto naši implementaci rozhraní NamespaceContext
pak předhodíme instanci třídy XPath
, aby věděla, jakému jmennému prostoru odpovídá prefix ds
použitý v našem XPath výrazu. Odpovídající kód je celkem krátký:
// Vytvoření instance třídy XPath
final XPath xpath = XPathFactory.newInstance().newXPath();
// Nastaveni mapování jmenných prostorů a jejich prefixů
xpath.setNamespaceContext(MyNamespaceContext.getInstance());
// Nalezení výsledné množiny uzlů
final NodeList signatureElements = (NodeList) xpath.evaluate(
„descendant-or-self::ds:Signature“, ancestor,
XPathConstants.NODESET);
Ověření platnosti podpisu
Když jsme všechny podpisy obsažené v dokumentu našli, můžeme přikročit k ověření jejich platnosti. Zjištění, zda je podpis jako celek platný, je také docela jednoduché:
// Získání poskytovatele XML podpisu
final XMLSignatureFactory fac = XMLSignatureFactory.getInstance(„DOM“);
for (int i = 0; i < signatureElements.getLength(); i++) {
// Vytvoření kontextu pro validaci
final DOMValidateContext valContext = new DOMValidateContext(
new MyKeySelector(), signatureElements.item(i));
// Získání XML podpisu z validačního kontextu
final XMLSignature signature = fac
.unmarshalXMLSignature(valContext);
// Ověření platnosti
validateSignature(signature, valContext);
}
Trochu vysvětlení si ještě zaslouží třída MyKeySelector
, která rozšiřuje třídu javax.xml.crypto.KeySelector
a slouží k nalezení veřejného klíče vhodného k ověření podpisu. Ve třídě MyKeyselector
musíme implementovat abstraktní metodu select(KeyInfo keyInfo, KeySelector.Purpose purpose, AlgorithmMethod method, XMLCryptoContext context)
. Naše implementace projde KeyInfo
a vrátí klíč z prvního certifikátu, který potká.
for (Object o1 : keyInfo.getContent()) {
if (o1 instanceof X509Data) {
for (Object o2 : ((X509Data) o1).getContent()) {
if (o2 instanceof X509Certificate) {
return new SimpleKeySelectorResult(
((X509Certificate) o2).getPublicKey());
}
}
}
}
Není-li podpis platný, je možné zjistit bližší podrobnosti o důvodu jeho neplatnosti. Nejprve si stručně zopakujeme, jak je XML podpis vytvořen.
- Vezmou se podepisované objekty určené svými URI (mohou to být celé dokumenty v libovolném formátu nebo části XML dokumentů) a po aplikaci kanonizace XML formátu a aplikaci nějakých transformací se z výsledku vypočte s použitím zadaného algoritmu otisk (hash). Každému z podepisovaných objektů odpovídá jeden element
Reference
, který obsahuje otisk a algoritmus, jímž byl otisk vypočten. - Všechny reference se dají do elementu
SignedInfo
. Dále se tam přidá také informace o algoritmu podpisu a podobné drobnosti. - Z elementu
SignedInfo
se vypočte otisk – algoritmus otisku je součástí algoritmu podpisu – a tento otisk se zašifruje pomocí soukromého klíče uživatele. Výsledný podpis se uloží do elementuSignatureValue
.
Možné důvody neplatnosti podpisu jsou následující:
- Některá z podepsaných referencí je neplatná – podepsaný otisk (hash) reference je odlišný od vypočteného otisku reference. To může být způsobeno tím, že po podepsání objektu někdo obsah URI změnil.
- Otisk elementu
SignedInfo
získaný s použitím veřejného klíče z podpisu tohoto elementu je odlišný od vypočteného otisku. To může být způsobeno špatným klíčem nebo tím, že mezi podpisem a ověřováním podpisu byl obsah elementuSignedInfo
neboSignatureValue
změněn.
Nyní se tedy nejprve podíváme na platnost podepsaných referencí:
for (Reference r : (List<Reference>) signature.getSignedInfo()
.getReferences()) {
boolean refValid = false;
try {
refValid = r.validate(valContext);
} catch (XMLSignatureException e) {
LOG.log(Level.SEVERE, „“, e);
}
LOG.info(„Platnost odkazu \““ + r.getURI() + „\“: “ + refValid);
}
A takto vypadá ověření platnosti podpisu elementu SignedInfo
:
signatureValidity = signature.getSignatureValue().validate(valContext);
Můžete si stáhnout a otestovat zdrojový kód programu a tři XML soubory. Soubor test_podepsany.xml je platně podepsaný dokument, soubor test_podepsany_spatny_odkaz.xml má do obsahu podepisovaného elementu přidanou mezeru a test_podepsany_spatny_podpis.xml má za element ds:SignedInfo
přidáno zalomení řádky. Uvidíte, jaký vliv mají tyto změny na platnost podpisu.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Proč je důležité tvořit obsah na váš web?
29. srpna 2024 -
Chcete jedinečnou doménu? Objevte koncovky FOOD, MEME a MUSIC!
7. listopadu 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024