9 Oracle Web Services Security

Oracle Web Services Security provides a complete implementation of the OASIS WS Security 1.1 standard. It provides mechanisms to sign and encrypt messages, and security tokens to ascertain the sender's identity.

This chapter describes how to install and use the SDK. This chapter contains these topics:

9.1 Setting Up Your Oracle Web Services Security Environment

You can setup Oracle Web Services Security environment by installing Oracle Security Developer Tools and Java Development Kit (JDK), and setting the CLASSPATH variable to all the required jar files.

The Oracle Security Developer Tools are installed with Oracle Application Server in ORACLE_HOME.

To use Oracle Web Services Security, you must have Development Kit (JDK) version 1.6 or higher.

Make sure the following items are included in your CLASSPATH:

  • osdt_core.jar

  • osdt_cert.jar

  • osdt_xmlsec.jar - This is the Oracle XML Security jar.

  • osdt_saml.jar - This is the Oracle SAML 1.0 and 1.1 jar.

  • osdt_saml2.jar - This is the Oracle SAML 2.0 jar.

  • org.jaxen_1.1.1.jar, which is included in $ORACLE_HOME/modules/.

  • osdt_wss.jar - This is the main jar containing Oracle Web Services Security.

  • saaj-api.jar - This is the standard SAAJ API and is included in JDK6; for previous JDKs, you can obtain it from your JavaEE container.

  • mail.jar, activation.jar - You can obtain these jars from your JavaEE container.

9.2 Classes and Interfaces of Oracle Web Services Security

Oracle Web Services Security provides classes, interfaces, and methods to sign and encrypt messages, and security tokens to ascertain the sender's identity.

Note:

Review Oracle XML Security before proceeding.

This section describes classes and interfaces in the Oracle Web Services Security API. It contains these topics:

9.2.1 Element Wrappers in Oracle Web Services Security

Oracle Web Services Security provides element wrappers to all XML elements.

Table 9-1 lists the element wrappers provided by Oracle Web Services Security.

Table 9-1 Element Wrappers for Oracle Web Services Security

XML Tag Name Java Class Name

<wsse:Security>

oracle.security.xmlsec.wss.WSSecurity

<wsse:BinarySecurityToken>

oracle.security.xmlsec.wss.WSSBinarySecurityToken or one of its derived classes depending on the valueType attribute: oracle.security.xmlsec.wss.x509.X509BinarySecurityToken oracle.security.xmlsec.wss.kerberos.KerberosBinarySecurityToken

<wsse: SecurityTokenReference>

oracle.security.xmlsec.wss.WSSecurityTokenReference

<wsse: Embedded>

oracle.security.xmlsec.wss.WSSEmbedded

<wsse11:EncryptedHeader>

oracle.security.xmlsec.wss.WSSEncryptedHeader

<wsse11:SignatureConfirmation>

oracle.security.xmlsec.wss.WSSignatureConfirmation

<wsse:KeyIdentifier>

oracle.security.xmlsec.wss.WSSKeyIdentifier or one of its derived classes depending on the valueType attribute: oracle.security.xmlsec.wss.x509.X509KeyIdentifier oracle.security.xmlsec.wss.saml.SAMLAssertionKeyIdentifier oracle.security.xmlsec.wss.saml2.SAML2AssertionKeyIdentifier oracle.security.xmlsec.wss.kerberos.KerberosKeyIdentifier oracle.security.xmlsec.wss.WSSEncryptedKeyIdentifier

<wsse:Reference>

oracle.security.xmlsec.wss.WSSReference

<wsu:Created>

oracle.security.xmlsec.wss.WSUCreated

<wsu:Expires>

oracle.security.xmlsec.wss.WSUExpires

<wsu:Timestamp>

oracle.security.xmlsec.wss.WSUTimestamp

<wsse:UsernameToken>

oracle.security.xmlsec.wss.username.UsernameToken oracle.security.xmlsec.wss. oracle.security.xmlsec.wss. oracle.security.xmlsec.wss. oracle.security.xmlsec.wss. oracle.security.xmlsec.wss. oracle.security.xmlsec.wss.

As explained in Understanding and Using Element Wrappers in the OSDT XML APIs, the java classes are only throwaway wrappers, while the DOM elements are the source of truth. You can create these wrapper classes using the appropriate constructor, which takes in the DOM element; you can get the underlying DOM element using the getElement method.

9.2.2 The <wsse:Security> header

The WS Security specification defines a new SOAP Header called <wsse:Security>. All security information, such as Security Tokens, Timestamp, Signatures, EncryptedKeys, and ReferenceList, are stored inside this header.

  • Security Tokens - Contain user name tokens, certificates, SAML assertion and so on (see next section)

  • Timestamp - The current time stamp is often included in the security header, and it is usually included in a signature to prevent replay attacks.

  • Signatures - Any signatures are stored inside the header. Even though the signature is in the Security header, what it signs is often outside the header - for example, a single signature can sign the SOAP Body, some SOAP attachments, a UserName token inside the Security header, and a Timestamp token in the Security header.

  • EncryptedKeys - Any encrypted session keys are stored here.

  • ReferenceList - Contains a list of all the EncryptedData sections.

9.2.2.1 Handling Outgoing Messages

For outgoing messages, you need to create a new <wsse:Security> header, add security tokens and then encrypt and/or sign parts of the document. Here is how to accomplish this task:

// Assuming we the outgoing message has already been constructed into 
// a SOAPMessage object (part of SAAJ API)
SOAPMessage msg = ...
 
// Now create a new <wsse:Security> Header 
// newInstance will internally use SOAPHeader.addHeaderElement
SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
WSSecurity ws = WSSecurity.newInstance(env);
 
// Add required prefixes to this SOAP header
 
// Now add some security tokens (refer to the next section on 
// how to create security tokens)
UsernameToken ut = ...
ws.addUsernameToken(ut);
 
// Create some security token references to this token 
// (refer to following sections)
ws.createSTR...
 
// Now sign or encrypt some data (refer to following sections)
// These should use the above STRs
ws.sign(...);
ws.encryptWithEncKey(...);
ws.encryptNoEncKey(...);
9.2.2.2 Handling Incoming Messages

For incoming messages, you need to look for a particular <wsse:Security> header, inspect its contents, and verify or decrypt parts of the document. To accomplish this task:

// Assuming we the incoming message has already been constructed into 
// a SOAPMessage object (part of SAAJ API)
SOAPMessage msg = ...

9.2.3 Security Tokens (ST) in Oracle Web Services Security

A security token represents an artifact such as a certificate, a kerberos ticket, a user name with password, a Single sign-on token and so on. Oracle Web Services Security contains different types security tokens, such as Username token, X509 certificate, Kerberos ticket, and SAML Assertion, with multiple variations.

Usually a key is derived/extracted from this token, and this key is used to encrypt/decrypt sign/verify parts of the message. However, the security token can also be used just as a data object.

Table 9-2 Security Tokens for Oracle Web Services Security

Type of Token (Java Class) Variations Keys

Username token oracle.security.xmlsec.wss.username. UsernameToken

  • With no password

  • With a SHA1 digest of the password

  • With the actual password, or a different kind of digest/derived password.

Symmetric key obtained by running KeyDerivation on user's password

X509 certificate oracle.security.xmlsec.wss.x509. X509BinarySecurityToken

  • Single v3 certificate

  • Chain of certificates in PKIPath format

  • Chain of certificates in PKCS7 format

  • Public key inside certificate

  • Private key associated with certificate

Kerberos ticket oracle.security.xmlsec.wss.kerberos. KerberosBinarySecurityToken

  • AP_REQ packet

  • GSS-wrapped AP_REQ packet

Either the session key present in the ticket, or a subkey.

SAML Assertion 1.1 oracle.security.xmlsec.wss.saml.SAMLAssertionToken

SAML Assertion 2.0 oracle.security.xmlsec.wss.saml2. SAML2AssertionToken

  • holder_of_key

  • sender_vouchers

  • bearer

For holder_of_key the subject's key is used – this is, the key inside the <saml:SubjectConfirmation> which is inside the <saml:Assertion>.

For sender_vouches, the key of the attesting entity is used.

Keys are not extracted from bearer tokens.

9.2.3.1 Creating a WSS Username Token

First, create a UsernameToken and place it inside your WSSecurity header. The only mandatory field in the UsernameToken is the username:

// create a Username token
WSSecurity ws = ...
UsernameToken ut = new UsernameToken(doc);
ut.setUserName("Zoe");
 
// remember to put this inside your WSSecurity header. 
// addUserNameToken puts it at the beginning, you can also
// use a regular DOM method appendChild or insertChild to put it in.
ws.addUsernameToken(ut); 
 
// optionally add an wsu:Id, so you can refer to it
ut.setWsuId("MyUser");

Next, decide how to put the password into this token. There are several choices:

  1. Add a clear text password. Consider using this technique only when the whole message is being sent over a secure channel like SSL.
  2. Add a digest of the password or some other kind of derived password. A digest is not necessarily more secure than a clear text password, as it can also be replayed unless it is protected by a nonce and time.
  3. Add a digest of the password using the digest mechanism given in the WS Security specification. This uses the nonce and the createdDate.
  4. Do not add the password or its digest at all. Instead derive a key from the password and use that to sign the message, to demonstrate knowledge of the key.
// For options 1 and 2, use the setPassword method
ut.setPassword("IloveDogs");  
 
// With this mechanism, the reciever should simply call
// UsernameToken.getPassword to check if the password is as expected.
 
// For option 3, use the setPasswordDigest method, but before doing 
// thatfor that you have to  at first set a nonce and a created date.
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte nonce[] = new byte[20];
random.nextBytes(nonce); // compute a 20 byte random nonce
ut.setNonce(nonce);
ut.setCreatedDate(new Date()); // Set the date to now
ut.setPasswordDigest("IloveDogs"); // will compute the digest from 
                                   // this clear text password using 
                                   // nonce and createdDate
 
// For this mechanism, the reciever should use the following
byte nonce[] = ut.getNonce();
.. check against the used nonces, to make sure this is a new nonce
Date createdDate = ut.getCreated();
.. check that this createdDate is within an expected clock skew
boolean valid = ut.isValid(userName, passwd), 
// above call will recompute the digest from the passwd
// and the nonce and created date, and check if this digest matches 
// the digest in the username token
 
 
// For option 4, set the salt and iteration count
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte salt[] = new byte[15];
random.nextBytes(salt); // compute a 15 byte random salt
 
ut.setSalt(1, salt);
ut.setIteration(1000);
SecretKey key = ut.deriveKey("IloveDogs");

Now you can use this secret key to sign or encrypt data.

9.2.3.2 Creating an X509 Token

You can either use the X509BinarySecurityToken constructor followed by the setToken method, or use the equivalent helper method WSSecurity.createBST_X509:

WSSecurity ws = ...
X509Certificate cert = ...
X509BinarySecurityToken x509token = WSSecurity.createBST_X509(cert);
 
// remember to put this inside your WSSecurity header. 
// addX509CertificateToken puts it at the beginning, you can also
// use a regular DOM method appendChild or insertChild to put it in.
ws.addX509CertificateToken(x509Token);
 
// optionally add an wsu:Id, so you can refer to it
x509Token.setWsuId("MyCert");

You can also create an X509BinarySecurityToken from a CertPath object if you want to include an entire chain of certificates.

For encryption data with this certificate, you need the public key which you can obtain by using cert.getPublicKey(). For signing, however, you need the private key, which you should maintain in a keystore.

9.2.3.3 Creating a Client-Side Kerberos Token

Kerberos tokens are used, as a rule, in conjunction with the Java GSS-API.

This example shows how to create a client-side token:

//Use JAAS Authentication with Kerberos Login Module
 
// Set up the config files and then call  login()
// to login using this module. This will cause the client to contact 
// the Kerberos Authentication-Service and get a ticket to talk to the 
// Kerberos Ticket-Granting-Service
LoginContext lc = new LoginContext(...);
lc.login();
 
//Use JAAS Authorization to set the subject into the thread context
Subject.doAs(lc.getSubject(), action)
 
// The rest of the code should be executed as a Privileged action
// Create a GSSContext to talk to a particular server.
 
GSSManager gssManager = GSSManager.getInstance();
GSSName serviceName = gssManager.createName(svcPrincipalName, null);
GSSContext gssContext = gssManager.createContext(serviceName, null, 
    null, GSSCredential.DEFAULT_LIFETIME);
 
// Then call initSecContext. this will cause the client to contact 
// the Ticket-Granting-Service to obtain a ticket for talking to that 
// particular server. The token that is returned by the initSecContext
// is a GSS wrapped AP_REQ packet.
byte[] token = new byte[1];
token = gssContext.initSecContext(token, 0, token.length);
 
// Create a Kerberos BST using this AP_REQ packet
WSSecurity ws = ...
KerberosBinarySecurityToken kbst = ws.createBST_Kerberos(token,   
      WSSURI.vt_GSSKerberosv5);
ws.addKerberosToken(kbst);
 
// Get the sessionKey that is present inside the AP_REQ packet, 
// this is the session that is generated by the TGT and returned
// to the client in the initSecContext class
//
// This getSessionKey call simply calls Subject.getPrivateCredentials
// to get a list of tickets associated with the subject, and then
// iterates through them to find the one to be used for
// for that particular server
SecretKey sessionKey = 
   KerberosUtils.getSessionKey(lc.getSubject(),svcPrincipalName);

Now you can use this secret key to sign or encrypt data.

Server Side

9.2.3.4 Creating a Server-side Kerberos Token

Server-side kerberos tokens require creation of the GSSContext and extraction of the session key.

This example shows how to create a server-side kerberos token:

// Use JAAS Authentication and Authorization as for the client 
// Create GSSContext will null credentials </b><br>
SSManager manager = GSSManager.getInstance();
GSSContext gssContext = manager.createContext((GSSCredential)null);
 
 
// Locate the KerberosBinarySecurityToken in the incoming WSSecurity 
// header. You can do this by doing a DOM search
WSSecurity = ...
KerberosBinarySecurityToken kbst = ...
 
 
// Now extract the AP_REQ from the BST and call acceptSecContext 
byte ap_req[] = kbst.getValue();
gssContext.acceptSecContext(ap_req);
 
// The context is now extablished. (Note Mutual authentication would 
// need one more round trip)
 
// Now extract the session key
// KerberosUtils.getSession is an overloaded method, and this 
// particular one is meant to be used by server. Internally
// it decrypts the ap_req packet using the server's key (or the 
// tgtSession key) and extracts the key from the decrypted ap_req
// packet
Subject srvrSubject = ...
SecretKey sessionKey = 
   KerberosUtils.getSessionKey(srvrSubject, ap_req);

Now you can decrypt or verify using this key.

9.2.3.5 Creating a SAML Assertion Token

Refer to Oracle XML Security for information on how to create Assertion objects. From the Assertion object you can create a SAML assertion token by simply invoking the SAMLAssertionToken(Assertion assertion) constructor.

9.2.4 Security Token References (STR)

The WS Security specifications defines the concept of Security Token Reference (STR), which is a mechanism to refer to a security token. A Signature or Encryption uses this STR mechanism to identify the key that was used to sign or encrypt. STR supports mechanisms such as Direct Reference, Key Identifier, and Embedded.

STR typically supports the following mechanisms:

  • Direct Reference: The STR uses a URI to refer to the ST.

  • Key Identifier: The STR does not use a URI, but instead uses some other mechanism to identify the token, such as the Issuer serial for X509 tokens and the assertion ID for SAML tokens. The token may not be in the message at all.

  • Embedded: The token is directly embedded in the KeyInfo.

9.2.4.1 Creating a direct reference STR

STRs are created using a uniform procedure; the mechanism to pass in the STR depends on the type of token.

To create the STR:

  1. Create the token as mentioned earlier.
  2. Call .setWsuId() to set an ID on that token
  3. Create the STR with the ID from Step 2
  4. Pass in that STR in the WSSSignatureParams or WSEncryptionParams

Subsequent sections demonstrate how to pass in the STR for various tokens.

9.2.4.2 Creating a Reference STR for a username token

This example shows how to create a reference STR for a username token:

WSSecurity ws = ...
WSSecurityTokenReference str = 
   ws.createSTR_Username_ref("#MyUser");
9.2.4.3 Creating a Reference STR for a X509 Token

This example shows how to create a reference STR for an X509 token:

WSSecurity ws = ...
WSSecurityTokenReference str =     
   ws.createSTR_X509_Ref("#MyCert");
9.2.4.4 Creating a Reference STR for Kerberos Token

This example shows how to create a reference STR for a kerberos token:

WSSecurity ws = ...
// use the appropriate value type
String valueType = WSSURI.vt_GSSKerberosv5;
WSSecurityTokenReference str =     
   ws.createSTR_KerberosKeyRef ( "#MyToken");
9.2.4.5 Creating a Reference STR for a SAML Assertion token

This example shows how to create a reference STR for a SAML assertion token:

WSSecurity ws = ...
WSSecurityTokenReference str =
   ws.createSTR_SAML_Assertion_Ref20("MySAMLAssertion")
9.2.4.6 Creating a Reference STR for an EncryptedKey

This example shows how to create a reference STR for an encrypted key:

WSSecurity ws = ...
WSSecurityTokenReference str =
  ws.createSTR_EncKeyRef("MyEncKey")
9.2.4.7 Creating a Reference STR for a generic token

Instead of using the createSTR methods you can also create the reference directly with the appropriate valueType and tokenType:

WSSecurity ws = ...
String uri = "#MyToken";
WSSReference ref = new WSSReference(doc, uri);
ref.setValueType(valueType); // set an optional valueType
WSSecurityTokenReference str = new WSSecurityTokenReference(doc);
str.setTokenType(tokenType); // set an optional tokenType
str.appendChild(ref);
9.2.4.8 Creating a Key Identifier STR

A KeyIdentifier is another way to refer to a security token that uses some intrinsic property of the token; for example, an assertionID for a SAML Token or a Subject Key Identifier for an X509 token.

KeyIdentifers are often used when the token itself is not present in the document. For example, an incoming message can be encrypted with a X509Cert, but instead of having that X509Cert in the message, it can have only a hint to it, in the form of a SubjectKeyIdentifier.

9.2.4.9 Creating a KeyIdentifier STR for an X509 Token

There are three different ways to identify an X509 Token:

  1. Issuer Serial: A combination of Issuer DN and Serial number of the certificate
  2. Subject Key Identifier : The subject key Identifier of the certificate
  3. Thumbprint SHA1: SHA1 of the certificate.
X509Certificate cert = ... 
WSSecurity ws = ...
WSSecurityTokenReference str = 
   ws.createSTR_X509_IssuerSerial(cert);
// alternatively use ws.createSTR_X509_SKI(cert) 
// or ws. createSTR_X509_ThumbprintSHA1(cert)
9.2.4.10 Creating a KeyIdentifier STR for a Kerberos Token

Kerberos tokens can be identified by the SHA1 of the AP_REQ packet or of the GSS wrapped AP_REQ packet.

byte ap_req[] = ...
WSSecurity ws = ...
String valueType = WSSURI.vt_GSSKerberosv5;
WSSecurityTokenReference str = 
   ws.createSTR_KerberosKeyIdSHA1(ap_req, valueType);
9.2.4.11 Creating a KeyIdentifier STR for a SAML Assertion Token

SAML assertions can be identified by the Assertion ID.

For local SAML 1.1 assertions use:

WSSecurity.createSTR_SAML_AssertionIdv11(byte assertionId[])

For remote SAML 1.1 assertions use:

createSTR_SAML_AssertionIdv11(
   byte assertionId[], AuthorityBinding authorityBinding)

For local SAML 2.0 assertions use:

createSTR_SAML_AssertionIdv20(byte assertionId[])

For remote SAML 2.0 assertions use a reference URI:

createSTR_SAML_Assertion_Ref20("MySAMLAssertion")
9.2.4.12 Creating a KeyIdentifier STR for an EncryptedKey

Remote encrypted keys can be identified by their SHA1 hash. Use this function to create the KeyIdentifier:

createSTR_EncKeySHA1(byte sha1[])
9.2.4.13 Adding an STRTransform

An STRTransform is a very useful transform that you add to your signatures. This transform causes a temporary replacement of the STRs wth the corresponding STs while calculating the signature.

For example, you might include an X509 SKI based STR in your reference. Without the STRTransform this will result in only the STR reference being included in the signature,that is, only the SKI value. But if you add an STRTransform, during the signing and verifiing process the STR will be replaced by the actual X509 Certificate, that is, the entire X509 certificate will be included in the message.

9.2.5 Signing and Verifying

You can sign and verify SOAP messages, and confirm signatures.

This section contains a discussion of signing and verifying data.

Topics include:

9.2.5.1 Signing SOAP Messages

Take these steps to sign a SOAP message:

  1. Decide how you want to identify the data to be signed – the most common mechanism is to use an ID, but instead of an ID you can also use an XPath expression
  2. Decide on additional transforms – exclusive c14n and STR transforms are two common transforms that you might add.
  3. Decide on the signing key – you can either do HMAC signing with a symmetric key or do RSA/DSA signatures.
  4. Decide on how to indicate this signing key to the receiver – for this you usually need to create an STR as mentioned earlier.
9.2.5.1.1 Adding IDs to elements

IDs may be added to DOM elements.

Use the function:

WSSUtils.addWsuIdToElement(String id, Element element) 

to add a wsu:Id to the element to be signed. You can use this mechanism to add an ID to regular DOM element, or SAAJ objects which also derive from DOM Elements.

You must declare the wsu namespace prefix. For example, you can declare it at the SOAP Envelope level like this

SOAPEnvelope env = ...
env.addNamespaceDeclaration("wsu" , WSSURI.ns_wsu);

To sign attachments, you must assign a ContentId to each attachment. For this you need to use the following method:

setContentId(String contentId) 

of the SAAJ AttachmentPart object.

9.2.5.1.2 Creating the WSSignatureParams object

A WSSSignatureParams object must be created with all the signing parameters.

Use the following constructor to create the initial WSSignatureParams object. If you want to use HMAC signing, pass in a value for hmacKey, and null for the signingKey; to use asymmetric signing, pass in a value for the signingKey and null for hmacKey.

WSSignatureParams(byte[] hmacKey, PrivateKey signingKey); 

This constructor assumes c14nMethod=excC14N, digestMethod=SHA1 and signMethod=hmacSHA/rsaSHA1/dsaSHA1 (depending on the key). If you want different algorithms use the following setters to set them:

setDigestMethod(String digestMethod)
setSignMethod(String signMethod)
setC14nMethod(String method)

You also need to set the STR that you have created earlier into this object; use the setKeyInfoData for setting the STR.

setKeyInfoData(KeyInfoData keyInfoData)

When signing attachments, you need to set the SOAPMessage into this WSSignatureParams object so that it can resolve the cid references by locating corresponding attachments.

setSOAPMessage(SOAPMessage msg)

9.2.5.1.3 Specifying Transforms

There are two ways to specify transforms - a simpler but limited way, and an advanced and flexible way.

For the simple way, you need to set the following parameters in the WSSignatureParams:

setAttachmentContentOnly(boolean)

In the simple mode, all cid references automatically get the AttachmentContentOnly transform, but if you call setAttachmentContentOnly(false) then the cid references will get an AttachmentComplete transform

·	setUsingSTRTransform(boolean)

If you set this to true, each reference will be checked whether it points to an STR, if it does an STRTransform will we added to that reference. Note the STRTransform is only added if the reference directly points to an STR, not if the reference points to a an ancestor of an STR.

·	setC14Nmethod(String) 

This parameter defaults to exclusive c14n, and specifies both the canonicalization method for each of the references and the canonicalization method for the SignedInfo section.

·	setUsingDecryptTransfom(boolean)

Set this to true if you want a decrypt transform to be added.

9.2.5.1.4 Calling the WSSecurity.sign method

The final step is to call the following method in WSSecurity to perform the actual signing.

XSSignature sign (String[] uris, WSSignatureParams sigParams, XSAlgorithmIdentifier[][] trans)

This method creates the <Signature> element, computes digests of each reference and finally computes the signature.

uris is an array of IDs to be signed. A separate <Reference> will be created for each element of this array.

As described earlier there are two ways to specify the transforms – a simple way in which the transform must be null, and the transformation information is specified throught the various set methods mentioned above (in WSSignatureParams). Or a more advanced way where the transform parameter must explicitly specify all the transforms for each reference, that is, trans.length must be equal to uris.length.

9.2.5.2 Verifying SOAP Messages

When verifying a signature you first need to locate the signature elements in the <wsse:Security> header; for this you can use the method

WSSecurity ws = ...
List<XSSignature>sigs = ws.getSignatures();

This method searches the DOM tree to find all immediate children of <wsse:Security> that are <dsig:Signature> and then creates XSSignature wrapper objects for each of those elements and returns them. (Note the namespace prefixes do not have to use wsse and dsig).

If you already have the verification key in hand, you can call the following method - either pass in an hmacKey for HMAC signatures or a signingKey for asymmetric key signatures. The SOAPMessage is only need when attachments are signed.

XSSignature sig = sigs[0];
 
byte [] hmacKey = ...
PublicKey signingKey = ... ; // Need either hmacKey of signingKey
 
SOAPMessage msg = null; // needed only for attachments
boolean res = WSSecurity.verify(sig, byte[] hmacKey, signingKey, msg);

However, if you do not have the verification key, you need to set up the following callbacks for resolving STR Key Identifiers. Recall that STR Key Identifiers are usually references to tokens outside the document, so Oracle Security Developer Tools cannot locate these tokens unless you explicitly set up these callbacks.

Table 9-3 Callbacks to Resolve STR Key Identifiers

Token Type Implementation Interface and Registration Notes

Username Token

Interface: PasswordRetriever

Registration: UsernameToken.addPasswordRetriever

This callback resolves the UsernameToken Reference STRs.

In the getPassword() callback, return the password corresponding to the user.

This secret key will be derived from password, iteration count and salt.

login() and logout() callbacks are not used

Username Token

Interface: KeyDerivator

Registration: UsernameToken.addKeyDerivator

This callback also resolves the UsernameToken Reference STRs. Use it when you want to use your own key derivation algorithm. In the resolve() callback, derive the key and return it.

X509

Interface: X509KeyIdentifierResolver

Registration: X509KeyIdentifier.addResolver

This callback resolves Thumbprint and SKI Key Identifier STRs.

Implement the resolve() and getPrivateKey() callbacks to return the certificate and the private key respectively.

Note: The private key is not required for verification, but it is required for decryption.

If you have an array of certificates, use the X509KeyIdentifier.matches() method to match each

cerificate against the passed-in X509 KeyIdentifier.

X509

Interface: X509IssuerSerialResolver

Registration: X509IssuerSerial.addResolver

This callback resolves Issuer Serial Key Identifier STRs.

Implement the resolve() and getPrivateKey() callbacks as in the previous case.

Kerberos

Interface: KerberosKeyIdentifierResolver

Registration: KerberosKeyIdentifier.addResolver

This callback resolves Kerberos STRs.

Implement the resolve() and resolveKey() method to return the ap_req packet and the session key/subkey

which corresponds to the SHA1 value present in the KeyIdentifier.

If you have an array of ap_req packets, calculate the SHA1 of each one of them, and find the one

whose SHA1 matches the value returned by KerberosKeyIdentifier.getValue().

Return this ap_req packet in the resolve() method.

For the resolveKey() method you need to take one more step and return they key present inside

the ap_Req packet, for this youe can use the KerberosUtils.getSessionKey(Subject, byte[]) method,

which decrypts the ap_req packet using the Subject's key and extracts the session key/sub-key from it.

SAML Assertion v1.1

Interface: SAMLAssertionKeyIdentifierResolver

Registration: SAMLAssertionKeyIdentifier.addResolver

This callback resolves SAML Assertion KeyIdentifier STRs.

Implement the resolve(), getPublicKey() and getPrivateKey() methods to return the SAML assertion, SAMLX509Cert, and private key respectively. (Note: The private key is required only for decryption, not for verification.)

SAML Assertion v 2.0

Interface: SAML2AssertionKeyIdentifierResolver

Registration: SAML2AssertionKeyIdentifier.addResolver

See previous notes for SAML Assertion v1.1.

For tokens that use symmetric keys - UserName Token, Kerberos, and EncryptedKey - you need to set up a resolver, because the document does not have this symmetric key, and Oracle Security Developer Tools cannot verify (or decrypt) unless you set the resolvers.

For tokens that use asymmetric keys - SAML Assertions and X509 Tokens - you do not need to set up a resolver if it uses a direct URI reference STR or an embedded token, because in these cases Oracle Security Developer Tools can locate the certificate on its own. However you still need to set up the CertificateValidator callback because Oracle Security Developer Tools will not blindly use a certificate in the message unless you have validated the certificate in your callback.

After you have set up all the resolvers and the CertificateValidator, use the following method:

SOAPMessage msg = null; // needed only for attachments
boolean searchTokens = true; 
boolean res = WSSecurity.verify(sig, searchTokens, msg);

This method inspects the Signature's KeyInfo and either searches for the certificate, or calls the appropriate resolvers to get the signing key.

You can also use the WSSecurity.verifyAll method which searches for signatures and verifies them one by one.

9.2.5.3 Confirming Signatures

You use the WSSignatureConfirmation wrapper class to contruct and process signature confirmation elements.

9.2.5.3.1 Signature Confirmation Response Generation

For response generation use the following function in WSSecurity:

List<WSSignatureConfirmation> createSignatureConfirmations(Document doc);

This looks at all the Signatures present in the current WSSecurity element, and constructs corresponding SignatureConfirmation elements in a new document. These could be put in the response's WSSecuirty header.

9.2.5.3.2 Signature Confirmation Response Processing

For response processing, first use this function (at request time) to save all the Signature values.

String [] getSignatureValues()

At response processing time, you can then use this saved list to compare against the incoming SignatureConfirmations as follows:

boolean verifySignatureConfirmations(String sigValue[])

9.2.6 Encrypting and Decrypting

You can encrypt or decrypt SOAP messages with or without an EncryptedKey.

There are two primary encryption methods:

  1. With EncryptedKey: Encrypt the elements with a random session key, then encrypt this session key into an <EncryptedKey> element and place that element in the <wsse:Security> header.
  2. Without EncryptedKey: Encrypt the elements with known symmetric keys, which may be different for each element; construct a <ReferenceList> element with references to each of these encrypted data sections, and place the <ReferenceList> in the <wsse:Security> header.

Note:

While encrypting regular DOM elements is standard practice, you can also encrypt SOAP headers, the SOAP body, and attachments. Special considerations apply for encrypting these objects as explained later.

9.2.6.1 Encrypting SOAP messages with EncryptedKey

You can encrypt SOAP messages by means of EncryptedKey.

First decide on a key to use to encrypt this random session key, then create an STR with the information that the receiver will use to locate this decryption key:

Key keyEncKey = ... ; WSSecurityTokenReference str = ...

create a WSSEncryptionParams with this information:

// Choose a data encryption algorithm - say AES 128
String dataEncAlg = XMLURI.alg_aes128_CBC;
 
// Either generate a random session key yourself, or set this to 
// null to indicate that OSDT should generate it
SecretKey dataEncKey = null;
 
// Depending on the KeyEncryptionKey that you have chosen choose 
// either an RSA key wrap or a symmetric key wrap
String keyEncAlg = XMLURI.alg_rsaOAEP_MGF1;
 
// Now put all this information into a WSSEncryptionParams
WSSEncryptionParams eParam = new WSSEncryptionParams(
 dataEncAlg, dataEncKey, keyEncAlg, keyEncKey, str);

regular DOM element, SOAP headers, the SOAP Body or AttachmentParts:

Element elem1 = ... // one object to be encrypted
Element elem2 = … // another object to be encrypted
ArrayList objectList[] = new ArrayList();
objectList.add(elem1);
objectList.add(elem2);

Create two more arrays to indicate whether each object is to be encrypted content only, and what IDs will be assigned to the resulting EncryptedData objects:

Note:

SOAP bodies are always encrypted content only, regardless of what you pass in this flag. For attachments, "not content only" means content plus mime headers.

// both these elements are not content only
boolean[] contentOnlys = { false, false };
 
// After encryption the EncryptedData elements will get these ids
String encDataIds[] = { "id1", "id2" };

Finally, call the encryptWithEncKey method:

WSSecurity ws = ...
XEEncryptedKey encKey = ws.encryptWithEncKey(objectList, contentOnlys, 
 encDataIds, eParam);
9.2.6.2 Encrypting SOAP messages without EncryptedKey

Use these steps if you do not wish to use an EncryptedKey:

Decide on a data encryption key; you can either use the same one for all the EncryptedData sections or a different one for each. Also create an STR with the information that the receiver will use to locate this decryption key, and put into a WSSEncryptionParams object:

SecretKey dataEncKey = ... ; // assuming 128 bit AES key
String dataEncAlg = XMLURI.alg_aes128_CBC;
WSSecurityTokenReference str = ...
 
// Now put all this information into a WSSEncryptionParams
WSSEncryptionParams eParam = new WSSEncryptionParams(
 dataEncAlg, dataEncKey, null, null, str);

Now create a list of elements to be encrypted as before, along with the associated contentOnly and encDataIds array:

Element elem1 = ... // one object to be encrypted
Element elem2 = … // another object to be encrypted
ArrayList objectList[] = new ArrayList();
objectList.add(elem1);
objectList.add(elem2);
 
// both these elements are not content only
boolean[] contentOnlys = { false, false };
 
// After encryption the EncryptedData elements will get these ids
String encDataIds[] = { "id1", "id2" };

Finally, call the encryptWithNoEncKey method:

WSSecurity ws = ...
XEEncryptedKey encKey = ws.encryptWithNoEncKey(objectList, 
 contentOnlys, encDataIds, new WSEncryptionParams[]{eParam, eParam});

In this example we used the same encryptionParams for both elements.

9.2.6.3 Encrypting SOAP Headers into an EncryptedHeader

When you call the encrypt methods on the SOAP header block , with content only set to false, the entire SOAP header block is encrypted into an EncryptedData element; this element is placed inside an EncryptedHeader element, which replaces the original SOAP header block.

The mustUnderstand and actor attributes are copied over from the current wsse:Security header.

9.2.6.4 Decrypting SOAP messages with EncryptedKey

To decrypt SOAP messages with EncryptedKey, use:

WSSecurity.decrypt(XEEncryptedKey, PrivateKey, SOAPMessage)

which first decrypts the EncryptedKey with the given PrivateKey to obtain a symmetric key, then uses this symmetric key to decrypt all the references inside the EncrytedKey.

If you do not know the PrivateKey, call:

decrypt(XEEncryptedKey, SOAPMessage)

which looks into the KeyInfo of the EncryptedKey and calls the registered callbacks to obtain the private key.

If you already know the decrypted form of the EncryptedKey then use:

decrypt(XEEncryptedKey, SecretKey, SOAPMessage)

which uses the given symmetric key to decrypt all the references inside the EncryptedKey.

9.2.6.5 Decrypting SOAP messages without EncryptedKey

When you wish to decrypt all the elements (or attachments) mentioned in a top level ReferenceList, use:

decrypt(XEReferenceList, SecretKey, SOAPMessage)

which uses the given symmetric key to decrypt all the references inside the ReferenceList. This functions assumes that all the references are encrypted with the same key.

If you do not know the SecretKey, or if all the references are not encrypted with the same key, send in a null for the SecretKey; decrypt then looks into the KeyInfo of each of the EncrytedData and calls the registered callbacks to obtain the symmetric key.

9.3 Additional Resources for Web Services Security

OASIS Specifications, such as OASIS WSS SOAP Message Security Specification and OASIS WSS Username Token Profile Specification, provide more information about Web Services Security.

The following resources provide more information about Web Services Security:

  • OASIS WSS SOAP Message Security Specification

  • OASIS WSS Username Token Profile Specification

  • OASIS WSS X.509 Certificate Token Profile Specification

  • OASIS WSS SAML Assertion Token Profile Specification

  • OASIS WSS SWA Token Profile Specification 1.1

See Also:

Links to these documents are available in References.

9.4 The Oracle Web Services Security Java API Reference

The Oracle Fusion Middleware Java API Reference for Oracle Security Developer Tools guide explains the classes, interfaces, and methods available in the Oracle Web Services Security API.