Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WSS4j elements order during signing SOAP message

I'm implementing web service client in Java which uses wss4j 1.6.8 for WS-Security (to be more precize I need to sign a SOAP message). Server side requires requests to have the following structure:

<Envelope>
    <Header>
        <wsse:Security mustUnderstand="1">
            **<wsu:Timestamp wsu:Id="Timestamp-913ca68e-05ed-44e1-9d6c-b2f293da5a1d">
                <wsu:Created>2012-12-21T11:37:31Z</wsu:Created>
                <wsu:Expires>2012-12-21T11:42:31Z</wsu:Expires>
            </wsu:Timestamp>**
            <wsse:BinarySecurityToken>
                MIID2jCCAsKg...
            </wsse:BinarySecurityToken>
            <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
                <SignedInfo>
                    <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                    <Reference URI="#Timestamp-913ca68e-05ed-44e1-9d6c-b2f293da5a1d">
                        <Transforms>
                            <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </Transforms>
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <DigestValue>jdVY1HaDLusqO9UcxASE/GQHxyo=</DigestValue>
                    </Reference>
                    <Reference URI="#Body-e344eef1-2d8a-42d0-8a30-361ee61a8617">
                        <Transforms>
                            <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </Transforms>
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <DigestValue>L60mQelZERvXgLEgWlW50uJNqEA=</DigestValue>
                    </Reference>
                </SignedInfo>
                <SignatureValue>
                    NmgACUqrYYc/Kp/F...
                </SignatureValue>
                <KeyInfo>
                    <wsse:SecurityTokenReference xmlns="">
                        <wsse:Reference URI="#SecurityToken-3f054298-711c-4090-95c3-105e1093f3ba" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
                    </wsse:SecurityTokenReference>
                </KeyInfo>
            </Signature>
        </wsse:Security>
    </S:Header>
    <S:Body>
        Body content...
    </S:Body>
</Envelope>

My solution signs the document (both body and timestamp elements) but for some reason wss4j puts timestamp element to the bottom of the section, after <wsse:BinarySecurityToken> and <Signature> elements what is wrong. Please look at the sources that does signing job:

 public static SOAPMessage signSoapMessage(SOAPMessage message, PrivateKey signingKey, X509Certificate signingCert, char[] passphrase) throws WSSecurityException {

    final String alias = "signingKey";
    final int signatureValidityTime = 3600; // 1hour in seconds

    WSSConfig config = new WSSConfig();
    config.setWsiBSPCompliant(false);

    WSSecSignature builder = new WSSecSignature(config);

    builder.setX509Certificate(signingCert);
    builder.setUserInfo(alias, new String(passphrase));
    builder.setUseSingleCertificate(true);
    builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);

    try {
        Document document = DanskeUtils.toDocument(message);
        WSSecHeader secHeader = new WSSecHeader();
        secHeader.setMustUnderstand(true);
        secHeader.insertSecurityHeader(document);

        WSSecTimestamp timestamp = new WSSecTimestamp();
        timestamp.setTimeToLive(signatureValidityTime);
        document = timestamp.build(document, secHeader);

        List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
        WSEncryptionPart timestampPart = new WSEncryptionPart("Timestamp", WSConstants.WSU_NS, "");
        WSEncryptionPart bodyPart = new WSEncryptionPart(WSConstants.ELEM_BODY, WSConstants.URI_SOAP11_ENV, "");
        parts.add(timestampPart);
        parts.add(bodyPart);
        builder.setParts(parts);

        Properties properties = new Properties();
        properties.setProperty("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin");
        Crypto crypto = CryptoFactory.getInstance(properties);
        KeyStore keystore = KeyStore.getInstance("JKS");
        keystore.load(null, passphrase);
        keystore.setKeyEntry(alias, signingKey, passphrase, new Certificate[]{signingCert});
        ((Merlin) crypto).setKeyStore(keystore);
        crypto.loadCertificate(new ByteArrayInputStream(signingCert.getEncoded()));

        document = builder.build(document, crypto, secHeader);
        return Utils.updateSoapMessage(document, message);
    } catch (Exception e) {
        throw new WSSecurityException(WSSecurityException.Reason.SIGNING_ISSUE, e);
    }
}

Could you please help me to clarify how to change the order of elements before document will be sign? Thank you!

like image 600
user1028128 Avatar asked Dec 27 '12 12:12

user1028128


1 Answers

The WS-SEC specification says "As elements are added to a header block, they SHOULD be prepended to the existing elements."

So if you first add the timestamp it will be above any existing child elements in the ws-header. Since you are signing message after adding the timstamp, the signing info will be again preappended to the header, thus it will appear above the timestamp element.

If you need the timestamp element to appear at the very top, add it to the header as the final process

like image 85
amindri Avatar answered Oct 10 '22 16:10

amindri