Java XML签名验证似乎不起作用

时间:2019-08-21 08:16:51

标签: java xml signature xml-signature xml-dsig

我正在尝试使用Java验证XML签名。 我正在遵循在Oracle website here:

上找到的步骤

我正在尝试验证在here找到的示例文件中找到的签名,该文件称为 olamundo-ds

XML文件为:

    <?xml version="1.0" encoding="ISO-8859-1"?>
<env:Envelope xmlns:env="http://example.org/envelope">
    <env:Body>
    Olá mundo
    </env:Body>
    <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="">
                <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>jDpk5iPbux5KxjW0GokRswYzXx4=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
MMekqfoO2kmT69ypNKzMvAtMrXaEQh2QmQKhTPKBMvku33GOv0HCUt2rkqy5ec7pEeLDUXu7LpRto5e+mwY1aq0Yk0FHoM1hDcC+uPrscraV2Lwi7594/czwO+VFSVXuziJSAx6TGSAmhCvoCo1X8l1b9g9rKsFJUgy3tf/Xov8=
        </ds:SignatureValue>
        <ds:KeyInfo>
            <ds:KeyValue>
                <ds:RSAKeyValue>
                    <ds:Modulus>
4IlzOY3Y9fXoh3Y5f06wBbtTg94Pt6vcfcd1KQ0FLm0S36aGJtTSb6pYKfyX7PqCUQ8wgL6xUJ5GRPEsu9gyz8ZobwfZsGCsvu40CWoT9fcFBZPfXro1Vtlh/xl/yYHm+Gzqh0Bw76xtLHSfLfpVOrmZdwKmSFKMTvNXOFd0V18=
                    </ds:Modulus>
                    <ds:Exponent>AQAB</ds:Exponent>
                </ds:RSAKeyValue>
            </ds:KeyValue>
        </ds:KeyInfo>
    </ds:Signature>
</env:Envelope>

到目前为止,这是我的完整代码:

    package consoletest;

    import java.io.ByteArrayInputStream;
    import java.io.File;
    import java.io.IOException;
    import java.nio.file.Files;
    import java.security.Key;
    import java.security.KeyException;
    import java.security.PublicKey;
    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.XMLCryptoContext;
    import javax.xml.crypto.XMLStructure;
    import javax.xml.crypto.dsig.SignatureMethod;
    import javax.xml.crypto.dsig.XMLSignature;
    import javax.xml.crypto.dsig.XMLSignatureFactory;
    import javax.xml.crypto.dsig.dom.DOMValidateContext;
    import javax.xml.crypto.dsig.keyinfo.KeyInfo;
    import javax.xml.crypto.dsig.keyinfo.KeyValue;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;

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

    public class Main {

        public static void main(String[] args) {

            try {
                final ByteArrayInputStream is = readFile("files\\olamundo-ds.xml");

                final DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                dbFactory.setNamespaceAware(true);
                final DocumentBuilder builder = dbFactory.newDocumentBuilder();
                final Document doc = builder.parse(is);

                XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
                // Find Signature element.
                NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
                if (nl.getLength() == 0) {
                    throw new Exception("Cannot find Signature element");
                }

                // Create a DOMValidateContext and specify a KeySelector and document context.
                // DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(), nl.item(0));
                DOMValidateContext valContext = new DOMValidateContext(new KeyValueKeySelector(), nl.item(0));

                // Unmarshal the XMLSignature.
                XMLSignature signature = fac.unmarshalXMLSignature(valContext);

                // Validate the XMLSignature.
                boolean coreValidity = signature.validate(valContext);

                System.out.println("core validity: " + coreValidity);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private static ByteArrayInputStream readFile(final String filePath) throws IOException {
            return new ByteArrayInputStream(Files.readAllBytes(new File(filePath).toPath()));
        }

        /**
         * KeySelector which retrieves the public key out of the
         * KeyValue element and returns it.
         * NOTE: If the key algorithm doesn't match signature algorithm,
         * then the public key will be ignored.
         */
        private static class KeyValueKeySelector extends KeySelector {
            public KeySelectorResult select(KeyInfo keyInfo,
                                            KeySelector.Purpose purpose,
                                            AlgorithmMethod method,
                                            XMLCryptoContext context)
                throws KeySelectorException {
                if (keyInfo == null) {
                    throw new KeySelectorException("Null KeyInfo object!");
                }
                SignatureMethod sm = (SignatureMethod) method;
                List list = keyInfo.getContent();

                for (int i = 0; i < list.size(); i++) {
                    XMLStructure xmlStructure = (XMLStructure) list.get(i);
                    if (xmlStructure instanceof KeyValue) {
                        PublicKey pk = null;
                        try {
                            pk = ((KeyValue)xmlStructure).getPublicKey();
                        } catch (KeyException ke) {
                            throw new KeySelectorException(ke);
                        }
                        // make sure algorithm is compatible with method
                        if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) {
                            return new SimpleKeySelectorResult(pk);
                        }
                    }
                }
                throw new KeySelectorException("No KeyValue element found!");
            }

            private static class SimpleKeySelectorResult implements KeySelectorResult {
                private PublicKey pk;
                SimpleKeySelectorResult(PublicKey pk) {
                    this.pk = pk;
                }

                public Key getKey() { return pk; }
            }

            //@@@FIXME: this should also work for key types other than DSA/RSA
            static boolean algEquals(String algURI, String algName) {
                if (algName.equalsIgnoreCase("DSA") &&
                    algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) {
                    return true;
                } else if (algName.equalsIgnoreCase("RSA") &&
                           algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) {
                    return true;
                } else {
                    return false;
                }
            }
        }
    }

但是当我运行这段代码时,最后的 coreValidity 变量为false,并且我希望它不会。

我似乎找不到验证XML签名的任何示例,这些示例不需要我创建自己的各种类的实现。

没有标准的或广泛使用的Java库可以成功验证XML签名吗?

0 个答案:

没有答案