Avatar billede vis_dk Nybegynder
22. september 2009 - 15:17 Der er 1 løsning

Validering af XMLDSIG udfra xml fil

Hej,

Grundlæggende forsøger jeg at validere en XMLDSIG.

Jeg har lavet nedenstående test, som giver følgende resultat:
Verified from DOM? true
Verified from file? false

Jeg er altså i stand til at verificere signaturen, hvis jeg gør det direkte på DOM strukturen. Signaturen kan dog ikke verificeres, hvis DOM'en først skrives til en XML fil og herefter indlæses.

Er der et problem med den måde jeg indlæser XML filen?

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.KeySelectorException;
import javax.xml.crypto.KeySelectorResult;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class SignatureTest {

    /**
    * @param args
    * @throws XMLSignatureException
    * @throws MarshalException
    * @throws InvalidAlgorithmParameterException
    * @throws NoSuchAlgorithmException
    * @throws TransformerException
    */
    public static void main(String[] args) throws NoSuchAlgorithmException,
            InvalidAlgorithmParameterException, MarshalException,
            XMLSignatureException, TransformerException {
        SignatureTest test = new SignatureTest();

        test.run();
    }

    private KeyStore.PrivateKeyEntry keyEntry;
    private X509Certificate cert;

    public SignatureTest() {
        // Load the KeyStore and get the signing key and certificate.
        try {
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream("keystore.jks"), "Test1234"
                    .toCharArray());
            keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry("function",
                    new KeyStore.PasswordProtection("Test1234".toCharArray()));
            cert = (X509Certificate) keyEntry.getCertificate();
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    public void run() throws NoSuchAlgorithmException,
            InvalidAlgorithmParameterException, MarshalException,
            XMLSignatureException, TransformerException {
        Document document;
        try {
            // Get response from servlet
            DocumentBuilderFactory factory = DocumentBuilderFactory
                    .newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            document = builder.parse(new File("unsigned.xml"));
        } catch (Exception e) {
            throw new RuntimeException("Error in parsing xml", e);
        }

        sign(document);

        boolean verified = verify(document);

        System.out.println("Verified from DOM? " + verified);
       
        TransformerFactory tranFactory = TransformerFactory.newInstance();
        Transformer aTransformer = tranFactory.newTransformer();
        Source src = new DOMSource(document);
        Result dest = new StreamResult(new File("signed.xml"));
        aTransformer.transform(src, dest);
       
        Document document2;
        try {
            // Get response from servlet
            DocumentBuilderFactory factory = DocumentBuilderFactory
                    .newInstance();
            factory.setNamespaceAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();
            document2 = builder.parse(new File("signed.xml"));
        } catch (Exception e) {
            throw new RuntimeException("Error in parsing xml", e);
        }
       
        boolean verified2 = verify(document2);
       
        System.out.println("Verified from file? " + verified2);
    }

    private boolean verify(Document document) throws MarshalException,
            XMLSignatureException {

        // Find Signature element.
        NodeList nl = document.getElementsByTagNameNS(XMLSignature.XMLNS,
                "Signature");

        // Create a DOMValidateContext and specify a KeySelector
        // and document context.
        X509KeySelector keySelector = new X509KeySelector();
        DOMValidateContext valContext = new DOMValidateContext(keySelector, nl
                .item(0));
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
        // Unmarshal the XMLSignature.
        XMLSignature signature = fac.unmarshalXMLSignature(valContext);
        // Validate the XMLSignature.
        boolean coreValidity = signature.validate(valContext);

        return coreValidity;
    }

    private void sign(Document document) throws NoSuchAlgorithmException,
            InvalidAlgorithmParameterException, MarshalException,
            XMLSignatureException {
        // Create a DOM XMLSignatureFactory that will be used to
        // generate the enveloped signature.
        Element xmlElementToSign = document.getDocumentElement();

        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Create a Reference to the enveloped document (in this case,
        // you are signing the whole document, so a URI of "" signifies
        // that, and also specify the SHA1 digest algorithm and
        // the ENVELOPED Transform.
        Reference ref = fac.newReference("", fac.newDigestMethod(
                DigestMethod.SHA1, null), Collections.singletonList(fac
                .newTransform(Transform.ENVELOPED,
                        (TransformParameterSpec) null)), null, null);

        // Create the SignedInfo.
        SignedInfo si = fac
                .newSignedInfo(fac.newCanonicalizationMethod(
                        CanonicalizationMethod.INCLUSIVE,
                        (C14NMethodParameterSpec) null), fac
                        .newSignatureMethod(SignatureMethod.RSA_SHA1, null),
                        Collections.singletonList(ref));

        // Create the KeyInfo containing the X509Data.
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        List<Object> x509Content = new ArrayList<Object>();
        x509Content.add(cert.getSubjectX500Principal().getName());
        x509Content.add(cert);
        X509Data xd = kif.newX509Data(x509Content);
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));

        // Create a DOMSignContext and specify the RSA PrivateKey and
        // location of the resulting XMLSignature's parent element.
        DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(),
                xmlElementToSign);

        // Create the XMLSignature, but don't sign it yet.
        XMLSignature signature = fac.newXMLSignature(si, ki);

        // Marshal, generate, and sign the enveloped signature.
        signature.sign(dsc);
    }

}

class X509KeySelector extends KeySelector {

    public X509KeySelector() {
        super();
    }

    @Override
    public KeySelectorResult select(KeyInfo keyInfo,
            KeySelector.Purpose purpose, AlgorithmMethod method,
            XMLCryptoContext context) throws KeySelectorException {
        Iterator ki = keyInfo.getContent().iterator();
        while (ki.hasNext()) {
            XMLStructure info = (XMLStructure) ki.next();

            if (!(info instanceof X509Data))
                continue;

            X509Data x509Data = (X509Data) info;

            Iterator xi = x509Data.getContent().iterator();

            while (xi.hasNext()) {
                Object o = xi.next();

                if (!(o instanceof X509Certificate))
                    continue;

                X509Certificate certificate = (X509Certificate) o;

                InputStream fis = null;
                try {
                    // Check if the certificate is expired or active.
                    certificate.checkValidity();

                    /*
                    * Checks whether the certificate is in the trusted store.
                    * We use direct peer trust, so don't check any chains.
                    */
                    /*
                    * KeyStore ks =
                    * KeyStore.getInstance(KeyStore.getDefaultType());
                    *
                    * fis = trustedKeyStore.openStream(); ks.load(fis,
                    * "Test1234".toCharArray());
                    *
                    * String alias = ks.getCertificateAlias(certificate);
                    *
                    * if (alias != null) {
                    */
                    final PublicKey key = certificate.getPublicKey();
                    // Make sure the algorithm is compatible
                    // with the method.
                    if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
                        return new KeySelectorResult() {
                            public Key getKey() {
                                return key;
                            }
                        };
                    }
                    /* } */

                } catch (Exception e) {
                    throw new KeySelectorException(e);
                } finally {
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (IOException e) {
                            throw new KeySelectorException(e);
                        }
                    }
                }
            }
        }
        throw new KeySelectorException("No key found!");
    }

    private static boolean algEquals(String algURI, String algName) {
        if ((algName.equalsIgnoreCase("DSA") && algURI
                .equalsIgnoreCase(SignatureMethod.DSA_SHA1))
                || (algName.equalsIgnoreCase("RSA") && algURI
                        .equalsIgnoreCase(SignatureMethod.RSA_SHA1))) {
            return true;
        } else {
            return false;
        }
    }
}
Avatar billede vis_dk Nybegynder
22. september 2009 - 15:20 #1
Fejlen var at jeg ikke havde sat det factory der indlæste det originale dokument til at være namespace aware:

factory.setNamespaceAware(true);
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester