Thursday, March 14, 2013

Signature and Encryption Key Identifiers in Apache WSS4J

The Apache WSS4J configuration allows you to specify how to reference a public key or certificate when signing or encrypting a SOAP message via the following configuration items:
This blog entry will explain what values are valid for each of these configuration items, and will explain what each of these values means. Firstly, let's look at what these configuration items refer to.

When creating a Signature you have the option of adding content to the Signature KeyInfo Element. This lets the recipient know what certificate/public key to use to verify the signature. Specifying a value for WSHandlerConstants.SIG_KEY_ID allows you to change how to refer to the key.

When encrypting some part of the message, a session key is typically generated and used to encrypt the message part, which is then wrapped in an EncryptedData Element. This refers (typically via a Direct Reference) to a EncryptedKey Element in the security header, where the session key is encrypted using the public key of the recipient. Specifying a value for WSHandlerConstants.ENC_KEY_ID allows you to change how to refer to the public key of the recipient in the EncryptedKey KeyInfo element.

The following valid values for these configuration items are:
  • IssuerSerial (default)
  • DirectReference
  • X509KeyIdentifier
  • Thumbprint
  • SKIKeyIdentifier
  • KeyValue (signature only)
  • EncryptedKeySHA1 (encryption only)
1) IssuerSerial

This (default) key identifier method means that the Issuer Name and Serial Number of a X.509 Certificate is included directly in the KeyInfo Element. For example:

<ds:KeyInfo>
    <wsse:SecurityTokenReference>
        <ds:X509Data>
            <ds:X509IssuerSerial>
                <ds:X509IssuerName>CN=XYZ</ds:X509IssuerName>
                <ds:X509SerialNumber>124124....</ds:X509SerialNumber>
            </ds:X509IssuerSerial>
        </ds:X509Data>
    </wsse:SecurityTokenReference>
</ds:KeyInfo>

The certificate is not included in the message and so the recipient will have to have access to the certificate matching the given Issuer Name and Serial Number in a keystore.

2) DirectReference

This key identifier method is used when the X.509 Certificate is included in the message, unlike the IssuerSerial case above. The certificate is Base-64 encoded and included in the request via a BinarySecurityToken element, e.g.:

<wsse:BinarySecurityToken EncodingType="...#Base64Binary"
    ValueType="...#X509v3">MIIBY...
</wsse:BinarySecurityToken>

This Certificate is then referred to directly from the KeyInfo Element as follows:

<ds:KeyInfo>
    <wsse:SecurityTokenReference>
        <wsse:Reference URI="#X509-..." ValueType="...#X509v3"/>
    </wsse:SecurityTokenReference>
</ds:KeyInfo>

3) X509KeyIdentifier 

This key identifier method is similar to DirectReference, in that the certificate is included in the request. However, instead of referring to a certificate, the certificate is included directly in the KeyInfo element, e.g.:

<ds:KeyInfo>
    <wsse:SecurityTokenReference>
        <wsse:KeyIdentifier EncodingType="...#Base64Binary"
            ValueType="...#X509v3">MIIB...
        </wsse:KeyIdentifier>
    </wsse:SecurityTokenReference>
</ds:KeyInfo>

4) Thumbprint

This Key Identifier method refers to the Certificate via a SHA-1 Thumbprint. The certificate may or may not be included in the request. For example:

<ds:KeyInfo>
    <wsse:SecurityTokenReference>
        <wsse:KeyIdentifier EncodingType="...#Base64Binary"
            ValueType="...#ThumbprintSHA1">
            5epW9GhL6s0kC9X9egsRZ90ooeE=
        </wsse:KeyIdentifier>
    </wsse:SecurityTokenReference>
</ds:KeyInfo>

5) SKIKeyIdentifier

This Key Identifier method refers to a Certificate via a Base-64 encoding of the Subject Key Identifier, e.g.:

<ds:KeyInfo>
    <wsse:SecurityTokenReference>
        <wsse:KeyIdentifier EncodingType="...#Base64Binary"
            ValueType="...#X509SubjectKeyIdentifier">
            2DUoN4ppxJz/RNgcCDsJ4SocPdk=
        </wsse:KeyIdentifier>
    </wsse:SecurityTokenReference>
</ds:KeyInfo>

6) KeyValue

This Key Identifier method only applies for Signatures. It includes the (RSA) PublicKey directly in the Signature KeyInfo Element as follows:

<ds:KeyInfo>
    <ds:KeyValue>
        <ds:RSAKeyValue>
            <ds:Modulus>tfJ29N0G1...</ds:Modulus>
            <ds:Exponent>AQAB</ds:Exponent>
        </ds:RSAKeyValue>
    </ds:KeyValue>
</ds:KeyInfo>

7) EncryptedKeySHA1

This Key Identifier method only applies for Encryption. Unlike the previous methods it refers to the way the EncryptedData references the EncryptedKey Element, rather than the way the EncryptedKey Element refers to the public key. For example:

<ds:KeyInfo>
    <wsse:KeyIdentifier EncodingType="...#Base64Binary"   
        ValueType="...#EncryptedKeySHA1">
        X/8wvCY...
    </wsse:KeyIdentifier>
</ds:KeyInfo>

19 comments:

  1. Thanks for this, very useful! Is there a way using WSS4J to produce the following structure via configuration?
    <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>...
    <SignatureValue>...
    <KeyInfo>
    <X509Data>
    <X509SubjectName>CN=EIL2-CHUQ...
    <X509Certificate>MIIFG...
    </X509Data>
    </KeyInfo>
    </Signature>
    </Security>

    I realize that sticking the X509Data right in the KeyInfo goes against the OASIS recommendation to use BinarySecurityToken to pass key material, but I'm trying to follow a spec that requires this. Any idea?

    Thanks!

    ReplyDelete
  2. There is currently no way to support this. I guess what we need is a pluggable CallbackHandler type approach to allow users to specify custom KeyInfos. Is this something you'd be interested in contributing to WSS4J?

    Colm.

    ReplyDelete
    Replies
    1. I looked over the source code a bit yesterday and it doesn't look easy. There's a getSignatureKeyId method which returns an int from all these different things (which reminds me, there's also an "EmbeddedKeyName" that you don't have listed here which seems to apply only to encryption). So seems like it would need some "custom" value added to the list, and that list seems to get checked in a few places- meaning it would need to touch a variety of places to make it work.

      Then in the case of that custom value, I guess it would have to read another field which would be your CallbackHandler. I'm not sure at this point what all stuff it would have to pass to that handler to be able to accommodate the various scenarios people might dream up. This is the point where my understanding is lacking in order to be able to do this.

      Also, this appears to be a one-off and the first I've personally seen of this nature where some consultant felt that following existing standards wouldn't be appropriate. So I'm not sure the effort would be usable for more than my particular case.

      Delete
  3. Ok, that sounds reasonable. I guess you can always swap out the SignatureAction in WSS4J with your own implementation if required.

    Colm.

    ReplyDelete
  4. Hi Colm,

    What assertion should we put to a WS-SecurityPolicy document in order to require the option 2, DirectReference. I have seen there are possibilities like MustSupportRefKeyIdentifier, MustSupportRefIssuerSerial, MustSupportRefExternalURI, MustSupportRefEmbeddedToken. The last one would make sense for me. But in general, how do these security policy assertions correlate to the key reference options you mention in the article?

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. I don't think there is a specific way of requiring Direct Reference via policy as such. You have the following policy options:

      sp:RequireKeyIdentifierReference
      sp:RequireIssuerSerialReference
      sp:RequireEmbeddedTokenReference
      sp:RequireThumbprintReference .

      Delete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Thank you, Colm, that's very useful info.

    Can WSS4J be set to omit KeyInfo field at all?

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete
  9. I need to Sign (no Timestamp, no Encryption) a Web Service Envelope so that the "ds:KeyInfo" section of the signed XML includes a "ds:X509Certificate" as shown below. I know this is not recomended, but I'm forced to do it.

    [ds:KeyInfo]
    [wsse:SecurityTokenReference]
    [ds:X509Data]
    [ds:X509IssuerSerial]
    [ds:X509IssuerName]C=CL,...,CN=Name[/ds:X509IssuerName]
    [ds:X509SerialNumber]162...970[/ds:X509SerialNumber]
    [/ds:X509IssuerSerial]
    [ds:X509Certificate]MIA1g...ljnELi+[/ds:X509Certificate]
    [/ds:X509Data]
    [/wsse:SecurityTokenReference]
    [/ds:KeyInfo]

    Please, how can I do this using lastest version of Apache WSS4J (2.1.7)?

    ReplyDelete
    Replies
    1. Hello Eduardo,
      It's been 2 weeks that I try to find a solution to this, but always in vain.

      Please, help me.
      Thanks.

      Delete
  10. You can create the SecurityTokenReference Element yourself and then inject it into WSSecSignature directly using the "setSecurityTokenReference" method. Example here: ("testCustomSTR") https://svn.apache.org/repos/asf/webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureTest.java

    ReplyDelete
  11. This comment has been removed by the author.

    ReplyDelete
  12. This comment has been removed by the author.

    ReplyDelete
  13. Hello Team,

    I would like to contact you about a problemI have during 2 week on WS-SECURITY using CXF 3.1.3 (jax-ws).
    Indeed, my configuration file spring like this :


    [entry key="action" value="Signature" /]
    [entry key="signaturePropFile" value="security.out.properties"/]
    [entry key="user" value="${user}"/]
    [entry key="passwordCallbackRef"]
    [ref bean="serverPasswordCallback"/]
    [/entry]
    [entry key="signatureKeyIdentifier" value="X509KeyIdentifier"/]
    [entry key="signatureDigestAlgorithm" value="http://www.w3.org/2001/04/xmlenc#sha256"/]
    [entry key="signatureAlgorithm" value="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/]
    [entry key="signatureParts" value="{Content}{}Body "/]

    [entry key="schema-validation-enabled" value="false" /]
    [entry key="security.sts.token.usecert" value="true" /]

    By specifying key "signatureKeyIdentifier" as "X509KeyIdentifier" value, I got a result at the section "keyInfo" as follows:

    [ds: KeyInfo]
    [wsse: SecurityTokenReference]
    [wsse: KeyIdentifier EncodingType = "... # Base64Binary"
    ValueType = "# ... X509v3"] MIIB ...
    [/ wsse: KeyIdentifier]
    [/ wsse: SecurityTokenReference]
    [/ ds: KeyInfo]

    By cons, this is not the result I want, I want a result like this:

    [ds: KeyInfo Id = "KI-ED321E02A6CAE33F8615378788884713"]
    [ds: X509Data]
    [X509Certificate] MIICXTCCA .. [/ X509Certificate]
    [/ds: X509Data]
    [/ds: KeyInfo]

    It's been 2 weeks that I try to find a solution to this, but always in vain.
    Thank you for your help.

    Cordially,

    ReplyDelete
    Replies
    1. Hello, I have the same problem. Did you find the solution?

      Delete
  14. I've replied to your mail on the CXF users list, please send any follow up there.

    ReplyDelete