8 Oracle XML Security

XML security refers to standard security requirements of XML documents such as confidentiality, integrity, message authentication, and non-repudiation. The need for digital signature and encryption standards for XML documents prompted the World Wide Web Consortium (W3C) to put forth an XML Signature standard and an XML Encryption standard.

This chapter describes key features and benefits of Oracle XML Security, and explains how to set up your environment to use Oracle XML Security.

This chapter contains these topics:

See Also:

The following resources provide more information about XML and XML standards:
  • W3C's Recommendation for XML Signatures

  • W3C's Recommendation for XML Encryption

Links to these resources are available in Appendix A, "References".

8.1 Oracle XML Security Features and Benefits

Oracle Security Developer Tools provide a complete implementation of XML Signature and XML Encryption specification.

8.1.1 Supported Algorithms

Oracle Security Developer Tools provide a complete implementation of the XML Signature and XML Encryption specifications, and support these algorithms:

Signature Algorithms

  • DSA with SHA1

  • RSA with SHA1

  • HMAC-SHA1

Digest Algorithms

  • MD5

  • SHA1

  • SHA256

  • SHA512

Transforms

  • Canonicalization – Canonical XML 1.0, Canonical XML 1.1, exclusive Canonical XML 1.0, (all forms are supported with and without comments)

  • XSLT

  • XPath Filter

  • XPath Filter 2.0

  • Base64 Decode

  • Enveloped Signature

  • Decrypt Transform

Data Encryption Algorithms

  • AES-128 in CBC mode

  • AES-192 in CBC mode

  • AES-256 in CBC mode

  • DES EDE in CBC mode

Key Encryption and Key Wrapping Algorithms

  • RSAES-OAEP-ENCRYPT with MGF1

  • RSAES-PKCS1-v1_5

  • AES-128 Key Wrap

  • AES-192 Key Wrap

  • AES-256 Key Wrap

  • DES-EDE Key Wrap

Links to these standards are available in Appendix A, "References".

8.2 Setting Up Your Oracle XML Security Environment

The Oracle Security Developer Tools are installed with Oracle Application Server in ORACLE_HOME/modules/oracle.osdt_11.1.1.

System Requirements

In order to use Oracle XML Security, you must have JDK 5 or higher.

CLASSPATH Environment Variable

Make sure the following items are included in your CLASSPATH:

  • osdt_core.jar

  • osdt_cert.jar

  • osdt_xmlsec.jar (This is the main jar containing all the Oracle XML Security classes.)

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

    Oracle XML Security relies on the Jaxen XPath engine for XPath processing.

8.3 How Data is Signed

Using the Oracle Security Developer Tools Oracle XML Security API, you can sign an XML document, a fragment of an XML document, or some binary data. This section explains the concepts behind data signing.

The basic steps are as follows:

  1. Identify what to sign and where to place the signature.

  2. Decide on a signing key.

See Also:

For details of data signing with the Oracle XML Security APIs, see Section 8.8 through Section 8.11.

8.3.1 Identify What to Sign

The first step is to identify the data that you need to sign and where your signature will be placed.

The most common case of signing is when you are signing a part of a document, and the signature is also placed in the same document. For this you need to decide how you refer to that part. The simplest way is to use an ID, for example:

<myDoc>
  <importantInfo>
    ...
  </importantInfo>
  <dsig:Signature>
    ...
      <dsig:Reference URI="#foo1">
    ...
  </dsig:Signature>
</myDoc>

In this example myDoc is the entire document, of which you only want to sign the <importantInfo> element, and the signature is placed right after the <importantInfo> element. The <importantInfo> has an xml:id attribute, which the Signature uses to refer to it.

xml:id is a generic identifying mechanism.

If your schema does not allow you to add this attribute to your <importantInfo> element, you can instead use an Xpath to refer to it.

8.3.1.1 Determine the Signature Envelope

This example uses a "disjoint" signature where the signature and element to be signed are completely separate.

There are two other ways of signing "enveloped":

  • where the signature element is the child/descendant of the element to be signed, and

  • "enveloping" where the signature element is a parent/ancestor of the element to be signed.

Example of Enveloped Signing

<myDoc>
  <importantInfo>
    ...
    <dsig:Signature>
      ...
      <dsig:Reference URI="#foo1">
         ...
         <Transform Algorithm="...enveloped-signature">
         ...
      </dsig:Reference>
      ...
    </dsig:Signature>
    ...
  </importantInfo>
</myDoc>

When you use enveloped signature, you must use the EnvelopedSignatureTransform to exclude the signature itself from the signature calculation, otherwise the very act of generating a signature changes the content of the importtantInfo element, and the verification will fail.

8.3.1.2 Decide How to Sign Binary Data

It is also possible to sign binary data. To do this you must make the binary data available through a URI. Oracle XML Security allows any URIs that can be resolved by the JDK, such as http:, file:, and zip: URIs.

You need to create a separate XML document which will hold the Signature element, and this signature will refer to the binary data using this URI.

Indeed you can sign XML data using this mechanism as well, provided your XML data can be accessed by a URI. But for XML you can decide to either treat it as binary data and sign as is, or apply canonicalization and sign as XML. To apply canonicalization you need to add a canonicalization transform.

If your binary data is present as a base64 encoded string in your XML document, you can use an ID-based or an Xpath-based reference to it, and then use a Base64DecodeTransform to decode the data and sign the binary.

<myDoc>
  <importantBinaryData>
    XJELGHKLasNDE12KL=
  </importantBinaryData>
  <dsig:Signature>
    ...
      <dsig:Reference URI="#foo1">
         ...
         <Transform Algorithm="...base64">
         ...
      </dsig:Reference>
      ...
  </dsig:Signature>
</myDoc>

Note:

External URI dereferencing can be very insecure. For example, say you are running Oracle Security Developer Tools code inside a server, and you verify an incoming message; if this message has an external URI reference, it is essentially causing your server to read from the file or from external web sites. This can lead to denial of service attacks and cross-site scripting.

This is why External URI dereferencing is disabled by default. You need to set the JVM property osdt.allow.externalReferences (or set osdt.allow.all) to allow external URI dereferencing.

8.3.1.3 Sign Multiple XML Fragments with a Signature

You can include multiple XML fragments into the same signature. For example, you can have two ID-based references, and include both of them in the same signature. Or you can use an Xpath expression which resolves to multiple subtrees.

You can also mix and match local ID-based references with remote URI references, and have all of them in the same signature.

In fact it is recommended that you include multiple parts into the same signature to cryptographically bind them together; for example, if you are using an XML signature to sign a purchase order approval, you must include the items that are being purchased, the user who approved it, and time it was approved, all in the same signature. If you forget to include the user, somebody can potentially steal this message, change the user name, resubmit it, and the signature will still verify.

8.3.1.4 Exclude Elements from a Signature

At times you may need to sign subtrees with exclusions, rather than signing complete subtrees; to achieve this you need to use an Xpath expression.

8.3.2 Decide on a Signing Key

Once you have decided what to sign, and how to reference it, you need to decide on a signing key. Options include:

  • Use a X509Certificate.

    This is the most common mechanism. You sign with the private key, and anybody who has your public key can verify with it.

  • Use a raw asymmetric signing key, like a DSA, RSA, or DH key.

    When you are signing with an X509certificate, you are in fact signing with the DSA/RSA/DH signing key that is associated with the certificate. You can also sign with DSA/RSA/DH signing key that is not associated with any certificate, although there is no good reason for doing so.

  • Use a symmetric key.

    You can also do HMAC signing with a symmetric key. This is useful when you and the verifier already share a symmetric key; it could be a key derived from a password, or it could be from a kerberos system which uses symmetric keys. The Oracle Security Developer Tools WS Security APIs provide explicit APIs for password-based keys and kerberos keys.

8.3.2.1 Set Up Key Exchange

The key exchange needs to happen out of band. For example, if you signing with a certificate, the receiver should already be set up with the trust points, so that the receiver can verify your certificate. Or if you are signing with a symmetric key, the receiver should already know this symmetric key. The XML Signature specification does not define this initial key exchange mechanism.

8.3.2.2 Provide a Receiver Hint

You also need to provide a hint to the receiver so that it knows how to verify your signature. This will be in the <dsig:KeyInfo> tag inside the <dsig:Signature>. This can be accomplished in different ways:

  • You can provide no hint at all. This perfectly acceptable, if you have already communicated the key to the receiver, and the receiver is expecting all signatures to be signed by this key. However this is not a likely situation.

  • When signing with an X509Certificate, you can provide one or more of the following:

    • The entire X509Certificate. This is the most common usage.

    • The Subject DN of the certificate – This is useful when the receiver has access to a LDAP directory, and it can look up the certificate based on the DN.

    • The SubjectKeyIdentifier or the IssuerDN/Serial number pair – This is useful when the receiver is only expecting a signatures from a set of certificates, and it every time it has to verify a signature, it can loop over all the certificates and find the one with matching SKI or IssuerSerial.

  • When signing with a raw asymmetric key, you can provide the actual values of the RSA/DSA/DH public key. This is not recommended as the receiver cannot verify the key; alternatively, if you include the certificate, the receiver can do PKIX processing and verify it; that is, the receiver can check for certificate validity and check against an OCSP or CRL.

  • When signing with a symmetric key, you can provide a key name. This is just a string that conveys some information that the receiver can use to retrieve/construct the symmetric key.

8.4 How Data is Verified

This section explains the concepts behind data verification.

Once you understand how to create a signature, you can use similar steps to verify the signature. The basic steps are as follows:

  1. Search for the signature element, and check what was signed

    When you first search for the signature element in the XML document. Oracle XML Security provides a method (put in link here) to list the elements included in this signature. Verify that those are the elements you were expecting to be signed.

  2. Fetch the verification key

    Next identify the key with which the signature was signed. To do this, examine the <dsig:KeyInfo> for the certificate, raw public key, or symmetric key that should be used for verification.

See Also:

For details of data verification with the Oracle XML Security APIs, see

8.5 How Data is Encrypted

This section explains the concepts behind data encryption.

Using the Oracle XML Security API, you can sign an XML document, a fragment of an XML document or some binary data. The basic steps are as follows:

See Also:

For details of data encryption with the Oracle XML Security APIs, see Section 8.10, "How to Encrypt Data with the Oracle XML Security API".

8.5.1 Identify what to Encrypt

The most common encryption scenario is to encrypt and replace. When you are encrypting a part of the document, replacing the document with the encrypted bytes.

For example:

<myDoc>
  <importantInfo>
    ...
  </importantInfo>
</myDoc>

If you encrypt the importantInfo element, it will look like this:

<myDoc>
  <xenc:EncryptedData>
    ...
  </xenc:EncryptedData>
</myDoc>

Here the entire <importantInfo> and all its contents are replaced by an EncryptedData element which essentially contains a large base64 string, which is the base64 encoding of the encrypted <importantInfo> element.

In this mode the <importantInfo> element is completely hidden, and the receiver has no way of knowing the contents until it is decrypted.

8.5.1.1 The Content Only Encryption Mode

There is also a "Content only" encryption mode where the element tag itself is not encrypted, but all its contents are encrypted.

<myDoc>
  <importantInfo>
    <xenc:EncryptedData>
      ...
    </xenc:EncryptedData>
  </importantInfo>
</myDoc>

Use the "Content Only" mode if it is appropriate for everyone to know that the <importantInfo> exists; only the intended party will know how to decrypt and look at the contents of the <importantInfo> element.

8.5.1.2 Encrypting Binary Data

If you are encrypting binary data present as a base64 encoded string, you can encrypt it as if it were regular XML data.

However if you are encrypting external binary data (that is, data outside the XML document), your options depend on where you will store the encrypted data.

Store Externally

One option is to store the encrypted data externally as well. For SOAP Attachments refer to the WS Security SOAP Attachments (insert link) which specifies a mechanism to encrypt attachments and store the encrypted data back as an attachment.

To store the encrypted data externally, you need to use a xenc:CipherReference, which is a subelement of xencEncryptedData and uses a URI to refer to the encrypted bytes.

Store Internally

The other option is to store the encrypted bytes inside the EncryptedData, just as you would with in-place XML encryption.

8.5.2 Decide on the Encryption Key

This is very similar to the task of deciding the signing key (see section Section 8.3.2, "Decide on a Signing Key") except that you never directly encrypt with an asymmetric key. Instead, you usually:

  • choose a random symmetric key,

  • encrypt your data with this key,

  • encrypt this random symmetric key with your asymmetric key, and

  • send both the encrypted data and encrypted key to the receiver.

Even with a symmetric key, you can still choose to:

  • generate a random symmetric key,

  • encrypt this random symmetric key with your symmetric key and

  • send both the encrypted data key and the encrypted key to the receiver

To use this encrypted key mechanism, you need to decide where to place the xenc:EncryptedKey in your document.

  • If you only have one encryptedData element, place the EncryptedKey in the KeyInfo of the EncryptedData.

  • Otherwise, place them separately and have one refer to the other.

Use the <dsig:KeyInfo> inside the EncryptedKey to refer to the certificate, asymmetric key, or key name that can be used to decrypt the EncryptedKey.

8.6 How Data is Decrypted

Data decryption follows the same process as for data encryption, but in reverse. The basic steps are as follows:

If the data was encrypted with a simple encryption in place, locate the EncryptedData element and look at its KeyInfo.

If it is directly encrypted with a known symmetric key, decrypt it.

Otherwise if it is encrypted with a random symmetric key:

  • locate the corresponding EncryptedKey,

  • decrypt it first, and

  • use this decrypted random symmetric key to decrypt the EncryptedData.

See Also:

For details of data decryption with the Oracle XML Security APIs, see

8.7 About Element Wrappers in the Oracle Security Developer Tools XML APIs

All the XML-based Oracle Security Developer Tools APIs like Oracle XML Security, Oracle Web Services Security, Oracle SAML, Oracle XKMS, and Oracle Liberty SDK use a wrapper concept.

For each XML element, there is a corresponding Java wrapper class. For example, the <dsig:Signature> XML element corresponds to the XSSignature class. All these wrapper classes inherit from XMLElement, and they contain only one data member, which is the pointer to the corresponding DOM element.

This section shows how to work with wrapper objects in the Oracle Security Developer Tools APIs.

8.7.1 Construct the Wrapper Object

To construct a wrapper object from the DOM element, simply invoke the constructor.

For example:

Element sigElem =  
   (Element)doc.getElementsByTagNameNS(XMLURI.ns_dsig, "Signature").item(0);
XSSignature sig = new XSSignature(sigElem);

To construct a Wrapper object when the DOM element does not exist, you can either:

  • create a DOM element, and use the above method, or

  • use a newInstance method

XSSignature sig = XSSignature.newInstance(doc, null);

This internally achieves the same ends, that is, it creates a <dsig:Signature> DOM element, without appending it anywhere, then creates a wrapper object on top of the element. You will need to append this element somewhere in your document.

For some wrapper classes, there is no newInstance method and you need to call a constructor that takes the document object.

XSSignedInfo sigInfo =  new XSSignedInfo(doc, null);

Another way to create the wrapper object from the element is to call the XMLUtils.getInstance method:

XSSignature sig = (XSSignature)XMLUtils.getInstance(sigElem);

The Oracle Security Developer Tools APIs internally maintain a table associating element names to wrapper class names. The XMLUtils.getInstance uses this table to invoke the appropriate constructor and return an instance of that wrapper class.

8.7.2 Obtain the DOM Element from the Wrapper Object

The underlying DOM element is readily available. All wrapper classes extend from XMLElement which provides a method, XMLElement.getElement(), to get the underlying DOM element.

8.7.3 Parse Complex Elements

Whenever there are complex elements containing a hierarchy of subelements, there will also be an equivalent hierarchy of wrapper objects. For example, suppose you have an incoming document containing a signature:

<dsig:Signature>
  <dsig:SignedInfo>
    <dsig:CanonicalizationMethod ... />
     ...
  <dsig:SignedInfo>
  <dsig:SignatureValue>..</dsig:SignatureValue>
  ...  
</dsig:Signature>

Most of these elements have a corresponding wrapper class, such as dsig:Signature -> XSSignature, dsig:SignedInfo -> XSSignedInfo, dsig:SignatureValue -> XSSignatureValue and so on.

But when you construct the XSSignedInfo object from the dsig:Signature DOM element, it does not construct any of the child objects, in fact it does not even look at any of the child elements. The new XSSignature(sigElem) is a quick call which simply creates an object with the data member pointing to the sigElem. The child objects are created every time. So when you call XSSignature.getSignedInfo() it searches the child elements of dsig:Signature to find the dsig:SignedInfo element, constructs a wrapper object on that element, and returns it.

This wrapper object is not stored anywhere. So if you invoke XSSignature.getSignedInfo() again, it does the same thing, returning a different instance of the SignedInfo object; however both these objects point to the same DOM element, so they behave exactly the same way even though they are different instances.

Note:

Remember that the DOM is the source of truth, while the wrapper objects are throwaway objects. The get methods always create new wrapper objects, and if you modify the underlying DOM, the wrapper objects always see the most recent changes.

8.7.4 Construct Complex Elements

Consider the same example as before, but now instead of the signature present in an incoming document, you want to create a document containing a signature and send this document to someone.

<dsig:Signature>
  <dsig:SignedInfo>
     ...
  <dsig:SignedInfo>
  ...  
</dsig:Signature>

To construct this complex element, you need to create individual wrapper objects and assemble them using set methods.

For example:

XSSignature sig = XSSignature.newInstance(doc, null);
XSSignedInfo sigInfo = new XSSignedInfo(doc, null);
sig.setSignedInfo(sigInfo);

Remember that the DOM is always the source of truth; the set methods do not store or copy the passed-in wrapper object, they just modify the underlying DOM.

So in this case the setSignedInfo gets the dsig:SignedInfo element, and makes that a child of the dsig:Signature element. So after invoking setSignedInfo(sigInfo), if you do sigInfo = null, it will not affect anything.

Finally you need to insert the top-level object somewhere into your DOM:

elem.appendChild(sig.getElement());

8.8 How to Sign Data with the Oracle XML Security API

This section describes techniques for signing data with the Oracle XML Security APIs.

8.8.1 Basic Procedure to Create a Detached Signature

To create a detached signature like this:

<myDoc>
  <importantInfo>
    ...
  </importantInfo>
  <dsig:Signature>
    ...
      <dsig:Reference URI="#foo1">
    ...
  </dsig:Signature>
</myDoc>

You need to do this:

// assume you have your data set up in doc
Document doc = ...
Element impElem = ...
 
// Now put an ID on the importantInfo element
impElem.setAttributeNS(XMLURI.ns_xml, "xml:id", "foo1");
 
// Then get the signing key and certificate from 
// somewhere – e.g. you can load them from a keystore
PrivateKey signKey = ...
X509Certificate signCert = ...
 
// Create the Signature object
XSSignature sig = XSSignature.newInstance(doc, null);
 
// Create the SignedInfo object
// Normally you should use exclusive canonicalization
//    alg_exclusiveC14N
// Depending on the type of your private key DSA or RSA
//    use dsaWithSHA1 or rsaWithSHA1
XSSignedInfo sigInfo = sig.createSignedInfo(
  XMLURI.alg_exclusiveC14N, XMLURI.alg_rsaWithSHA1, null)
sig.setSignedInfo(sigInfo);
 
 
// Create a Reference object to the importantInfo element
// You need to specify the id which you set up earlier, 
//  and also a digestMethod
XSReference ref = sig.createReference(null, "#foo1", null, 
   XMLURI.alg_sha1);
sigInfo.addReference(ref);
// Create an exclusive c14n Transform object
// If you do not add this transform object, it will use 
// inclusive by default
XSAlgorithmIdentifier transform = 
  new XSAlgorithmIdentifier(doc, "Transform", 
  XMLURI.alg_exclusiveC14n);
ref.addTransform(transform);
 
 
// Create a KeyInfo object
XSKeyInfo keyInfo = sig.createKeyInfo();
sig.setKeyInfo(keyInfo);
 
// Create an X509Data element for your signingCert, inside
//  this keyingo
X509Data x509 = keyInfo.createX509Data(signingCert);
keyInfo.addKeyInfoData(x509);
 
// Everything is setup, now do the actual signing
// This will actually do all the canonicalization, 
// digesting, signing etc
sig.sign(signKey, null);
 
// Finally insert the signature somewhere in your document
doc.getDocumentElement().appendChild(sig.getElement());

Note:

After creating a child Wrapper object, you must call a set or add method to put it in its parent, and also remember to insert the top level Signature object into your document.

8.8.2 Variations on the Basic Signing Procedure

Variations on the basic signing procedure include multiple references, enveloped signatures, XPath expressions, certificate hints, and HMAC key signing.

8.8.2.1 Multiple References

To include multiple references in a signature, simply add more XSReference objects to the XSSignedInfo object. Each XSReference object needs its own list of transforms.

8.8.2.2 Enveloped Signature

To use an enveloped signature, add the enveloped signature transform to the reference. This means inserting the following code just before the code that adds the exclusive transform:

XSAlgorithmIdentifier transform1 = 
  new XSAlgorithmIdentifier(doc, "Transform", 
  XMLURI.alg_envelopedSignature);
ref.addTransform(transform1);

8.8.2.3 XPath Expression

To use an XPath expression instead of an ID-based reference, pass in an empty string instead of "#foo1" for the URI parameter of createReference, then add an XPath transform to the Reference as the first transform.

String xpathExpr = "ancestor-or-self:importantInfo";
Element xpathElem = doc.createElementNS(XMLURI.ns_dsig, 
 "dsig:XPath");
xpathElem.appendChild(doc.createTextNode(xpathExpr);
XSAlgorithmIdentifier transform2 = 
  new XSAlgorithmIdentifier(doc, "Transform", 
  XMLURI.alg_xpath);
transform2.addParameter(xpathElem);
ref.addTransform(transform2);

8.8.2.4 Certificate Hint

If you do not want to include the entire certificate in the key info, but only a hint to the certificate, use the no-argument form of XSKeyInfo.createX509Data() and call one of the methods X509Data.addIssuerSerial, addSubjectName, or addSubjectKeyID.

8.8.2.5 Sign with HMAC Key

TO sign with an HMAC key, instead of signing with an RSA or DSA private key, use the XSSignature.sign(byte[] secret, String sigValueId) method, and pass your HMAC key as the first argument.

Also use a different kind of KeyInfo, such as a KeyName, by calling XSKeyInfo.createKeyName.

8.9 How to Verify Signatures with the Oracle XML Security API

This section explains how to verify signatures using the Oracle XML Security APIs.

8.9.1 Basic Procedure to Check What is Signed

To verify a signature, first locate the <dsig:Signature> element in your document, then use it to construct the XSSignature wrapper object.

Element sigElem = …
XSSignature sig = new XSSignature(sigElem);

Next, fetch the KeyInfo of the signature and examine the key to determine if you trust the signer. There are different ways to deal with the KeyInfo:

  • For very simple cases, you may already know the verification key in advance, and you do not need to look at the KeyInfo at all.

  • In most cases, however, you should look at the KeyInfo. One way is to set up callbacks, so when you call XSSignature.verify() you call it with no verification key. Internally, the Oracle Security Developer Tools look at the KeyInfo to see if it invokes a callback to fetch the key.

  • The other option is to proactively look into the KeyInfo and determine the key yourself.

8.9.2 Set Up Callbacks

If the KeyInfo Contains the Signing Certificate

If you expect the KeyInfo to contain the signing certificate, and you do not already have this certificate, but you have set up the trust points, you just need to set a certificate validator callback.

// Create your certificate validator
CertificateValidator myValidator 
  = new CertificateValidator() {
  public void validateCert(CertPath cp) {
     // Code to validate the certificate
  }
};
KeyRetriever.setCertificateValidator(myValidator);

The Oracle Security Developer Tools API retrieves the certificate from the KeyInfo and invokes your callback; if the callback returns true, it will verify with that certificate.

If the KeyInfo Contains a Hint

If you expect the KeyInfo to contain only a hint to the signing certificate, that is, the subjectDN or Issuer Serial or subject key identifier, write a KeyRetriever to fetch a certificate from a certificate store given this hint.

If your certificate store is a keystore, a PKCS12 wallet, or a PKCS8 file, you can use one of the built-in retrievers for these types. These retrievers iterate through all the certificates in the keystore or Oracle wallet and find the one which matches the given subjectDN/issuerSerial or SubjectKey.

Note:

You can also use this mechanism also if your KeyInfo contains the entire certificate; the key retriever will simply match the entire certificate.
// Load your keystore
KeyStore ks = 
// Set up a callback against this KeyStore
KeyRetriever.addKeyRetriever(
  new KeyStoreKeyRetriever(ks, passwd));

8.9.3 Write a Custom Key Retriever

If these built in retrievers are not suitable, you can write a custom KeyRetriever by deriving from the KeyRetriever class; for example you could do this when you expect the KeyInfo to contain a subjectDN, and you will look up an LDAP directory to find the certificate for that DN.

KeyRetriever myRetriever = new KeyRetriever() {
   X509Certificate retrieveCertificate (KeyInfoData keyInfo) {
       // write code to fetch the certificate from 
       // the certificate store based on keyInfo
   }
 
   PublicKey retrieveCertificate (KeyInfoData keyInfo) {
       // write code to fetch the PublicKey from 
       // the certificate store based on keyInfo
   }
};
KeyRetriever.addKeyRetriever(myRetriever);

If the signature used the symmetric key, and the KeyInfo has the keyname of that key, write a custom key retriever which can fetch the symmetric key based on this key name.

8.9.4 Check What is Signed

The next step is to check if this signature really signs what you were expecting it to sign. The Oracle Security Developer Tools provide an API to return this information:

// XSSignature has be created as mentioned before
XSSignature sig = ...
 
// at first locate the element that are expecting 
// to be signed
Element impElem = ...
 
// Now check if the signature really signs this
List signedObjects = XMLUtils.resolveReferences(sig);
if (signedObjects.size() != 1 ||
   signedObjects.get(0) != impElem {
   // something is wrong – impElem is not signed by
   // this signature
}

8.9.5 Verify the Signature

The last step is to actually verify the signature.

8.9.5.1 If Callbacks are Set Up

If you set up callbacks, then make this call:

boolean result = sig.verify();

You need to check for both a false result and an exception:

  • sig.verify() returns false if the signature format is correct, but one of the reference digests does not match, or if the signature does not verify.

  • sig.verify() throws an exception if there is something wrong in the construction of the signature; for example, if the algorithm names are wrong or signature bytes are not of the right size.

8.9.5.2 If Callbacks are Not Set Up

If you did not set up callbacks, and you determined the key by yourself, you must call:

  • sig.verify(byte[]) for HMAC keys or

  • sig.verify(PublicKey) for DSA/RSA keys.

8.9.5.3 Debugging Verification

If you cannot determine why a particular signature does not verify, and you need to debug it, set the JVM property –Dxml.debug.verify=1. This flag instructs the Oracle Security Developer Tools to print diagnostic output to the stderr for failed signatures.

8.10 How to Encrypt Data with the Oracle XML Security API

This section describes various options for data encryption with Oracle XML Security.

8.10.1 Encrypt with a Shared Symmetric Key

To encrypt and replace the following <importantInfo> element:

<myDoc>
  <importantInfo>
    ...
  </importantInfo>
</myDoc>

you will need to take the following steps:

// Assuming there is a shared symmetric key
SecretKey dataEncKey = ...
 
// Create a new XEEncryptedData instance 
// use either obj_Element or obj_Content depending
// on whether you want to encrypt the whole element
// or content only
XEEncryptedData ed = XEEncryptedData
    .newInstance(doc, null, XMLURI.obj_Element);
 
// Specify the data encryption method
XEEncryptionMethod em =   
   ed.createEncryptionMethod(XMLURI.alg_aes128_CBC);
ed.setEncryptionMethod(em);
 
// Create a Keyinfo with a hint to the symmetric key
XEKeyInfo ki= ed.createKeyInfo();
ki.addKeyInfoData(ki.createKeyName("MyKey"));
ed.setKeyInfo(ki);
 
// Locate the importantInfo element
Element impElem = ...
 
// Encrypt the importantInfo element and replace
// it with the EncryptedData element
XEEncrytedData.encryptAndReplace(impElem, dataEncKey, 
   null, ed);

A Utility Method for Encryption

There is a utility method which performs all these steps:

XEncUtils.encryptElement(
  impElem,  // element to be encrypted
  false,    // true = contentOnly, false = entire element
  XMLURI.alg_aes128_CBC, // data encryption alg
  "MyKey" // hint to data key
);

8.10.2 Encrypt with a Random Symmetric Key

In Section 8.10.1, "Encrypt with a Shared Symmetric Key", the example made a simplifying assumption that there was a shared symmetric key. In practice, you usually generate a random symmetric key and encrypt with that key, and then encrypt this random symmetric key with the receiver's public key. Here is how you would do that:

// Load up the encryption certificate of the reciever
X509Certificate encCert = ...
 
// Get the reciever's public key from the cert
PublicKey keyEncKey = encCert.getPublicKey();
 
// Then generate a random symmetric key
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey dataEncKey = keyGen.generateKey();
 
// Now create an EncryptedKey object
XEEncryptedKey = new XEEncryptedKey(doc);
 
// set up the key encryption algorithm
XEEncryptionMethod em =   
  ek.createEncryptionMethod(XMLURI.alg_rsaOAEP_MGF1);
em.setDigestMethod(XMLURI.alg_sha1);
ek.setEncryptionMethod(em);
 
// encrypt the random symmetric key with public key
byte[] cipherValue = ek.encrypt(dataEncKey, keyEncKey);
 
// store this cipherValue into ek
XECipherData cd = ek.createCipherData();
cd.setCipherValue(cipherValue);
ek.setCipherData(cd);
 
 
// decide on how you would let the receiver know the
// the key encryption key. We are putting in the 
// entire reciever's certificate
XEKeyInfo kki = ek.createKeyInfo();
kki.addKeyInfoData(kki.createX509Data(encCert);
 
// Now the encrypted key has been set up, let us
// do the data encryption as before
XEncUtils.encryptElement(
  impElem,  // element to be encrypted
  false,    // true = contentOnly, false = entire element
  XMLURI.alg_aes128_CBC, // data encryption alg
  null // No hint to data key
);
 
// Finally we need to put the EncryptedKey inside the
// KeyInfo of the EncryptedData
ed.addKeyInfoData(ek);

A Utility Method for Encryption

There is a utility method which performs all these steps:

XEncUtils.encryptElement (
  impElem,  // element to be encrypted
  false,    // true = contentOnly, false = entire element
  XMLURI.alg_aes128_CBC, // data encryption alg
  dataEncKey, // the random symmetric key that we generated
  XMLURI.alg_rsaOAEP_MGF1, // key encryption alg
  KeyEncKey, // public key that we got from cert
  "RecieverCert" // A hint to the certificate
);

Notice that this utility method puts KeyName in the EncryptedKey's KeyInfo; if you want to pass X509Data instead, pass null for keyEncKeyName and then add the X509Data yourself:

// use utility method to create EncrytedData
XEEncryptedData ed = XEncUtils...
 
// no extract EncryptedKey from it
XEEncryptedKey ek = (XEEncryptedKey)ed.getKeyInfo()
 .getEncryptedKeys().elementAt(0);
 
// Set the keyInfo of the ek
XEKeyInfo kki = ek.createKeyInfo();
kki.addKeyInfoData(kki.createX509Data(encCert);

8.11 How to Decrypt Data with the Oracle XML Security API

Decryption techniques depend on whether you have a shared symmetric key or use a random symmetric key.

8.11.1 Decrypt with a Shared Symmetric Key

If you have a shared symmetric key, do the following:

// search for the EncryptedData element
Element edElem = ...
 
// decrypt the data
SecretKey dataDecKey = ...
XEEncrytedData.decryptAndReplace(dataDecKey, edElem, true);

8.11.2 Decrypt with a Random Symmetric Key

If you expect to use a random symmetric key:

// search for the EncryptedData element
Element edElem = ...
 
// decrypt the data
PrivateKey keyDecKey = ...
XEEncUtils.decryptElement(edElem, keyDecKey);

8.12 Supporting Classes and Interfaces

This section describes additional classes and interfaces in the Oracle XML Security API.

8.12.1 The oracle.security.xmlsec.util.XMLURI Interface

This interface defines URI string constants for algorithms, namespaces, and objects. It uses the following naming convention:

  • Algorithm URIs begin with "alg_".

  • Namespace URIs begin with "ns_".

  • Object type URIs begin with "obj_".

8.12.2 The oracle.security.xmlsec.util.XMLUtils class

This class contains static utility methods for XML and XML-DSIG. Methods frequently used in applications include the createDocBuilder(), createDocument(), toBytesXML(), and toStringXML() methods.

8.13 Common XML Security Questions

This section answers frequently asked questions about XML security and about using Oracle XML Security. It addresses these areas:

What is the DER format? The PEM format? How are these formats used?

DER is an abbreviation for ASN.1 Distinguished Encoding Rules. DER is a binary format that is used to encode certificates and private keys. Oracle XML Security SDK uses DER as its native format, as do most commercial products that use certificates and private keys.

Many other formats used to encode certificates and private keys, including PEM, PKCS #7, and PKCS #12, are transformations of DER encoding. For example, PEM (Privacy Enhanced Mail) is a text format that is the Base 64 encoding of the DER binary format. The PEM format also specifies the use of text BEGIN and END lines that indicate the type of content that is being encoded.

I received a certificate in my email in a text format. It has several lines of text characters that don't seem to mean anything. How do I convert it into the format that Oracle XML Security uses?

If you received the certificate in your email, it is in PEM format. You need to convert the certificate from PEM (Privacy-Enhanced Mail) format to ASN.1 DER (Distinguished Encoding Rules) format.

How do I use a certificate that is exported from a browser?

If you have exported the certificate from a browser, it is most likely in PKCS #12 format (*.p12 or *.pfx). You must parse the PKCS #12 object into its component parts.

8.14 Best Practices

For a discussion of best practices for implementors and users of the XML Signature specification, see:

http://www.w3.org/TR/xmldsig-bestpractices/

8.15 The Oracle XML Security Java API Reference

The Oracle XML Security API (Javadoc) is available at:

Oracle Fusion Middleware XML Security Java API Reference for Oracle Security Developer Tools

8.16 Example Programs

For example programs using the Oracle Security Developer Tools, see the Oracle Technology Network Web Site at http://www.oracle.com/technology/sample_code/products/id_mgmt/index.html.