如何在Java中使用签名XML移动签名节点

时间:2015-09-29 09:11:07

标签: java xml sign

我有这个XML的例子。我需要的是用Java签署xml。问题是我得到了签名'节点在错误的地方..

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fu="http://www.fu.gov.si/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Body>
    <fu:BusinessPremiseRequest Id="data">
        <fu:Header>
            <fu:MessageID>20DF8D44-ABBE-76BA-E053-AA02010AEA8E</fu:MessageID>
            <fu:DateTime>2015-09-24T12:07:28</fu:DateTime>
        </fu:Header>
        <fu:BusinessPremise>
            <fu:TaxNumber>99999862</fu:TaxNumber>
            <fu:BusinessPremiseID>P001</fu:BusinessPremiseID>
            <fu:BPIdentifier>
                <fu:RealEstateBP>
                    <fu:PropertyID>
                        <fu:CadastralNumber>2606</fu:CadastralNumber>
                        <fu:BuildingNumber>6967</fu:BuildingNumber>
                        <fu:BuildingSectionNumber>1</fu:BuildingSectionNumber>
                    </fu:PropertyID>
                    <fu:Address>
                        <fu:Street>TEST</fu:Street>
                        <fu:HouseNumber>7</fu:HouseNumber>
                        <fu:HouseNumberAdditional>C</fu:HouseNumberAdditional>
                        <fu:Community>KOPER</fu:Community>
                        <fu:City>KOPER</fu:City>
                        <fu:PostalCode>6000</fu:PostalCode>
                    </fu:Address>
                </fu:RealEstateBP>
            </fu:BPIdentifier>
            <fu:ValidityDate>2010-09-24</fu:ValidityDate>
            <fu:SoftwareSupplier>
                <fu:TaxNumber>10031685</fu:TaxNumber>
            </fu:SoftwareSupplier>
            <fu:SpecialNotes>Primer prijave poslovnega prostora</fu:SpecialNotes>
        </fu:BusinessPremise>
    </fu:BusinessPremiseRequest>
</soapenv:Body>

现在我想用Java中的私钥对xml进行签名。

XPathFactory factory = XPathFactory.newInstance();
        List transforms = null;

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

        Reference ref = fac.newReference(
                "#data",
                fac.newDigestMethod(DigestMethod.SHA256, null),
                transforms,
                null,
                null
        );

        SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
                (C14NMethodParameterSpec) null),
                fac.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null),
                Collections.singletonList(ref));

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);

        Document doc = (Document) dbf.newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes()));


        KeyStore p12 = KeyStore.getInstance("pkcs12");
        p12.load(new FileInputStream("c:/cert/furspeter.pfx"), "PWD".toCharArray());


        Enumeration e = p12.aliases();
        String alias = (String) e.nextElement();
        System.out.println("Alias certifikata:" + alias);
        Key privateKey = p12.getKey(alias, "PWD".toCharArray());

        KeyStore.PrivateKeyEntry keyEntry
                = (KeyStore.PrivateKeyEntry) p12.getEntry(alias, new KeyStore.PasswordProtection("PWD".toCharArray()));

        X509Certificate cert = (X509Certificate) keyEntry.getCertificate();

        KeyInfoFactory kif = fac.getKeyInfoFactory();

        System.out.println(cert.getSerialNumber());

        X509IssuerSerial x509IssuerSerial = kif.newX509IssuerSerial(cert.getSubjectX500Principal().getName(), cert.getSerialNumber());

        List x509Content = new ArrayList();
        System.out.println("ime: " + cert.getSubjectX500Principal().getName());
        x509Content.add(cert.getSubjectX500Principal().getName());
        x509Content.add(x509IssuerSerial);

        X509Data xd = kif.newX509Data(x509Content);
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
        DOMSignContext dsc = new DOMSignContext(privateKey, doc.getDocumentElement());
        XMLSignature signature = fac.newXMLSignature(si, ki);
        signature.sign(dsc);

        OutputStream os = new FileOutputStream("c:/SignedXml.xml");
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));

我想要的是获得签名&#39;内部节点&fu; BusinessPremiseRequst&#39;节点

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"     xmlns:fu="http://www.fu.gov.si/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Body>
<fu:BusinessPremiseRequest Id="data">
<fu:Header>...</fu:Header>
<fu:BusinessPremise>...</fu:BusinessPremise>
     <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">...</Signature>
</fu:BusinessPremiseRequest>
</soapenv:Body>

在我的情况下,我将节点置于错误的位置(下面的示例)

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fu="http://www.fu.gov.si/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Body>
<fu:BusinessPremiseRequest Id="data">
 ....
</fu:BusinessPremiseRequest>
</soapenv:Body>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">..</Signature>
</soapenv:Envelope>

我在Java示例中做错了什么?或者如何在内部移动节点?

1 个答案:

答案 0 :(得分:1)

你的错误可能就在这里:DOMSignContext dsc = new DOMSignContext(privateKey, doc.getDocumentElement()); 您告诉DOMSignContext Signature应附加到主文档元素。

如果你想在fu:BusinessPremiseRequest中使用它,首先应该获取该节点,并将其作为new DOMSignContext()构造函数中的参数传递。